juk.cpp 21.8 KB
Newer Older
1 2
/**
 * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
3
 * Copyright (C) 2008, 2009, 2017 Michael Pyne <mpyne@kde.org>
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
17

18 19
#include "juk.h"

20
#include <kaboutdata.h>
21
#include <kmessagebox.h>
Laurent Montel's avatar
Laurent Montel committed
22
#include <kactioncollection.h>
23
#include <kstandardaction.h>
Laurent Montel's avatar
Laurent Montel committed
24 25
#include <ktoggleaction.h>
#include <kactionmenu.h>
26
#include <kconfiggroup.h>
Michael Pyne's avatar
Michael Pyne committed
27
#include <KSharedConfig>
28 29
#include <kglobalaccel.h>
#include <ktoolbarpopupaction.h>
30
#include <knotification.h>
31

32 33
#include <QIcon>
#include <QAction>
34
#include <QCoreApplication>
35
#include <QKeyEvent>
36
#include <QDir>
37
#include <QDirIterator>
38
#include <QMenuBar>
39
#include <QMetaType>
40
#include <QTime>
41
#include <QTimer>
42
#include <QDesktopWidget>
Michael Pyne's avatar
Michael Pyne committed
43
#include <QStatusBar>
44 45 46
#include <QDBusMessage>
#include <QDBusReply>
#include <QDBusInterface>
47

48 49 50 51 52
#include "slideraction.h"
#include "statuslabel.h"
#include "systemtray.h"
#include "keydialog.h"
#include "tagguesserconfigdlg.h"
53
#include "filerenamerconfigdlg.h"
54
#include "scrobbler.h"
55
#include "scrobbleconfigdlg.h"
56
#include "actioncollection.h"
57
#include "cache.h"
58 59
#include "playlistsplitter.h"
#include "collectionlist.h"
60
#include "covermanager.h"
61
#include "tagtransactionmanager.h"
Michael Pyne's avatar
Michael Pyne committed
62
#include "juk_debug.h"
63

64 65
using namespace ActionCollection;

66 67
JuK* JuK::m_instance;

68 69 70 71 72 73 74
template<class T>
void deleteAndClear(T *&ptr)
{
    delete ptr;
    ptr = 0;
}

75 76 77 78
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

79
JuK::JuK(const QStringList &filesToOpen, QWidget *parent) :
80
    KXmlGuiWindow(parent, Qt::WindowFlags(Qt::WA_DeleteOnClose)),
81 82 83
    m_splitter(nullptr),
    m_statusLabel(nullptr),
    m_systemTray(nullptr),
84
    m_player(new PlayerManager),
85
    m_scrobbler(nullptr),
Michael Pyne's avatar
Michael Pyne committed
86
    m_filesToOpen(filesToOpen),
87 88
    m_shuttingDown(false),
    m_pmToken(0)
89
{
90 91
    // Expect segfaults if you change this order.

92 93 94 95
    // Allow to be passed across threads
    qRegisterMetaType<FileHandle>();
    qRegisterMetaType<FileHandleList>();

96 97
    m_instance = this;

98
    readSettings();
99

100 101
    Cache::ensureAppDataStorageExists();

102
    setupActions();
103
    setupLayout();
104

105
    bool firstRun = !KSharedConfig::openConfig()->hasGroup("MainWindow");
106 107

    if(firstRun) {
108
        KConfigGroup mainWindowConfig(KSharedConfig::openConfig(), "MainWindow");
109 110 111 112
        KConfigGroup playToolBarConfig(&mainWindowConfig, "Toolbar playToolBar");
        playToolBarConfig.writeEntry("ToolButtonStyle", "IconOnly");
    }

113 114
    QSize defaultSize(800, 480);

115
    if(QApplication::isRightToLeft())
116
        setupGUI(defaultSize, ToolBar | Save | Create, "jukui-rtl.rc");
117
    else
118 119 120 121
        setupGUI(defaultSize, ToolBar | Save | Create);

    // Center the GUI if this is our first run ever.

122
    if(firstRun) {
123
        QRect r = rect();
124
        r.moveCenter(QApplication::desktop()->screenGeometry().center());
125 126
        move(r.topLeft());
    }
127

Michael Pyne's avatar
Michael Pyne committed
128
    connect(m_splitter, SIGNAL(guiReady()), SLOT(slotSetupSystemTray()));
129
    readConfig();
130
    setupGlobalAccels();
131
    activateScrobblerIfEnabled();
132

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    QDBusInterface *pmInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
                                       QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"),
                                       QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
                                       QDBusConnection::sessionBus());

    connect(m_player, &PlayerManager::signalPlay, [=] () {
        QDBusReply<uint> reply;
        if (pmInterface->isValid() && (m_pmToken == 0)) {
            reply = pmInterface->call(QStringLiteral("Inhibit"),
                               KAboutData::applicationData().componentName(),
                               QStringLiteral("playing audio"));
            if (reply.isValid()) {
                m_pmToken = reply.value();
            }
        }
    });

    auto uninhibitPowerManagement = [=] () {
        QDBusMessage reply;
        if (pmInterface->isValid() && (m_pmToken != 0)) {
            reply = pmInterface->call(QStringLiteral("UnInhibit"), m_pmToken);
            if (reply.errorName().isEmpty()) {
                m_pmToken = 0;
            }
        }
    };

    connect(m_player, &PlayerManager::signalPause, uninhibitPowerManagement);
    connect(m_player, &PlayerManager::signalStop, uninhibitPowerManagement);

163 164 165 166 167
    // The system tray quit command will go straight to qApp->quit without calling
    // our quit action, so make sure we save config changes no matter how quit is
    // called.
    connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() { saveConfig(); });

Michael Pyne's avatar
Michael Pyne committed
168 169
    // slotCheckCache loads the cached entries first to populate the collection list

170
    QTimer::singleShot(0, this, SLOT(slotClearOldCovers()));
171
    QTimer::singleShot(0, CollectionList::instance(), SLOT(startLoadingCachedItems()));
172
    QTimer::singleShot(0, this, SLOT(slotProcessArgs()));
173 174 175 176
}

JuK::~JuK()
{
177 178 179 180 181 182 183 184 185 186 187 188 189
    if(!m_shuttingDown) {
        // Sometimes KMainWindow doesn't actually call QCoreApplication::quit
        // after queryClose, even if not in a session shutdown, so make sure to
        // do so ourselves when closing the main window.
        slotQuit();
    }

    // Some items need to be deleted before others, though I haven't looked
    // at this in some time so refinement is probably possible.
    delete m_systemTray;
    delete m_splitter;
    delete m_player;
    delete m_statusLabel;
190 191
}

192 193 194 195 196
JuK* JuK::JuKInstance()
{
    return m_instance;
}

197 198 199 200 201
PlayerManager *JuK::playerManager() const
{
    return m_player;
}

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
void JuK::coverDownloaded(const QPixmap &cover)
{
    QString event(cover.isNull() ? "coverFailed" : "coverDownloaded");
    KNotification *notification = new KNotification(event, this);
    notification->setPixmap(cover);
    notification->setFlags(KNotification::CloseOnTimeout);

    if(cover.isNull())
        notification->setText(i18n("Your album art failed to download."));
    else
        notification->setText(i18n("Your album art has finished downloading."));

    notification->sendEvent();
}

217 218 219 220
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

221 222
void JuK::setupLayout()
{
223
    m_splitter = new PlaylistSplitter(m_player, this);
224
    setCentralWidget(m_splitter);
225

226
    m_statusLabel = new StatusLabel(*m_splitter->playlist(), statusBar());
227
    statusBar()->addWidget(m_statusLabel, 1);
228 229 230 231 232 233
    connect(m_player, &PlayerManager::tick, m_statusLabel,
            &StatusLabel::setItemCurrentTime);
    connect(m_player, &PlayerManager::totalTimeChanged,
            m_statusLabel, &StatusLabel::setItemTotalTime);
    connect(m_splitter, &PlaylistSplitter::currentPlaylistChanged,
            m_statusLabel, &StatusLabel::slotCurrentPlaylistHasChanged);
234

235
    m_splitter->setFocus();
236 237
}

238 239
void JuK::setupActions()
{
240
    KActionCollection *collection = ActionCollection::actions();
Michael Pyne's avatar
Michael Pyne committed
241

242
    // Setup KDE standard actions that JuK uses.
243

244 245 246 247 248
    KStandardAction::quit(this, SLOT(slotQuit()), collection);
    KStandardAction::undo(this, SLOT(slotUndo()), collection);
    KStandardAction::cut(collection);
    KStandardAction::copy(collection);
    KStandardAction::paste(collection);
249
    QAction *clear = KStandardAction::clear(collection);
250 251
    KStandardAction::selectAll(collection);
    KStandardAction::keyBindings(this, SLOT(slotEditKeys()), collection);
252
    KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), collection);
Scott Wheeler's avatar
Scott Wheeler committed
253

254
    // Setup the menu which handles the random play options.
255 256
    KActionMenu *actionMenu = collection->add<KActionMenu>("actionMenu");
    actionMenu->setText(i18n("&Random Play"));
Michael Pyne's avatar
Michael Pyne committed
257
    actionMenu->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" )));
258
    actionMenu->setDelayed(false);
259

260
    QActionGroup* randomPlayGroup = new QActionGroup(this);
David Faure's avatar
David Faure committed
261

262 263
    QAction *act = collection->add<KToggleAction>("disableRandomPlay");
    act->setText(i18n("&Disable Random Play"));
Michael Pyne's avatar
Michael Pyne committed
264
    act->setIcon(QIcon::fromTheme( QLatin1String( "go-down" )));
265
    act->setActionGroup(randomPlayGroup);
266
    actionMenu->addAction(act);
267

Laurent Montel's avatar
Laurent Montel committed
268 269
    m_randomPlayAction = collection->add<KToggleAction>("randomPlay");
    m_randomPlayAction->setText(i18n("Use &Random Play"));
Michael Pyne's avatar
Michael Pyne committed
270
    m_randomPlayAction->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" )));
David Faure's avatar
David Faure committed
271
    m_randomPlayAction->setActionGroup(randomPlayGroup);
272
    actionMenu->addAction(m_randomPlayAction);
273

274
    act = collection->add<KToggleAction>("albumRandomPlay");
275
    act->setEnabled(false);
276
    act->setText(i18n("Use &Album Random Play"));
Michael Pyne's avatar
Michael Pyne committed
277
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" )));
278 279
    act->setActionGroup(randomPlayGroup);
    connect(act, SIGNAL(triggered(bool)), SLOT(slotCheckAlbumNextAction(bool)));
280
    actionMenu->addAction(act);
281

282
    act = collection->addAction("removeFromPlaylist", clear, SLOT(clear()));
Laurent Montel's avatar
Laurent Montel committed
283
    act->setText(i18n("Remove From Playlist"));
Michael Pyne's avatar
Michael Pyne committed
284
    act->setIcon(QIcon::fromTheme( QLatin1String( "list-remove" )));
Laurent Montel's avatar
Laurent Montel committed
285

286 287
    act = collection->addAction("play", m_player, SLOT(play()));
    act->setText(i18n("&Play"));
Michael Pyne's avatar
Michael Pyne committed
288
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" )));
289

290
    act = collection->addAction("pause", m_player, SLOT(pause()));
291
    act->setEnabled(false);
292
    act->setText(i18n("P&ause"));
Michael Pyne's avatar
Michael Pyne committed
293
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-pause" )));
294

295
    act = collection->addAction("stop", m_player, SLOT(stop()));
296
    act->setEnabled(false);
297
    act->setText(i18n("&Stop"));
Michael Pyne's avatar
Michael Pyne committed
298
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-stop" )));
Scott Wheeler's avatar
Scott Wheeler committed
299

Michael Pyne's avatar
Michael Pyne committed
300
    act = new KToolBarPopupAction(QIcon::fromTheme( QLatin1String( "media-skip-backward") ), i18nc("previous track", "Previous" ), collection);
301
    act->setEnabled(false);
302
    collection->addAction("back", act);
303 304
    connect(act, SIGNAL(triggered(bool)), m_player, SLOT(back()));

305
    act = collection->addAction("forward", m_player, SLOT(forward()));
306
    act->setEnabled(false);
307
    act->setText(i18nc("next track", "&Next"));
Michael Pyne's avatar
Michael Pyne committed
308
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-skip-forward" )));
309

310 311
    act = collection->addAction("loopPlaylist");
    act->setText(i18n("&Loop Playlist"));
312 313
    act->setCheckable(true);

314 315
    act = collection->add<KToggleAction>("resizeColumnsManually");
    act->setText(i18n("&Resize Playlist Columns Manually"));
316 317

    // the following are not visible by default
318

319 320
    act = collection->addAction("mute", m_player, SLOT(mute()));
    act->setText(i18nc("silence playback", "Mute"));
Michael Pyne's avatar
Michael Pyne committed
321
    act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-muted" )));
322

323 324
    act = collection->addAction("volumeUp", m_player, SLOT(volumeUp()));
    act->setText(i18n("Volume Up"));
Michael Pyne's avatar
Michael Pyne committed
325
    act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-high" )));
326

327 328
    act = collection->addAction("volumeDown", m_player, SLOT(volumeDown()));
    act->setText(i18n("Volume Down"));
Michael Pyne's avatar
Michael Pyne committed
329
    act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-low" )));
330

331 332
    act = collection->addAction("playPause", m_player, SLOT(playPause()));
    act->setText(i18n("Play / Pause"));
Michael Pyne's avatar
Michael Pyne committed
333
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" )));
334

335 336
    act = collection->addAction("seekForward", m_player, SLOT(seekForward()));
    act->setText(i18n("Seek Forward"));
Michael Pyne's avatar
Michael Pyne committed
337
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-seek-forward" )));
338

339 340
    act = collection->addAction("seekBack", m_player, SLOT(seekBack()));
    act->setText(i18n("Seek Back"));
Michael Pyne's avatar
Michael Pyne committed
341
    act->setIcon(QIcon::fromTheme( QLatin1String( "media-seek-backward" )));
342

343 344
    act = collection->addAction("showHide", this, SLOT(slotShowHide()));
    act->setText(i18n("Show / Hide"));
Stephan Binner's avatar
Stephan Binner committed
345

346
    //////////////////////////////////////////////////
347
    // settings menu
348 349
    //////////////////////////////////////////////////

350 351 352 353 354 355
    m_toggleSystemTrayAction = collection->add<KToggleAction>("toggleSystemTray");
    m_toggleSystemTrayAction->setText(i18n("&Dock in System Tray"));
    connect(m_toggleSystemTrayAction, SIGNAL(triggered(bool)), SLOT(slotToggleSystemTray(bool)));

    m_toggleDockOnCloseAction = collection->add<KToggleAction>("dockOnClose");
    m_toggleDockOnCloseAction->setText(i18n("&Stay in System Tray on Close"));
356

357 358
    m_togglePopupsAction = collection->add<KToggleAction>("togglePopups");
    m_togglePopupsAction->setText(i18n("Popup &Track Announcement"));
359

360 361
    act = collection->add<KToggleAction>("saveUpcomingTracks");
    act->setText(i18n("Save &Play Queue on Exit"));
Scott Wheeler's avatar
Scott Wheeler committed
362

363 364
    act = collection->addAction("tagGuesserConfig", this, SLOT(slotConfigureTagGuesser()));
    act->setText(i18n("&Tag Guesser..."));
365

366 367
    act = collection->addAction("fileRenamerConfig", this, SLOT(slotConfigureFileRenamer()));
    act->setText(i18n("&File Renamer..."));
368

369
    act = collection->addAction("scrobblerConfig", this, SLOT(slotConfigureScrobbling()));
370
    act->setText(i18n("&Configure scrobbling..."));
371

372
    //////////////////////////////////////////////////
373
    // just in the toolbar
374 375
    //////////////////////////////////////////////////

376 377 378
    collection->addAction("trackPositionAction",
                          new TrackPositionAction(i18n("Track Position"), this));
    collection->addAction("volumeAction",
379
                          new VolumeAction(i18n("Volume"), this));
380

381 382 383
    ActionCollection::actions()->addAssociatedWidget(this);
    foreach (QAction* action, ActionCollection::actions()->actions())
        action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
384 385
}

Michael Pyne's avatar
Michael Pyne committed
386
void JuK::slotSetupSystemTray()
387
{
388
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
389
        m_systemTray = new SystemTray(m_player, this);
390
        m_systemTray->setObjectName(QStringLiteral("systemTray"));
391

392 393
        m_toggleDockOnCloseAction->setEnabled(true);
        m_togglePopupsAction->setEnabled(true);
394 395 396 397 398 399

        // If this flag gets set then JuK will quit if you click the cover on
        // the track announcement popup when JuK is only in the system tray
        // (the systray has no widget).

        qGuiApp->setQuitOnLastWindowClosed(false);
400
    }
401
    else {
402
        m_systemTray = nullptr;
403 404
        m_toggleDockOnCloseAction->setEnabled(false);
        m_togglePopupsAction->setEnabled(false);
405
    }
406 407
}

408 409
void JuK::setupGlobalAccels()
{
410 411 412 413 414 415 416 417 418 419 420 421
    KeyDialog::setupActionShortcut("play");
    KeyDialog::setupActionShortcut("playPause");
    KeyDialog::setupActionShortcut("stop");
    KeyDialog::setupActionShortcut("back");
    KeyDialog::setupActionShortcut("forward");
    KeyDialog::setupActionShortcut("seekBack");
    KeyDialog::setupActionShortcut("seekForward");
    KeyDialog::setupActionShortcut("volumeUp");
    KeyDialog::setupActionShortcut("volumeDown");
    KeyDialog::setupActionShortcut("mute");
    KeyDialog::setupActionShortcut("showHide");
    KeyDialog::setupActionShortcut("forwardAlbum");
422 423
}

424
void JuK::slotProcessArgs()
425
{
426
    CollectionList::instance()->addFiles(m_filesToOpen);
427 428
}

429 430 431 432 433 434
void JuK::slotClearOldCovers()
{
    // Find all saved covers from the previous run of JuK and clear them out, in case
    // we find our tracks in a different order this run, which would cause old saved
    // covers to be wrong.
    // See mpris2/mediaplayer2player.cpp
435 436
    QString tmpDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
    QStringList nameFilters;
437

438 439 440 441
    nameFilters << QStringLiteral("juk-cover-*.png");
    QDirIterator jukCoverIter(tmpDir, nameFilters);
    while (jukCoverIter.hasNext()) {
        QFile::remove(jukCoverIter.next());
442 443 444
    }
}

445 446 447
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
448
        e->accept();
Kevin Ottens's avatar
Kevin Ottens committed
449
    KXmlGuiWindow::keyPressEvent(e);
450 451
}

452 453 454 455 456 457
/**
 * These are settings that need to be know before setting up the GUI.
 */

