File indexing completed on 2023-05-30 11:30:47

0001 /**
0002  * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
0003  * Copyright (C) 2008, 2009, 2017 Michael Pyne <mpyne@kde.org>
0004  *
0005  * This program is free software; you can redistribute it and/or modify it under
0006  * the terms of the GNU General Public License as published by the Free Software
0007  * Foundation; either version 2 of the License, or (at your option) any later
0008  * version.
0009  *
0010  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0011  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0012  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU General Public License along with
0015  * this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "juk.h"
0019 
0020 #include <KSharedConfig>
0021 #include <kaboutdata.h>
0022 #include <kactioncollection.h>
0023 #include <kactionmenu.h>
0024 #include <kconfiggroup.h>
0025 #include <kglobalaccel.h>
0026 #include <kmessagebox.h>
0027 #include <knotification.h>
0028 #include <kstandardaction.h>
0029 #include <ktoggleaction.h>
0030 #include <ktoolbarpopupaction.h>
0031 
0032 #include <QAction>
0033 #include <QCoreApplication>
0034 #include <QDBusInterface>
0035 #include <QDBusMessage>
0036 #include <QDBusReply>
0037 #include <QDir>
0038 #include <QDirIterator>
0039 #include <QKeyEvent>
0040 #include <QMenuBar>
0041 #include <QScreen>
0042 #include <QStatusBar>
0043 #include <QTime>
0044 #include <QTimer>
0045 
0046 #include "actioncollection.h"
0047 #include "cache.h"
0048 #include "collectionlist.h"
0049 #include "covermanager.h"
0050 #include "filerenamerconfigdlg.h"
0051 #include "iconsupport.h"
0052 #include "keydialog.h"
0053 #include "playermanager.h"
0054 #include "playlistsplitter.h"
0055 #include "scrobbleconfigdlg.h"
0056 #include "scrobbler.h"
0057 #include "slideraction.h"
0058 #include "statuslabel.h"
0059 #include "systemtray.h"
0060 #include "tagguesserconfigdlg.h"
0061 #include "tagtransactionmanager.h"
0062 
0063 #include "juk_debug.h"
0064 
0065 using namespace ActionCollection; // ""_act and others
0066 using namespace IconSupport;      // ""_icon
0067 
0068 JuK* JuK::m_instance;
0069 
0070 template<class T>
0071 void deleteAndClear(T *&ptr)
0072 {
0073     delete ptr;
0074     ptr = 0;
0075 }
0076 
0077 ////////////////////////////////////////////////////////////////////////////////
0078 // public members
0079 ////////////////////////////////////////////////////////////////////////////////
0080 
0081 JuK::JuK(const QStringList &filesToOpen, QWidget *parent)
0082   : KXmlGuiWindow(parent, Qt::WindowFlags(Qt::WA_DeleteOnClose))
0083   , m_player(new PlayerManager)
0084   , m_filesToOpen(filesToOpen)
0085 {
0086     // Expect segfaults if you change this order.
0087 
0088     // Allow to be passed across threads
0089     qRegisterMetaType<FileHandle>();
0090     qRegisterMetaType<FileHandleList>();
0091 
0092     m_instance = this;
0093 
0094     Cache::ensureAppDataStorageExists();
0095 
0096     setupActions();
0097     setupLayout(); // Creates PlaylistSplitter and therefore CollectionList
0098 
0099     bool firstRun = !KSharedConfig::openConfig()->hasGroup("MainWindow");
0100 
0101     if(firstRun) {
0102         KConfigGroup mainWindowConfig(KSharedConfig::openConfig(), "MainWindow");
0103         KConfigGroup playToolBarConfig(&mainWindowConfig, "Toolbar playToolBar");
0104         playToolBarConfig.writeEntry("ToolButtonStyle", "IconOnly");
0105     }
0106 
0107     QSize defaultSize(800, 480);
0108 
0109     if(QApplication::isRightToLeft())
0110         setupGUI(defaultSize, ToolBar | Save | Create, "jukui-rtl.rc");
0111     else
0112         setupGUI(defaultSize, ToolBar | Save | Create);
0113 
0114     // Center the GUI if this is our first run ever.
0115 
0116     if(firstRun) {
0117         QRect r = rect();
0118         const QRect screenCenter = QApplication::primaryScreen()->availableGeometry();
0119         r.moveCenter(screenCenter.center());
0120         move(r.topLeft());
0121     }
0122 
0123     connect(m_splitter, SIGNAL(guiReady()), SLOT(slotSetupSystemTray()));
0124     readConfig();
0125     setupGlobalAccels();
0126     activateScrobblerIfEnabled();
0127 
0128     QDBusInterface *pmInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
0129                                        QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"),
0130                                        QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
0131                                        QDBusConnection::sessionBus());
0132 
0133     connect(m_player, &PlayerManager::signalPlay, pmInterface, [=] () {
0134         QDBusReply<uint> reply;
0135         if(pmInterface->isValid() && (m_pmToken == 0)) {
0136             reply = pmInterface->call(QStringLiteral("Inhibit"),
0137                                KAboutData::applicationData().componentName(),
0138                                QStringLiteral("playing audio"));
0139             if(reply.isValid()) {
0140                 m_pmToken = reply.value();
0141             }
0142         }
0143     });
0144 
0145     auto uninhibitPowerManagement = [=] () {
0146         QDBusMessage reply;
0147         if(pmInterface->isValid() && (m_pmToken != 0)) {
0148             reply = pmInterface->call(QStringLiteral("UnInhibit"), m_pmToken);
0149             if(reply.errorName().isEmpty()) {
0150                 m_pmToken = 0;
0151             }
0152         }
0153     };
0154 
0155     connect(m_player, &PlayerManager::signalPause, uninhibitPowerManagement);
0156     connect(m_player, &PlayerManager::signalStop, uninhibitPowerManagement);
0157 
0158     // KMainWindow will close the window on this signal, but we need the visible state
0159     // of it in saveConfig()
0160     disconnect(qApp, &QGuiApplication::commitDataRequest, nullptr, nullptr);
0161 
0162     connect(qApp, &QGuiApplication::commitDataRequest, this, [this]() { saveConfig(); },
0163             Qt::DirectConnection);
0164 
0165     // slotCheckCache loads the cached entries first to populate the collection list
0166 
0167     QTimer::singleShot(0, this, SLOT(slotClearOldCovers()));
0168     QTimer::singleShot(0, CollectionList::instance(), SLOT(startLoadingCachedItems()));
0169     QTimer::singleShot(0, this, SLOT(slotProcessArgs()));
0170 }
0171 
0172 JuK::~JuK()
0173 {
0174     if(!m_shuttingDown)
0175         slotQuit();
0176 
0177     // Some items need to be deleted before others, though I haven't looked
0178     // at this in some time so refinement is probably possible.
0179     delete m_systemTray;
0180     delete m_splitter;
0181     delete m_player;
0182     delete m_statusLabel;
0183 
0184     // Sometimes KMainWindow doesn't actually call QCoreApplication::quit
0185     // after queryClose, even if not in a session shutdown, so make sure to
0186     // do so ourselves when closing the main window.
0187     QTimer::singleShot(0, qApp, &QCoreApplication::quit);
0188 }
0189 
0190 JuK* JuK::JuKInstance()
0191 {
0192     return m_instance;
0193 }
0194 
0195 PlayerManager *JuK::playerManager() const
0196 {
0197     return m_player;
0198 }
0199 
0200 void JuK::coverDownloaded(const QPixmap &cover)
0201 {
0202     QString event(cover.isNull() ? "coverFailed" : "coverDownloaded");
0203     KNotification *notification = new KNotification(event);
0204     notification->setWidget(this);
0205     notification->setPixmap(cover);
0206     notification->setFlags(KNotification::CloseOnTimeout);
0207 
0208     if(cover.isNull())
0209         notification->setText(i18n("Your album art failed to download."));
0210     else
0211         notification->setText(i18n("Your album art has finished downloading."));
0212 
0213     notification->sendEvent();
0214 }
0215 
0216 ////////////////////////////////////////////////////////////////////////////////
0217 // private members
0218 ////////////////////////////////////////////////////////////////////////////////
0219 
0220 void JuK::setupLayout()
0221 {
0222     m_splitter = new PlaylistSplitter(m_player, this);
0223     setCentralWidget(m_splitter);
0224 
0225     m_statusLabel = new StatusLabel(*m_splitter->playlist(), statusBar());
0226     statusBar()->addWidget(m_statusLabel, 1);
0227     connect(m_player, &PlayerManager::tick, m_statusLabel,
0228             &StatusLabel::setItemCurrentTime);
0229     connect(m_player, &PlayerManager::totalTimeChanged,
0230             m_statusLabel, &StatusLabel::setItemTotalTime);
0231     connect(m_splitter, &PlaylistSplitter::currentPlaylistChanged,
0232             m_statusLabel, &StatusLabel::slotCurrentPlaylistHasChanged);
0233 
0234     m_splitter->setFocus();
0235 }
0236 
0237 void JuK::setupActions()
0238 {
0239     KActionCollection *collection = ActionCollection::actions();
0240 
0241     // Setup KDE standard actions that JuK uses.
0242 
0243     KStandardAction::quit(this, SLOT(slotQuit()), collection);
0244     KStandardAction::undo(this, SLOT(slotUndo()), collection);
0245     KStandardAction::cut(collection);
0246     KStandardAction::copy(collection);
0247     KStandardAction::paste(collection);
0248     QAction *clear = KStandardAction::clear(collection);
0249     KStandardAction::selectAll(collection);
0250     KStandardAction::keyBindings(this, SLOT(slotEditKeys()), collection);
0251     KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), collection);
0252 
0253     // Setup the menu which handles the random play options.
0254     KActionMenu *actionMenu = collection->add<KActionMenu>("actionMenu");
0255     actionMenu->setText(i18n("&Random Play"));
0256     actionMenu->setIcon("media-playlist-shuffle"_icon);
0257     actionMenu->setPopupMode(QToolButton::InstantPopup);
0258 
0259     QActionGroup* randomPlayGroup = new QActionGroup(this);
0260 
0261     QAction *act = collection->add<KToggleAction>("disableRandomPlay");
0262     act->setText(i18n("&Disable Random Play"));
0263     act->setIcon("go-down"_icon);
0264     act->setActionGroup(randomPlayGroup);
0265     actionMenu->addAction(act);
0266 
0267     m_randomPlayAction = collection->add<KToggleAction>("randomPlay");
0268     m_randomPlayAction->setText(i18n("Use &Random Play"));
0269     m_randomPlayAction->setIcon("media-playlist-shuffle"_icon);
0270     m_randomPlayAction->setActionGroup(randomPlayGroup);
0271     actionMenu->addAction(m_randomPlayAction);
0272 
0273     act = collection->add<KToggleAction>("albumRandomPlay");
0274     act->setText(i18n("Use &Album Random Play"));
0275     act->setIcon("media-playlist-shuffle"_icon);
0276     act->setActionGroup(randomPlayGroup);
0277     connect(act, &QAction::toggled,
0278             this, &JuK::slotCheckAlbumNextAction);
0279     actionMenu->addAction(act);
0280 
0281     act = collection->addAction("removeFromPlaylist", clear, SLOT(clear()));
0282     act->setText(i18n("Remove From Playlist"));
0283     act->setIcon("list-remove"_icon);
0284 
0285     act = collection->addAction("play", m_player, SLOT(play()));
0286     act->setText(i18n("&Play"));
0287     act->setIcon("media-playback-start"_icon);
0288 
0289     act = collection->addAction("pause", m_player, SLOT(pause()));
0290     act->setEnabled(false);
0291     act->setText(i18n("P&ause"));
0292     act->setIcon("media-playback-pause"_icon);
0293 
0294     act = collection->addAction("stop", m_player, SLOT(stop()));
0295     act->setEnabled(false);
0296     act->setText(i18n("&Stop"));
0297     act->setIcon("media-playback-stop"_icon);
0298 
0299     act = new KToolBarPopupAction("media-skip-backward"_icon, i18nc("previous track", "Previous" ), collection);
0300     act->setEnabled(false);
0301     collection->addAction("back", act);
0302     connect(act, SIGNAL(triggered(bool)), m_player, SLOT(back()));
0303 
0304     act = collection->addAction("forward", m_player, SLOT(forward()));
0305     act->setEnabled(false);
0306     act->setText(i18nc("next track", "&Next"));
0307     act->setIcon("media-skip-forward"_icon);
0308 
0309     act = collection->addAction("loopPlaylist");
0310     act->setText(i18n("&Loop Playlist"));
0311     act->setCheckable(true);
0312 
0313     act = collection->add<KToggleAction>("resizeColumnsManually");
0314     act->setText(i18n("&Resize Playlist Columns Manually"));
0315 
0316     // the following are not visible by default
0317 
0318     act = collection->addAction("mute", m_player, SLOT(mute()));
0319     act->setText(i18nc("silence playback", "Mute"));
0320     act->setIcon("audio-volume-muted"_icon);
0321 
0322     act = collection->addAction("volumeUp", m_player, SLOT(volumeUp()));
0323     act->setText(i18n("Volume Up"));
0324     act->setIcon("audio-volume-high"_icon);
0325 
0326     act = collection->addAction("volumeDown", m_player, SLOT(volumeDown()));
0327     act->setText(i18n("Volume Down"));
0328     act->setIcon("audio-volume-low"_icon);
0329 
0330     act = collection->addAction("playPause", m_player, SLOT(playPause()));
0331     act->setText(i18n("Play / Pause"));
0332     act->setIcon("media-playback-start"_icon);
0333 
0334     act = collection->addAction("seekForward", m_player, SLOT(seekForward()));
0335     act->setText(i18n("Seek Forward"));
0336     act->setIcon("media-seek-forward"_icon);
0337 
0338     act = collection->addAction("seekBack", m_player, SLOT(seekBack()));
0339     act->setText(i18n("Seek Back"));
0340     act->setIcon("media-seek-backward"_icon);
0341 
0342     act = collection->addAction("showHide", this, SLOT(slotShowHide()));
0343     act->setText(i18n("Show / Hide"));
0344 
0345     //////////////////////////////////////////////////
0346     // settings menu
0347     //////////////////////////////////////////////////
0348 
0349     m_toggleSystemTrayAction = collection->add<KToggleAction>("toggleSystemTray");
0350     m_toggleSystemTrayAction->setText(i18n("&Dock in System Tray"));
0351     connect(m_toggleSystemTrayAction, SIGNAL(triggered(bool)), SLOT(slotToggleSystemTray(bool)));
0352 
0353     m_toggleDockOnCloseAction = collection->add<KToggleAction>("dockOnClose");
0354     m_toggleDockOnCloseAction->setText(i18n("&Stay in System Tray on Close"));
0355 
0356     m_togglePopupsAction = collection->add<KToggleAction>("togglePopups");
0357     m_togglePopupsAction->setText(i18n("Popup &Track Announcement"));
0358 
0359     act = collection->add<KToggleAction>("saveUpcomingTracks");
0360     act->setText(i18n("Save &Play Queue on Exit"));
0361 
0362     act = collection->addAction("tagGuesserConfig", this, SLOT(slotConfigureTagGuesser()));
0363     act->setText(i18n("&Tag Guesser..."));
0364 
0365     act = collection->addAction("fileRenamerConfig", this, SLOT(slotConfigureFileRenamer()));
0366     act->setText(i18n("&File Renamer..."));
0367 
0368     act = collection->addAction("scrobblerConfig", this, SLOT(slotConfigureScrobbling()));
0369     act->setText(i18n("&Configure scrobbling..."));
0370 
0371     //////////////////////////////////////////////////
0372     // just in the toolbar
0373     //////////////////////////////////////////////////
0374 
0375     collection->addAction("trackPositionAction",
0376                           new TrackPositionAction(i18n("Track Position"), this));
0377     collection->addAction("volumeAction",
0378                           new VolumeAction(i18n("Volume"), this));
0379 
0380     ActionCollection::actions()->addAssociatedWidget(this);
0381     foreach (QAction* action, ActionCollection::actions()->actions())
0382         action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0383 }
0384 
0385 void JuK::slotSetupSystemTray()
0386 {
0387     if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
0388         m_systemTray = new SystemTray(m_player, this);
0389         m_systemTray->setObjectName(QStringLiteral("systemTray"));
0390 
0391         m_toggleDockOnCloseAction->setEnabled(true);
0392         m_togglePopupsAction->setEnabled(true);
0393 
0394         // since we need the information if the main window is visible
0395         // when quit was selected, we need to reroute the signal to our slot
0396         QAction *quitAction = m_systemTray->action(QStringLiteral("quit"));
0397         if (quitAction) {
0398             quitAction->disconnect();
0399             connect(quitAction, &QAction::triggered, this, &JuK::slotQuit);
0400         }
0401 
0402         // If this flag gets set then JuK will quit if you click the cover on
0403         // the track announcement popup when JuK is only in the system tray
0404         // (the systray has no widget).
0405 
0406         qGuiApp->setQuitOnLastWindowClosed(false);
0407     }
0408     else {
0409         m_systemTray = nullptr;
0410         m_toggleDockOnCloseAction->setEnabled(false);
0411         m_togglePopupsAction->setEnabled(false);
0412     }
0413 }
0414 
0415 void JuK::setupGlobalAccels()
0416 {
0417     KeyDialog::setupActionShortcut("play");
0418     KeyDialog::setupActionShortcut("playPause");
0419     KeyDialog::setupActionShortcut("stop");
0420     KeyDialog::setupActionShortcut("back");
0421     KeyDialog::setupActionShortcut("forward");
0422     KeyDialog::setupActionShortcut("seekBack");
0423     KeyDialog::setupActionShortcut("seekForward");
0424     KeyDialog::setupActionShortcut("volumeUp");
0425     KeyDialog::setupActionShortcut("volumeDown");
0426     KeyDialog::setupActionShortcut("mute");
0427     KeyDialog::setupActionShortcut("showHide");
0428     KeyDialog::setupActionShortcut("forwardAlbum");
0429 }
0430 
0431 void JuK::slotProcessArgs()
0432 {
0433     CollectionList::instance()->addFiles(m_filesToOpen);
0434 }
0435 
0436 void JuK::slotClearOldCovers()
0437 {
0438     // Find all saved covers from the previous run of JuK and clear them out, in case
0439     // we find our tracks in a different order this run, which would cause old saved
0440     // covers to be wrong.
0441     // See mpris2/mediaplayer2player.cpp
0442     QString tmpDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
0443     QStringList nameFilters;
0444 
0445     nameFilters << QStringLiteral("juk-cover-*.png");
0446     QDirIterator jukCoverIter(tmpDir, nameFilters);
0447     while (jukCoverIter.hasNext()) {
0448         QFile::remove(jukCoverIter.next());
0449     }
0450 }
0451 
0452 void JuK::keyPressEvent(QKeyEvent *e)
0453 {
0454     if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
0455         e->accept();
0456     KXmlGuiWindow::keyPressEvent(e);
0457 }
0458 
0459 void JuK::readConfig()
0460 {
0461     // player settings
0462 
0463     KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player");
0464 
0465     if(m_player)
0466     {
0467         const int maxVolume = 100;
0468         const int volume = playerConfig.readEntry("Volume", maxVolume);
0469         m_player->setVolume(volume * 0.01);
0470 
0471         //bool enableCrossfade = playerConfig.readEntry("CrossfadeTracks", true);
0472         //m_player->setCrossfadeEnabled(enableCrossfade);
0473         //ActionCollection::action<QAction>("crossfadeTracks")->setChecked(enableCrossfade);
0474     }
0475 
0476     // Default to no random play
0477 
0478     ActionCollection::action<KToggleAction>("disableRandomPlay")->setChecked(true);
0479 
0480     QString randomPlayMode = playerConfig.readEntry("RandomPlay", "Disabled");
0481     if(randomPlayMode == "true" || randomPlayMode == "Normal")
0482         m_randomPlayAction->setChecked(true);
0483     else if(randomPlayMode == "AlbumRandomPlay")
0484         ActionCollection::action<QAction>("albumRandomPlay")->setChecked(true);
0485 
0486     bool loopPlaylist = playerConfig.readEntry("LoopPlaylist", false);
0487     ActionCollection::action<QAction>("loopPlaylist")->setChecked(loopPlaylist);
0488 
0489     // general settings
0490 
0491     KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings");
0492 
0493     bool dockInSystemTray = settingsConfig.readEntry("DockInSystemTray", true);
0494     m_toggleSystemTrayAction->setChecked(dockInSystemTray);
0495 
0496     bool dockOnClose = settingsConfig.readEntry("DockOnClose", true);
0497     m_toggleDockOnCloseAction->setChecked(dockOnClose);
0498 
0499     bool showPopups = settingsConfig.readEntry("TrackPopup", false);
0500     m_togglePopupsAction->setChecked(showPopups);
0501 }
0502 
0503 void JuK::saveConfig()
0504 {
0505     // player settings
0506 
0507     KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player");
0508 
0509     if (m_player)
0510     {
0511         playerConfig.writeEntry("Volume", static_cast<int>(100.0 * m_player->volume()));
0512     }
0513 
0514     playerConfig.writeEntry("RandomPlay", m_randomPlayAction->isChecked());
0515 
0516     QAction *a = ActionCollection::action<QAction>("loopPlaylist");
0517     playerConfig.writeEntry("LoopPlaylist", a->isChecked());
0518 
0519     playerConfig.writeEntry("CrossfadeTracks", false); // TODO bring back
0520 
0521     a = ActionCollection::action<QAction>("albumRandomPlay");
0522     if(a->isChecked())
0523         playerConfig.writeEntry("RandomPlay", "AlbumRandomPlay");
0524     else if(m_randomPlayAction->isChecked())
0525         playerConfig.writeEntry("RandomPlay", "Normal");
0526     else
0527         playerConfig.writeEntry("RandomPlay", "Disabled");
0528 
0529     // general settings
0530 
0531     KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings");
0532     settingsConfig.writeEntry("StartDocked", !isVisible() && m_toggleDockOnCloseAction->isChecked());
0533     settingsConfig.writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
0534     settingsConfig.writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
0535     settingsConfig.writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
0536 
0537     KSharedConfig::openConfig()->sync();
0538 }
0539 
0540 bool JuK::queryClose()
0541 {
0542     if(!m_shuttingDown &&
0543        !qApp->isSavingSession() &&
0544        m_systemTray &&
0545        m_toggleDockOnCloseAction->isChecked())
0546     {
0547         KMessageBox::information(this,
0548             i18n("<qt>Closing the main window will keep JuK running in the system tray. "
0549                  "Use Quit from the File menu to quit the application.</qt>"),
0550             i18n("Docking in System Tray"), "hideOnCloseInfo");
0551         hide();
0552         return false;
0553     }
0554 
0555     return true;
0556 }
0557 
0558 ////////////////////////////////////////////////////////////////////////////////
0559 // private slot definitions
0560 ////////////////////////////////////////////////////////////////////////////////
0561 
0562 void JuK::slotShowHide()
0563 {
0564     setHidden(!isHidden());
0565 }
0566 
0567 void JuK::slotQuit()
0568 {
0569     m_shuttingDown = true;
0570 
0571     // Some phonon backends will crash on shutdown unless we've stopped
0572     // playback.
0573     if(m_player->playing()) {
0574         m_player->stop();
0575     }
0576 
0577     saveConfig();
0578 
0579     // this will start chain of events causing PlaylistCollection (in
0580     // guise of PlaylistBox) and CollectionList (as first Playlist child)
0581     // to save themselves and then quit the application when this widget
0582     // closes.
0583     delete m_statusLabel;
0584     m_statusLabel = nullptr;
0585 
0586     delete m_splitter;
0587     m_splitter = nullptr;
0588 
0589     close();
0590 }
0591 
0592 ////////////////////////////////////////////////////////////////////////////////
0593 // settings menu
0594 ////////////////////////////////////////////////////////////////////////////////
0595 
0596 void JuK::slotToggleSystemTray(bool enabled)
0597 {
0598     if(enabled && !m_systemTray)
0599         slotSetupSystemTray();
0600     else if(!enabled && m_systemTray) {
0601         delete m_systemTray;
0602         m_systemTray = nullptr;
0603         m_toggleDockOnCloseAction->setEnabled(false);
0604         m_togglePopupsAction->setEnabled(false);
0605 
0606         qGuiApp->setQuitOnLastWindowClosed(true);
0607     }
0608 }
0609 
0610 void JuK::slotEditKeys()
0611 {
0612     KeyDialog(ActionCollection::actions(), this).configure();
0613 }
0614 
0615 void JuK::slotConfigureTagGuesser()
0616 {
0617     TagGuesserConfigDlg(this).exec();
0618 }
0619 
0620 void JuK::slotConfigureFileRenamer()
0621 {
0622     FileRenamerConfigDlg(this).exec();
0623 }
0624 
0625 void JuK::slotConfigureScrobbling()
0626 {
0627     ScrobbleConfigDlg(this).exec();
0628     activateScrobblerIfEnabled();
0629 }
0630 
0631 void JuK::activateScrobblerIfEnabled()
0632 {
0633     bool isScrobbling = Scrobbler::isScrobblingEnabled();
0634 
0635     if (!m_scrobbler && isScrobbling) {
0636         m_scrobbler = new Scrobbler(this);
0637         connect (m_player,    SIGNAL(signalItemChanged(FileHandle)),
0638                  m_scrobbler, SLOT(nowPlaying(FileHandle)));
0639     }
0640     else if (m_scrobbler && !isScrobbling) {
0641         delete m_scrobbler;
0642         m_scrobbler = 0;
0643     }
0644 }
0645 
0646 void JuK::slotUndo()
0647 {
0648     TagTransactionManager::instance()->undo();
0649 }
0650 
0651 void JuK::slotCheckAlbumNextAction(bool albumRandomEnabled)
0652 {
0653     action("forwardAlbum")->setEnabled(m_player->playing() && albumRandomEnabled);
0654 }
0655 
0656 // vim: set et sw=4 tw=0 sta: