diff --git a/gui/kmixprefdlg.cpp b/gui/kmixprefdlg.cpp index 0f90929b..5922dac8 100644 --- a/gui/kmixprefdlg.cpp +++ b/gui/kmixprefdlg.cpp @@ -1,471 +1,471 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de> * Copyright (C) 2001 Preston Brown * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gui/kmixprefdlg.h" #include #include #include #include #include #include #include #include #include "dialogbase.h" #include "dialogstatesaver.h" #include "gui/kmixerwidget.h" #include "core/GlobalConfig.h" KMixPrefDlg* KMixPrefDlg::instance = 0; KMixPrefDlg* KMixPrefDlg::getInstance() { return instance; } KMixPrefDlg* KMixPrefDlg::createInstance(QWidget *parent, GlobalConfig& config) { if (instance == 0) { instance = new KMixPrefDlg(parent, config); } return instance; } KMixPrefDlg::KMixPrefDlg(QWidget *parent, GlobalConfig& config) : KConfigDialog(parent, i18n("Configure"), &config), dialogConfig(config) { setFaceType(KPageDialog::List); //setCaption(i18n("Configure")); dvc = 0; dvcSpacerBelow = 0; // general buttons m_generalTab = new QFrame(this); m_controlsTab = new QFrame(this); m_startupTab = new QFrame(this); createStartupTab(); createGeneralTab(); createControlsTab(); updateWidgets(); // I thought KConfigDialog would call this, but I saw during a gdb session that it does not do so. generalPage = addPage(m_generalTab, i18n("General"), "configure"); startupPage = addPage(m_startupTab, i18n("Startup"), "preferences-system-login"); soundmenuPage = addPage(m_controlsTab, i18n("Volume Control"), "audio-volume-high"); new DialogStateSaver(this); } /** * Switches to a specific page and shows it. * @param page */ void KMixPrefDlg::switchToPage(KMixPrefPage page) { switch (page) { case PrefGeneral: setCurrentPage(generalPage); break; case PrefSoundMenu: setCurrentPage(soundmenuPage); break; case PrefStartup: setCurrentPage(startupPage); break; default: qCWarning(KMIX_LOG) << "Tried to activated unknown preferences page" << page; break; } show(); } // --- TABS -------------------------------------------------------------------------------------------------- void KMixPrefDlg::createStartupTab() { layoutStartupTab = new QVBoxLayout(m_startupTab); layoutStartupTab->setContentsMargins(0, 0, 0, 0); layoutStartupTab->setSpacing(DialogBase::verticalSpacing()); allowAutostart = new QCheckBox(i18n("Start KMix on desktop startup"), m_startupTab); addWidgetToLayout(allowAutostart, layoutStartupTab, 10, i18n("Start KMix automatically when the desktop starts."), "AutoStart"); allowAutostartWarning = new KMessageWidget( i18n("Autostart will not work, because the autostart file kmix_autostart.desktop is missing. Check that KMix is installed correctly."), m_startupTab); allowAutostartWarning->setIcon(QIcon::fromTheme("dialog-error")); allowAutostartWarning->setMessageType(KMessageWidget::Error); allowAutostartWarning->setCloseButtonVisible(false); allowAutostartWarning->setWordWrap(true); allowAutostartWarning->setVisible(false); addWidgetToLayout(allowAutostartWarning, layoutStartupTab, 2, "", ""); layoutStartupTab->addItem(new QSpacerItem(1, 2*DialogBase::verticalSpacing())); m_onLogin = new QCheckBox(i18n("Restore previous volume settings on desktop startup"), m_startupTab); addWidgetToLayout(m_onLogin, layoutStartupTab, 10, i18n("Restore all mixer volume levels and switches to their last used settings when the desktop starts."), "startkdeRestore"); dynamicControlsRestoreWarning = new KMessageWidget( i18n("The volume of PulseAudio or MPRIS2 dynamic controls will not be restored."), m_startupTab); dynamicControlsRestoreWarning->setIcon(QIcon::fromTheme("dialog-warning")); dynamicControlsRestoreWarning->setMessageType(KMessageWidget::Warning); dynamicControlsRestoreWarning->setCloseButtonVisible(false); dynamicControlsRestoreWarning->setWordWrap(true); dynamicControlsRestoreWarning->setVisible(false); addWidgetToLayout(dynamicControlsRestoreWarning, layoutStartupTab, 2, "", ""); layoutStartupTab->addStretch(); } void KMixPrefDlg::createOrientationGroup(const QString& labelSliderOrientation, QGridLayout* orientationLayout, int row, KMixPrefDlgPrefOrientationType prefType) { QButtonGroup* orientationGroup = new QButtonGroup(m_generalTab); orientationGroup->setExclusive(true); QLabel* qlb = new QLabel(labelSliderOrientation, m_generalTab); QRadioButton* qrbHor = new QRadioButton(i18n("&Horizontal"), m_generalTab); QRadioButton* qrbVert = new QRadioButton(i18n("&Vertical"), m_generalTab); if (prefType == TrayOrientation) { _rbTraypopupHorizontal = qrbHor; _rbTraypopupVertical = qrbVert; orientationGroup->setObjectName("Orientation.TrayPopup"); } else { _rbHorizontal = qrbHor; _rbVertical = qrbVert; orientationGroup->setObjectName("Orientation"); } // Add both buttons to button group //qrbHor->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); orientationGroup->addButton(qrbHor); orientationGroup->addButton(qrbVert); // Add both buttons and label to layout orientationLayout->addWidget(qlb, row, 0, Qt::AlignLeft); orientationLayout->addWidget(qrbHor, row, 1, Qt::AlignLeft); orientationLayout->addWidget(qrbVert, row, 2, Qt::AlignLeft); orientationLayout->addItem(new QSpacerItem(1,1,QSizePolicy::Expanding), row, 3); connect(qrbHor, SIGNAL(toggled(bool)), SLOT(updateButtons())); connect(qrbVert, SIGNAL(toggled(bool)), SLOT(updateButtons())); connect(button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(kmixConfigHasChangedEmitter())); connect(button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(kmixConfigHasChangedEmitter())); // connect(qrbHor, SIGNAL(toggled(bool)), SLOT(settingsChangedSlot())); // connect(qrbVert, SIGNAL(toggled(bool)), SLOT(settingsChangedSlot())); } void KMixPrefDlg::createGeneralTab() { QBoxLayout* layout = new QVBoxLayout(m_generalTab); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(DialogBase::verticalSpacing()); // --- Behavior --------------------------------------------------------- QGroupBox *grp = new QGroupBox(i18n("Behavior"), m_generalTab); grp->setFlat(true); layout->addWidget(grp); auto *behaviorLayout = new QVBoxLayout; behaviorLayout->setContentsMargins(0, 0, 0, 0); grp->setLayout(behaviorLayout); // [CONFIG] m_beepOnVolumeChange = new QCheckBox(i18n("Volume feedback"), grp); addWidgetToLayout(m_beepOnVolumeChange, behaviorLayout, 10, "", "VolumeFeedback"); m_volumeOverdrive = new QCheckBox(i18n("Volume overdrive"), grp); addWidgetToLayout(m_volumeOverdrive, behaviorLayout, 10, i18nc("@info:tooltip", "Raise the maximum volume to 150%"), "VolumeOverdrive"); volumeFeedbackWarning = new KMessageWidget( i18n("Volume feedback and volume overdrive are only available for PulseAudio."), grp); volumeFeedbackWarning->setIcon(QIcon::fromTheme("dialog-warning")); volumeFeedbackWarning->setMessageType(KMessageWidget::Warning); volumeFeedbackWarning->setCloseButtonVisible(false); volumeFeedbackWarning->setWordWrap(true); volumeFeedbackWarning->setVisible(false); addWidgetToLayout(volumeFeedbackWarning, behaviorLayout, 2, "", ""); volumeOverdriveWarning = new KMessageWidget( i18n("KMix must be restarted for the Volume Overdrive setting to take effect."), grp); volumeOverdriveWarning->setIcon(QIcon::fromTheme("dialog-information")); volumeOverdriveWarning->setMessageType(KMessageWidget::Information); volumeOverdriveWarning->setCloseButtonVisible(false); volumeOverdriveWarning->setWordWrap(true); volumeOverdriveWarning->setVisible(false); addWidgetToLayout(volumeOverdriveWarning, behaviorLayout, 2, "", ""); // --- Visual --------------------------------------------------------- layout->addItem(new QSpacerItem(1, DialogBase::verticalSpacing())); grp = new QGroupBox(i18n("Visual"), m_generalTab); grp->setFlat(true); layout->addWidget(grp); auto *visualLayout = new QVBoxLayout; visualLayout->setContentsMargins(0, 0, 0, 0); grp->setLayout(visualLayout); // [CONFIG] - m_showTicks = new QCheckBox(i18n("Show &tickmarks"), grp); + m_showTicks = new QCheckBox(i18n("Show slider &tickmarks"), grp); addWidgetToLayout(m_showTicks, visualLayout, 10, i18n("Enable/disable tickmark scales on the sliders"), "Tickmarks"); - m_showLabels = new QCheckBox(i18n("Show &labels"), grp); + m_showLabels = new QCheckBox(i18n("Show control &labels"), grp); addWidgetToLayout(m_showLabels, visualLayout, 10, i18n("Enables/disables description labels above the sliders"), "Labels"); // [CONFIG] m_showOSD = new QCheckBox(i18n("Show On Screen Display (&OSD)"), grp); addWidgetToLayout(m_showOSD, visualLayout, 10, "", "showOSD"); // [CONFIG] Slider orientation (main window) visualLayout->addItem(new QSpacerItem(1, DialogBase::verticalSpacing())); QGridLayout* orientationGrid = new QGridLayout(); orientationGrid->setHorizontalSpacing(DialogBase::horizontalSpacing()); visualLayout->addLayout(orientationGrid); // Slider orientation (main window, and tray popup separately). createOrientationGroup(i18n("Slider orientation (main window): "), orientationGrid, 0, KMixPrefDlg::MainOrientation); createOrientationGroup(i18n("Slider orientation (system tray popup):"), orientationGrid, 1, KMixPrefDlg::TrayOrientation); // Push everything above to the top layout->addStretch(); } void KMixPrefDlg::createControlsTab() { layoutControlsTab = new QVBoxLayout(m_controlsTab); layoutControlsTab->setContentsMargins(0, 0, 0, 0); layoutControlsTab->setSpacing(DialogBase::verticalSpacing()); m_dockingChk = new QCheckBox(i18n("Dock in system tray"), m_controlsTab); addWidgetToLayout(m_dockingChk, layoutControlsTab, 10, i18n("Dock the mixer into the system tray. Click on it to open the popup volume control."), "AllowDocking"); layoutControlsTab->addItem(new QSpacerItem(1, 2*DialogBase::verticalSpacing())); replaceBackendsInTab(); } // --- Helper -------------------------------------------------------------------------------------------------- /** * Register widget with correct name for KConfigDialog, then add it to the given layout * * @param widget * @param layout * @param spacingBefore * @param toopTipText * @param objectName */ void KMixPrefDlg::addWidgetToLayout(QWidget* widget, QBoxLayout* layout, int spacingBefore, const QString &tooltip, const QString &kconfigName) { if (!kconfigName.isEmpty()) { // Widget to be registered for KConfig widget->setObjectName("kcfg_" + kconfigName); } if ( !tooltip.isEmpty() ) { widget->setToolTip(tooltip); } QBoxLayout *l = new QHBoxLayout(); l->addSpacing(spacingBefore); l->addWidget(widget); layout->addItem(l); } // --- KConfigDialog CUSTOM WIDGET management ------------------------------------------------------------------------ /** * Update Widgets from config. *