void JuK::readSettings()
{
458
    KConfigGroup config(KSharedConfig::openConfig(), "Settings");
459
    m_startDocked = config.readEntry("StartDocked", false);
460 461
}

462 463
void JuK::readConfig()
{
464
    // player settings
465

466
    KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player");
467

468 469 470 471 472
    if(m_player)
    {
        const int maxVolume = 100;
        const int volume = playerConfig.readEntry("Volume", maxVolume);
        m_player->setVolume(volume * 0.01);
473

474 475
        //bool enableCrossfade = playerConfig.readEntry("CrossfadeTracks", true);
        //m_player->setCrossfadeEnabled(enableCrossfade);
Michael Pyne's avatar
Michael Pyne committed
476
        //ActionCollection::action<QAction>("crossfadeTracks")->setChecked(enableCrossfade);
477
    }
478

479 480
    // Default to no random play

481
    ActionCollection::action<KToggleAction>("disableRandomPlay")->setChecked(true);
482

483 484
    QString randomPlayMode = playerConfig.readEntry("RandomPlay", "Disabled");
    if(randomPlayMode == "true" || randomPlayMode == "Normal")
485
        m_randomPlayAction->setChecked(true);
486
    else if(randomPlayMode == "AlbumRandomPlay")
Michael Pyne's avatar
Michael Pyne committed
487
        ActionCollection::action<QAction>("albumRandomPlay")->setChecked(true);
488

489
    bool loopPlaylist = playerConfig.readEntry("LoopPlaylist", false);
490
    ActionCollection::action<QAction>("loopPlaylist")->setChecked(loopPlaylist);
491

492
    // general settings
493

494
    KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings");
495

496
    bool dockInSystemTray = settingsConfig.readEntry("DockInSystemTray", true);
497 498
    m_toggleSystemTrayAction->setChecked(dockInSystemTray);

499
    bool dockOnClose = settingsConfig.readEntry("DockOnClose", true);
500 501
    m_toggleDockOnCloseAction->setChecked(dockOnClose);

502
    bool showPopups = settingsConfig.readEntry("TrackPopup", false);
503
    m_togglePopupsAction->setChecked(showPopups);
504 505 506 507
}

