File indexing completed on 2022-08-11 17:17:09

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