* Hint: this get internally called by KConfigdialog on initialization and reset. */ void KMixPrefDlg::updateWidgets() { if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << ""; bool toplevelHorizontal = dialogConfig.data.getToplevelOrientation() == Qt::Horizontal; _rbHorizontal->setChecked(toplevelHorizontal); _rbVertical->setChecked(!toplevelHorizontal); bool trayHorizontal = dialogConfig.data.getTraypopupOrientation() == Qt::Horizontal; _rbTraypopupHorizontal->setChecked(trayHorizontal); _rbTraypopupVertical->setChecked(!trayHorizontal); } /** * Updates config from the widgets. And emits the signal kmixConfigHasChanged(). *

* Hint: this get internally called by KConfigDialog after pressing the OK or Apply button. */ void KMixPrefDlg::updateSettings() { Qt::Orientation toplevelOrientation = _rbHorizontal->isChecked() ? Qt::Horizontal : Qt::Vertical; if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "toplevelOrientation" << toplevelOrientation << ", _rbHorizontal->isChecked()" << _rbHorizontal->isChecked(); dialogConfig.data.setToplevelOrientation(toplevelOrientation); Qt::Orientation trayOrientation = _rbTraypopupHorizontal->isChecked() ? Qt::Horizontal : Qt::Vertical; if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "trayOrientation" << trayOrientation << ", _rbTraypopupHorizontal->isChecked()" << _rbTraypopupHorizontal->isChecked(); dialogConfig.data.setTraypopupOrientation(trayOrientation); // Announcing MasterChanged, as the sound menu (aka ViewDockAreaPopup) primarily shows master volume(s). // In any case, ViewDockAreaPopup treats MasterChanged and ControlList the same, so it is better to announce // the "smaller" change. bool modified = dvc->getAndResetModifyFlag(); if (modified) { GlobalConfig::instance().setMixersForSoundmenu(dvc->getChosenBackends()); ControlManager::instance().announce(QString(), ControlManager::MasterChanged, QString("Select Backends Dialog")); } } void KMixPrefDlg::kmixConfigHasChangedEmitter() { emit(kmixConfigHasChanged()); } /** * Returns whether the custom widgets (orientation checkboxes) has changed. *

* Hint: this get internally called by KConfigDialog from updateButtons(). * @return */ bool KMixPrefDlg::hasChanged() { bool orientationFromConfigIsHor = dialogConfig.data.getToplevelOrientation() == Qt::Horizontal; bool orientationFromWidgetIsHor = _rbHorizontal->isChecked(); if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "Orientation MAIN fromConfig=" << (orientationFromConfigIsHor ? "Hor" : "Vert") << ", fromWidget=" << (orientationFromWidgetIsHor ? "Hor" : "Vert"); bool changed = orientationFromConfigIsHor ^ orientationFromWidgetIsHor; if (!changed) { bool orientationFromConfigIsHor = dialogConfig.data.getTraypopupOrientation() == Qt::Horizontal; orientationFromWidgetIsHor = _rbTraypopupHorizontal->isChecked(); if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "Orientation TRAY fromConfig=" << (orientationFromConfigIsHor ? "Hor" : "Vert") << ", fromWidget=" << (orientationFromWidgetIsHor ? "Hor" : "Vert"); changed = orientationFromConfigIsHor ^ orientationFromWidgetIsHor; } if (!changed) { changed = dvc->getModifyFlag(); } if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "hasChanged=" << changed; return changed; } void KMixPrefDlg::showEvent(QShowEvent * event) { // -1- Replace widgets ------------------------------------------------------------ // Hotplug can change mixers or backends => recreate tab replaceBackendsInTab(); KConfigDialog::showEvent(event); // -2- Change visibility and enable status (of the new widgets) ---------------------- // As GUI can change, the warning will only been shown on demand dynamicControlsRestoreWarning->setVisible(Mixer::dynamicBackendsPresent()); QString autostartConfigFilename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "/autostart/kmix_autostart.desktop"); if (dialogConfig.data.debugConfig) qCDebug(KMIX_LOG) << "autostartConfigFilename = " << autostartConfigFilename; bool autostartFileExists = !autostartConfigFilename.isEmpty(); allowAutostartWarning->setVisible(!autostartFileExists); allowAutostart->setEnabled(autostartFileExists); // Only PulseAudio supports volume feedback and volume overdrive. // Disable those configuration options for other backends, and // show a warning message. const bool pulseAudioAvailable = Mixer::pulseaudioPresent(); if (!pulseAudioAvailable) { m_beepOnVolumeChange->setChecked(false); m_beepOnVolumeChange->setEnabled(false); m_volumeOverdrive->setChecked(false); m_volumeOverdrive->setEnabled(false); volumeFeedbackWarning->setVisible(true); volumeOverdriveWarning->setVisible(false); } else { volumeFeedbackWarning->setVisible(false); volumeOverdriveWarning->setVisible(true); } } void KMixPrefDlg::replaceBackendsInTab() { if (dvc != 0) { layoutControlsTab->removeWidget(dvc); delete dvc; layoutControlsTab->removeItem(dvcSpacerBelow); delete dvcSpacerBelow; } QSet backendsFromConfig = GlobalConfig::instance().getMixersForSoundmenu(); dvc = new DialogChooseBackends(0, backendsFromConfig); connect(dvc, SIGNAL(backendsModified()), SLOT(updateButtons())); layoutControlsTab->addWidget(dvc); dvc->show(); // Push everything above to the top // layoutControlsTab->addStretch(); dvcSpacerBelow = new QSpacerItem(1,1); layoutControlsTab->addItem(dvcSpacerBelow); } diff --git a/gui/kmixtoolbox.cpp b/gui/kmixtoolbox.cpp index 8d00168b..4acefaea 100644 --- a/gui/kmixtoolbox.cpp +++ b/gui/kmixtoolbox.cpp @@ -1,90 +1,79 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 2004 Christian Esken * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gui/kmixtoolbox.h" #include -#include -#include -#include #include -#include "gui/guiprofile.h" -#include "mdwslider.h" #include "gui/mixdevicewidget.h" -#include "core/mixdevice.h" -#include "core/mixer.h" -#include "viewbase.h" - -// TODO KMixToolbox is rather superfluous today, as there is no "KMix Applet" any more, and it was probably always bad style. -// I only have to think what to do with KMixToolBox::notification() /*********************************************************************************** - KMixToolbox contains several GUI relevant methods that are shared between the - KMix Main Program, and the KMix Applet. - kmixctrl - as not non-GUI application - does NOT link to KMixToolBox. + KMixToolbox contains several GUI utility functions that are only used by the + KMix main program. kded_kmix and kmixctrl - as non-GUI applications - do not + use or link to KMixToolBox. - This means: Shared GUI stuff goes into the KMixToolBox class , non-GUI stuff goes + This means that shared GUI stuff goes into KMixToolBox here, non-GUI stuff goes into the MixerToolBox class. ***********************************************************************************/ -void KMixToolBox::setIcons(QList &mdws, bool on ) { - for (int i=0; i < mdws.count(); ++i ){ - QWidget *mdw = mdws[i]; - if ( mdw->inherits("MixDeviceWidget") ) { // -<- play safe here - static_cast(mdw)->setIcons( on ); - } - } + +void KMixToolBox::setIcons(QList &mdws, bool on) +{ + for (QWidget *w : mdws) + { + MixDeviceWidget *mdw = qobject_cast(w); + if (mdw!=nullptr) mdw->setIcons(on); + } } -void KMixToolBox::setLabels(QList &mdws, bool on ) { - for (int i=0; i < mdws.count(); ++i ){ - QWidget *mdw = mdws[i]; - if ( mdw->inherits("MixDeviceWidget") ) { // -<- play safe here - static_cast(mdw)->setLabeled( on ); - } - } + +void KMixToolBox::setLabels(QList &mdws, bool on) +{ + for (QWidget *w : mdws) + { + MixDeviceWidget *mdw = qobject_cast(w); + if (mdw!=nullptr) mdw->setLabeled(on); + } } -void KMixToolBox::setTicks(QList &mdws, bool on ) { - for (int i=0; i < mdws.count(); ++i ){ - QWidget *mdw = mdws[i]; - if ( mdw->inherits("MixDeviceWidget") ) { // -<- play safe here - static_cast(mdw)->setTicks( on ); - } - } + +void KMixToolBox::setTicks(QList &mdws, bool on) +{ + for (QWidget *w : mdws) + { + MixDeviceWidget *mdw = qobject_cast(w); + if (mdw!=nullptr) mdw->setTicks(on); + } } -void KMixToolBox::notification(const char *notificationName, const QString &text, - const QStringList &actions, QObject *receiver, - const char *actionSlot) + +void KMixToolBox::notification(const char *notificationName, const QString &text) { KNotification *notification = new KNotification(notificationName); - //notification->setComponentData(componentData()); notification->setText(text); - //notification->setPixmap(...); + notification->setIconName(QLatin1String("kmix")); notification->addContext(QLatin1String("Application"), QCoreApplication::applicationName()); - if (!actions.isEmpty() && receiver && actionSlot) { - notification->setActions(actions); - QObject::connect(notification, SIGNAL(activated(uint)), receiver, actionSlot); - } notification->sendEvent(); + // Otherwise there will be a memory leak (although the notification is not + // shown very often). Assuming that it is safe to delete here. + notification->deleteLater(); } diff --git a/gui/kmixtoolbox.h b/gui/kmixtoolbox.h index 519f6f5d..5ce4b5b6 100644 --- a/gui/kmixtoolbox.h +++ b/gui/kmixtoolbox.h @@ -1,44 +1,43 @@ //-*-C++-*- /* * KMix -- KDE's full featured mini mixer * * Copyright Christian Esken * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KMIXTOOLBOX_H #define KMIXTOOLBOX_H #include "qlist.h" #include "qwidget.h" - /** * This toolbox contains various static methods that are shared throughout KMix. * The reason, why it is not put in a common base class is, that the classes are * very different and cannot be changed (e.g. KPanelApplet) without major headache. */ -class KMixToolBox { - public: - static void setIcons (QList &mdws, bool on ); - static void setLabels (QList &mdws, bool on ); - static void setTicks (QList &mdws, bool on ); +namespace KMixToolBox +{ + void setIcons(QList &mdws, bool on); + void setLabels(QList &mdws, bool on); + void setTicks(QList &mdws, bool on); - static void notification(const char *notificationName, const QString &text, const QStringList &actions = QStringList(), QObject *receiver = nullptr, const char *actionSlot = nullptr); -}; + void notification(const char *notificationName, const QString &text); +} // namespace KMixToolBox #endif