void JuK::saveConfig()
{
508
    // player settings
509

510
    KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player");
511

512
    if (m_player)
513
    {
514
        playerConfig.writeEntry("Volume", static_cast<int>(100.0 * m_player->volume()));
515 516
    }

517 518
    playerConfig.writeEntry("RandomPlay", m_randomPlayAction->isChecked());

Michael Pyne's avatar
Michael Pyne committed
519
    QAction *a = ActionCollection::action<QAction>("loopPlaylist");
520 521
    playerConfig.writeEntry("LoopPlaylist", a->isChecked());

522
    playerConfig.writeEntry("CrossfadeTracks", false); // TODO bring back
523

Michael Pyne's avatar
Michael Pyne committed
524
    a = ActionCollection::action<QAction>("albumRandomPlay");
525
    if(a->isChecked())
526
        playerConfig.writeEntry("RandomPlay", "AlbumRandomPlay");
527
    else if(m_randomPlayAction->isChecked())
528
        playerConfig.writeEntry("RandomPlay", "Normal");
529
    else
530
        playerConfig.writeEntry("RandomPlay", "Disabled");
531

532 533
    // general settings

534
    KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings");
535 536 537 538 539
    settingsConfig.writeEntry("StartDocked", m_startDocked);
    settingsConfig.writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
    settingsConfig.writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
    settingsConfig.writeEntry("TrackPopup", m_togglePopupsAction->isChecked());

540
    KSharedConfig::openConfig()->sync();
541 542
}

543 544
bool JuK::queryClose()
{
545
    if(!m_shuttingDown &&
546
       !qApp->isSavingSession() &&
547 548 549
       m_systemTray &&
       m_toggleDockOnCloseAction->isChecked())
    {
550 551 552 553 554 555
        KMessageBox::information(this,
            i18n("<qt>Closing the main window will keep JuK running in the system tray. "
                 "Use Quit from the File menu to quit the application.</qt>"),
            i18n("Docking in System Tray"), "hideOnCloseInfo");
        hide();
        return false;
556
    }
557 558

    return true;
559 560
}

561 562 563 564
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

565 566
void JuK::slotShowHide()
{
Stephan Kulow's avatar
Stephan Kulow committed
567
    setHidden(!isHidden());
568 569
}

570 571
void JuK::slotQuit()
{
Michael Pyne's avatar
Michael Pyne committed
572
    m_shuttingDown = true;
573

574 575 576 577 578 579 580
    // Some phonon backends will crash on shutdown unless we've stopped
    // playback.
    if(m_player->playing()) {
        m_player->stop();
    }

    m_startDocked = !isVisible();
581
    saveConfig();
582 583

    QTimer::singleShot(0, qApp, &QCoreApplication::quit);
584 585
}

586 587 588 589
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

590
void JuK::slotToggleSystemTray(bool enabled)
591
{
592
    if(enabled && !m_systemTray)
Michael Pyne's avatar
Michael Pyne committed
593
        slotSetupSystemTray();
594
    else if(!enabled && m_systemTray) {
595
        delete m_systemTray;
596
        m_systemTray = nullptr;
597 598
        m_toggleDockOnCloseAction->setEnabled(false);
        m_togglePopupsAction->setEnabled(false);
599 600

        qGuiApp->setQuitOnLastWindowClosed(true);
601 602 603
    }
}

604 605
void JuK::slotEditKeys()
{
606
    KeyDialog(ActionCollection::actions(), this).configure();
607 608
}

609 610
void JuK::slotConfigureTagGuesser()
{
611
    TagGuesserConfigDlg(this).exec();
612 613
}

614 615
void JuK::slotConfigureFileRenamer()
{
616
    FileRenamerConfigDlg(this).exec();
617 618
}

619 620 621
void JuK::slotConfigureScrobbling()
{
    ScrobbleConfigDlg(this).exec();
622
    activateScrobblerIfEnabled();
623 624
}

625 626 627 628 629 630 631 632 633 634 635 636 637 638
void JuK::activateScrobblerIfEnabled()
{
    bool isScrobbling = Scrobbler::isScrobblingEnabled();

    if (!m_scrobbler && isScrobbling) {
        m_scrobbler = new Scrobbler(this);
        connect (m_player,    SIGNAL(signalItemChanged(FileHandle)),
                 m_scrobbler, SLOT(nowPlaying(FileHandle)));
    }
    else if (m_scrobbler && !isScrobbling) {
        delete m_scrobbler;
        m_scrobbler = 0;
    }
}
639

640 641 642 643 644
void JuK::slotUndo()
{
    TagTransactionManager::instance()->undo();
}

645 646 647 648 649 650
void JuK::slotCheckAlbumNextAction(bool albumRandomEnabled)
{
    // If album random play is enabled, then enable the Play Next Album action
    // unless we're not playing right now.

    if(albumRandomEnabled && !m_player->playing())
651
        albumRandomEnabled = false;
652 653 654 655

    action("forwardAlbum")->setEnabled(albumRandomEnabled);
}

656
// vim: set et sw=4 tw=0 sta: