juk.cpp 29.1 KB
Newer Older
1 2 3 4 5
/***************************************************************************
                          juk.cpp  -  description
                             -------------------
    begin                : Mon Feb  4 23:40:41 EST 2002
    copyright            : (C) 2002 by Scott Wheeler
6
    email                : wheeler@kde.org
7
***************************************************************************/
8 9 10 11 12 13 14 15 16 17

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

18
#include <kcmdlineargs.h>
19
#include <kstatusbar.h>
20
#include <kdebug.h>
21
#include <kmessagebox.h>
22

Frerich Raabe's avatar
Frerich Raabe committed
23
#include <qmetaobject.h>
24
#include <qslider.h>
25
#include <qmime.h>
26

27
#include "juk.h"
28
#include "slideraction.h"
29
#include "statuslabel.h"
30 31
#include "splashscreen.h"
#include "genrelisteditor.h"
32
#include "systemtray.h"
33
#include "keydialog.h"
34
#include "tagguesserconfigdlg.h"
35 36 37 38 39

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

40
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose),
41
					      DCOPObject("Player"),
42
					      m_shuttingDown(false)
43
{
44 45
    // Expect segfaults if you change this order.

46
    readSettings();
47 48 49 50 51 52

    if(m_showSplash) {
	SplashScreen::instance()->show();
	kapp->processEvents();
    }

53
    setupActions();
54 55
    setupLayout();
    setupSplitterConnections();
56
    slotPlaylistChanged();
57
    readConfig();
58
    setupPlayer();
59
    setupSystemTray();
60
    setupGlobalAccels();
61
    processArgs();
62

63
    SplashScreen::finishedLoading();
Scott Wheeler's avatar
Scott Wheeler committed
64
    QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
65 66 67 68
}

JuK::~JuK()
{
69

70 71
}

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

void JuK::setVolume(float volume)
{
    if(m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
    {
        slotSetVolume(volume / 100 * m_sliderAction->getVolumeSlider()->maxValue());
    }
}

void JuK::startPlayingPlaylist()
{
    if(m_randomPlayAction->isChecked())
        play(m_splitter->playRandomFile());
    else
        play(m_splitter->playFirstFile());
}

void JuK::play()
{
    if(!m_player)
    return;

    if(m_player->paused()) {
        m_player->play();
100
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	// Here, before doing anything, we want to make sure that the m_player did
	// in fact start.

        if(m_player->playing()) {
            actionCollection()->action("pause")->setEnabled(true);
            actionCollection()->action("stop")->setEnabled(true);
            m_playTimer->start(m_pollInterval);
	    if(m_systemTray)
		m_systemTray->slotPlay();
        }
    }
    else if(m_player->playing())
	m_player->seekPosition(0);
    else
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
}

void JuK::pause()
{
    if(!m_player)
	return;

    m_playTimer->stop();
    m_player->pause();
125
    m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
126 127 128 129 130 131 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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    actionCollection()->action("pause")->setEnabled(false);
    if(m_systemTray)
	m_systemTray->slotPause();
}

void JuK::stop()
{
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
	return;

    m_playTimer->stop();
    m_player->stop();

    actionCollection()->action("pause")->setEnabled(false);
    actionCollection()->action("stop")->setEnabled(false);
    actionCollection()->action("back")->setEnabled(false);
    actionCollection()->action("forward")->setEnabled(false);

    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);

    m_splitter->stop();

    m_statusLabel->clear();

    if(m_systemTray)
	m_systemTray->slotStop();
}

void JuK::back()
{
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
}

void JuK::back(int howMany)
{
    for(--howMany; howMany > 0; --howMany)
        m_splitter->playPreviousFile(m_randomPlayAction->isChecked());

    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
}

void JuK::slotPopulateBackMenu()
{
    m_splitter->populatePlayHistoryMenu(m_backAction->popupMenu(), m_randomPlayAction->isChecked());
}

void JuK::forward()
{
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
}

void JuK::seekBack()
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMAX(m_sliderAction->getTrackPositionSlider()->minValue(), position - 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

void JuK::seekForward()
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMIN(m_sliderAction->getTrackPositionSlider()->maxValue(), position + 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

void JuK::playPause()
{
    if(!m_player)
	return;

    if(m_player->playing())
	pause();
    else
	play();
}

void JuK::volumeUp()
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() +
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
	slotSetVolume(volume);
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

void JuK::volumeDown()
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() -
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
	slotSetVolume(volume);
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

void JuK::volumeMute()
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	if(m_muted)
	    slotSetVolume(m_sliderAction->getVolumeSlider()->value());
	else
	    slotSetVolume(0);
	    m_muted = !m_muted;
    }
}

void JuK::openFile(const QString &file)
{
    m_splitter->open(file);
}

239 240 241 242 243 244
void JuK::openFile(const QStringList &files)
{
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
	openFile(*it);
}

245 246 247 248
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

249 250
void JuK::setupLayout()
{
251
    m_splitter = new PlaylistSplitter(this, "playlistSplitter");
252
    setCentralWidget(m_splitter);
253 254

    // playlist item activation connection
255
    connect(m_splitter, SIGNAL(signalActivated()), this, SLOT(slotPlaySelectedFile()));
256
    connect(m_splitter, SIGNAL(signalListBoxDoubleClicked()), this, SLOT(startPlayingPlaylist()));
257

258
    // create status bar
259 260
    m_statusLabel = new StatusLabel(statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
261

262 263
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)), m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()), m_splitter, SLOT(slotSelectPlaying()));
264

265
    m_splitter->setFocus();
266

267
    resize(750, 500);
268 269
}

270 271
void JuK::setupActions()
{
272
    //////////////////////////////////////////////////
273
    // file menu
274
    //////////////////////////////////////////////////
275

276 277 278 279 280 281
    KActionMenu *newMenu = new KActionMenu(i18n("&New"), "", actionCollection(), "file_new");
    newMenu->insert(
        createSplitterAction(i18n("Empty Playlist..."), SLOT(slotCreatePlaylist()), 0, 0, 0));
    newMenu->insert(
        createSplitterAction(i18n("Playlist From Directory..."), SLOT(slotCreatePlaylistFromDir()), 0, 0, 0));

Scott Wheeler's avatar
Scott Wheeler committed
282
    createSplitterAction(i18n("Open..."),            SLOT(slotOpen()),              "file_open",          "fileopen", "CTRL+o");
283 284 285
    createSplitterAction(i18n("Open &Directory..."), SLOT(slotOpenDirectory()),     "openDirectory",      "fileopen");
    createSplitterAction(i18n("&Rename..."),         SLOT(slotRenamePlaylist()),    "renamePlaylist");
    createSplitterAction(i18n("D&uplicate..."),      SLOT(slotDuplicatePlaylist()), "duplicatePlaylist");
Scott Wheeler's avatar
Scott Wheeler committed
286
    createSplitterAction(i18n("Save"),               SLOT(slotSavePlaylist()),      "file_save",          "filesave", "CTRL+s");
287 288
    createSplitterAction(i18n("Save As..."),         SLOT(slotSaveAsPlaylist()),    "file_save_as",       "filesaveas");
    createSplitterAction(i18n("R&emove"),            SLOT(slotDeletePlaylist()),    "deleteItemPlaylist", "edittrash");
289

290
    KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
291

292
    //////////////////////////////////////////////////
293
    // edit menu
294 295 296 297
    //////////////////////////////////////////////////

    KStdAction::cut(this,   SLOT(cut()),   actionCollection());
    KStdAction::copy(this,  SLOT(copy()),  actionCollection());
298
    KStdAction::paste(this, SLOT(paste()), actionCollection());
299

300
    new KAction(i18n("C&lear"), "editclear", 0, this, SLOT(clear()), actionCollection(), "clear");
301

302
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
303

304
    //////////////////////////////////////////////////
305
    // view menu
306
    //////////////////////////////////////////////////
307

308 309
    m_showSearchAction = new KToggleAction(i18n("Show &Search Bar"), "filefind", 0, actionCollection(), "showSearch");
    m_showEditorAction = new KToggleAction(i18n("Show &Tag Editor"), "edit",     0, actionCollection(), "showEditor");
310

311
    createSplitterAction(i18n("Refresh Items"), SLOT(slotRefresh()), "refresh", "reload");
312

313
    //////////////////////////////////////////////////
314
    // play menu
315 316
    //////////////////////////////////////////////////

317
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0, actionCollection(), "randomPlay");
318 319 320 321 322

    new KAction(i18n("&Play"),  "player_play",  0, this, SLOT(play()),  actionCollection(), "play");
    new KAction(i18n("P&ause"), "player_pause", 0, this, SLOT(pause()), actionCollection(), "pause");
    new KAction(i18n("&Stop"),  "player_stop",  0, this, SLOT(stop()),  actionCollection(), "stop");

323
    m_backAction = new KToolBarPopupAction(i18n("Skip &Back"), "player_start", 0, this, SLOT(back()), actionCollection(), "back");
324
    connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()),  this, SLOT(slotPopulateBackMenu()));
325
    connect(m_backAction->popupMenu(), SIGNAL(activated(int)), this, SLOT(back(int)));
326 327 328

    new KAction(i18n("Skip &Forward"), "player_end", 0, this, SLOT(forward()), actionCollection(), "forward");

329
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), 0, 0, actionCollection(), "loopPlaylist");
330

331
    //////////////////////////////////////////////////
332
    // tagger menu
333 334 335 336
    //////////////////////////////////////////////////

    createSplitterAction(i18n("&Save"),   SLOT(slotSaveTag()),             "saveItem",   "filesave", "CTRL+t");
    createSplitterAction(i18n("&Delete"), SLOT(slotDeleteSelectedItems()), "removeItem", "editdelete");
337 338

    KActionMenu *guessMenu = new KActionMenu(i18n("&Guess Tag Information"), "", actionCollection(), "guessTag");
339

340 341 342 343 344 345 346 347
    guessMenu->insert(
        createSplitterAction(i18n("From &Filename"), SLOT(slotGuessTagInfoFile()),     "guessTagFile",     0, "CTRL+f"));
    guessMenu->insert(
        createSplitterAction(i18n("From &Internet"), SLOT(slotGuessTagInfoInternet()), "guessTagInternet", 0, "CTRL+i"));

    // new KAction(i18n("&Rename File"), 0, "CTRL+r", m_splitter, SLOT(slotRenameFile()), actionCollection(), "renameFile"); // 4

    //////////////////////////////////////////////////
348
    // settings menu
349 350
    //////////////////////////////////////////////////

351
    new KToggleAction(i18n("Show Menu Bar"), "CTRL+m", this, SLOT(slotToggleMenuBar()), actionCollection(), "toggleMenuBar");
352

353
    setStandardToolBarMenuEnabled(true);
354

355 356 357 358
    m_toggleSplashAction      = new KToggleAction(i18n("Show Splash Screen on Startup"), 0, actionCollection(), "showSplashScreen");
    m_toggleSystemTrayAction  = new KToggleAction(i18n("&Dock in System Tray"),          0, actionCollection(), "toggleSystemTray");
    m_toggleDockOnCloseAction = new KToggleAction(i18n("&Stay in System Tray on Close"), 0, actionCollection(), "dockOnClose");
    m_togglePopupsAction      = new KToggleAction(i18n("&Popup Track Announcement"),     0, this, 0, actionCollection(), "togglePopups");
359

360
    connect(m_toggleSystemTrayAction, SIGNAL(toggled(bool)), this, SLOT(slotToggleSystemTray(bool)));
361

362

363
    new KAction(i18n("Genre List Editor..."), 0, this, SLOT(slotShowGenreListEditor()), actionCollection(), "showGenreListEditor");
364

365
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
366

367
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
368 369
        m_outputSelectAction->setCurrentItem(0);
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
370
    }
371

372
    new KAction(i18n("&Tag Guesser..."), 0, 0, this, SLOT(slotConfigureTagGuesser()), actionCollection(), "tagGuesserConfig");
373

374 375
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

376
    //////////////////////////////////////////////////
377
    // just in the toolbar
378 379
    //////////////////////////////////////////////////

380
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");
381 382

    createGUI();
383 384

    // set the slider to the proper orientation and make it stay that way
385
    m_sliderAction->slotUpdateOrientation();
386 387
}

388 389 390 391 392 393 394 395 396
void JuK::setupSplitterConnections()
{
    QValueListConstIterator<SplitterConnection> it = m_splitterConnections.begin();
    for(; it != m_splitterConnections.end(); ++it)
        connect((*it).first, SIGNAL(activated()), m_splitter, (*it).second);

    connect(m_showSearchAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetSearchVisible(bool)));
    connect(m_showEditorAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetEditorVisible(bool)));
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), m_sliderAction, SLOT(slotUpdateOrientation(QDockWindow *)));
397
    connect(m_splitter, SIGNAL(signalPlaylistChanged()), this, SLOT(slotPlaylistChanged()));
398 399
}

400
void JuK::setupSystemTray()
401
{
402
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
Frerich Raabe's avatar
Frerich Raabe committed
403 404
        m_systemTray = new SystemTray(this, "systemTray");
        m_systemTray->show();
405

Frerich Raabe's avatar
Frerich Raabe committed
406
        connect(this, SIGNAL(signalNewSong(const QString&)), m_systemTray, SLOT(slotNewSong(const QString&)));
407

Frerich Raabe's avatar
Frerich Raabe committed
408 409 410 411
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
412

Frerich Raabe's avatar
Frerich Raabe committed
413
        m_toggleDockOnCloseAction->setEnabled(true);
414

Frerich Raabe's avatar
Frerich Raabe committed
415
        connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
416
    }
417
    else {
Frerich Raabe's avatar
Frerich Raabe committed
418 419
        m_systemTray = 0;
        m_toggleDockOnCloseAction->setEnabled(false);
420
    }
421 422
}

423 424
void JuK::setupPlayer()
{
425 426
    m_trackPositionDragging = false;
    m_noSeek = false;
Scott Wheeler's avatar
Scott Wheeler committed
427
    m_muted = false;
428 429 430 431
    actionCollection()->action("pause")->setEnabled(false);
    actionCollection()->action("stop")->setEnabled(false);
    actionCollection()->action("back")->setEnabled(false);
    actionCollection()->action("forward")->setEnabled(false);
432

433
    m_playTimer = new QTimer(this);
434
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
435

436
    if(m_sliderAction && m_sliderAction->getTrackPositionSlider() && m_sliderAction->getVolumeSlider()) {
437 438 439
        connect(m_sliderAction->getTrackPositionSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotTrackPositionSliderUpdate(int)));
        connect(m_sliderAction->getTrackPositionSlider(), SIGNAL(sliderPressed()), this, SLOT(slotTrackPositionSliderClicked()));
        connect(m_sliderAction->getTrackPositionSlider(), SIGNAL(sliderReleased()), this, SLOT(slotTrackPositionSliderReleased()));
440
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
441

442
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
443
    }
444

445
    int playerType = 0;
446
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
447 448
        playerType = m_outputSelectAction->currentItem();
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
449 450
    }

451
    m_player = Player::createPlayer(playerType);
452 453
}

454

455 456 457
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
458 459 460 461 462 463 464 465 466
    KeyDialog::insert(m_accel, "PlayPause",   i18n("Play/Pause"),   this, SLOT(playPause()));
    KeyDialog::insert(m_accel, "Stop",        i18n("Stop Playing"), this, SLOT(stop()));
    KeyDialog::insert(m_accel, "Back",        i18n("Back"),         this, SLOT(back()));
    KeyDialog::insert(m_accel, "Forward",     i18n("Forward"),      this, SLOT(forward()));
    KeyDialog::insert(m_accel, "SeekBack",    i18n("Seek Back"),    this, SLOT(seekBack()));
    KeyDialog::insert(m_accel, "SeekForward", i18n("Seek Forward"), this, SLOT(seekForward()));
    KeyDialog::insert(m_accel, "VolumeUp",    i18n("Volume Up"),    this, SLOT(volumeUp()));
    KeyDialog::insert(m_accel, "VolumeDown",  i18n("Volume Down"),  this, SLOT(volumeDown()));
    KeyDialog::insert(m_accel, "Mute",        i18n("Mute"),         this, SLOT(volumeMute()));
467

468 469 470 471 472
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

473 474 475 476
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
477

478
    for(int i = 0; i < args->count(); i++)
Frerich Raabe's avatar
Frerich Raabe committed
479
        files.append(args->arg(i));
480

481
    m_splitter->open(files);
482 483
}

484 485 486
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
Frerich Raabe's avatar
Frerich Raabe committed
487
        e->accept();
488 489 490
    KMainWindow::keyPressEvent(e);
}

491 492 493 494 495 496 497 498 499
/**
 * These are settings that need to be know before setting up the GUI.
 */

void JuK::readSettings()
{
    KConfig *config = KGlobal::config();
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
Frerich Raabe's avatar
Frerich Raabe committed
500
        m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
501 502 503
    }
}

504 505
void JuK::readConfig()
{
506
    // Automagically save and m_restore many window settings.
507 508
    setAutoSaveSettings();

509
    KConfig *config = KGlobal::config();
510
    { // player settings
511
        KConfigGroupSaver saver(config, "Player");
512
        if(m_sliderAction->getVolumeSlider()) {
513 514
            int volume = config->readNumEntry("Volume", m_sliderAction->getVolumeSlider()->maxValue());
            m_sliderAction->getVolumeSlider()->setValue(volume);
515
        }
Frerich Raabe's avatar
Frerich Raabe committed
516 517
        bool randomPlay = config->readBoolEntry("RandomPlay", false);
        m_randomPlayAction->setChecked(randomPlay);
518

Frerich Raabe's avatar
Frerich Raabe committed
519 520
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
        m_loopPlaylistAction->setChecked(loopPlaylist);
521
    }
522
    { // view settings
523
        KConfigGroupSaver saver(config, "View");
524 525 526 527 528

        bool showSearch = config->readBoolEntry("ShowSearch", true);
        m_showSearchAction->setChecked(showSearch);
        m_splitter->slotSetSearchVisible(showSearch);

Frerich Raabe's avatar
Frerich Raabe committed
529 530 531
        bool showEditor = config->readBoolEntry("ShowEditor", false);
        m_showEditorAction->setChecked(showEditor);
        m_splitter->slotSetEditorVisible(showEditor);
532
    }
533 534
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
535

Frerich Raabe's avatar
Frerich Raabe committed
536 537
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
538

Frerich Raabe's avatar
Frerich Raabe committed
539 540
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
541

Frerich Raabe's avatar
Frerich Raabe committed
542 543
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
544

Frerich Raabe's avatar
Frerich Raabe committed
545 546
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
547
    }
548

549
    m_toggleSplashAction->setChecked(m_showSplash);
550 551 552 553
}

void JuK::saveConfig()
{
554
    KConfig *config = KGlobal::config();
555
    { // m_player settings
556
        KConfigGroupSaver saver(config, "Player");
557 558
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
Frerich Raabe's avatar
Frerich Raabe committed
559 560 561 562
        if(m_randomPlayAction)
            config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
        if(m_loopPlaylistAction)
            config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
563
    }
564 565
    { // view settings
        KConfigGroupSaver saver(config, "View");
566

Frerich Raabe's avatar
Frerich Raabe committed
567
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
568
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
569
    }
570 571
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
Frerich Raabe's avatar
Frerich Raabe committed
572 573 574 575 576 577
        config->writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
        config->writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
        config->writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
        config->writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
        if(m_outputSelectAction)
            config->writeEntry("MediaSystem", m_outputSelectAction->currentItem());
578
    }
579
    config->sync();
580 581
}

582
bool JuK::queryExit()
583
{
584
    stop();
585
    delete m_player;
586
    Cache::instance()->save();
587
    saveConfig();
588
    delete m_splitter;
589
    return true;
590 591
}

592 593
bool JuK::queryClose()
{
594
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
595 596
	KMessageBox::information(this,
				 i18n("<qt>Closing the main window will keep JuK running in the system tray. "
597
				      "Use Quit from the File menu to quit the application.</qt>"),
598 599 600 601 602 603 604 605
				 i18n("Docking in System Tray"), "hideOnCloseInfo");
	hide();
	return false;
    }
    else
	return true;
}

606
void JuK::invokeEditSlot(const char *slotName, const char *slot)
607 608
{
    QObject *object = focusWidget();
609

610
    if(!object || !slotName || !slot)
Frerich Raabe's avatar
Frerich Raabe committed
611
        return;
612

613 614
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
615

616
    if(l.find(slotName) == -1)
Frerich Raabe's avatar
Frerich Raabe committed
617
        return;
618

619 620 621
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
622 623
}

624 625 626
QString JuK::playingString() const
{
    QString s;
627 628
    if(!m_player->playing() && !m_player->paused())
	return i18n("No song playing");
629

630
    if(m_splitter->playingArtist().isEmpty())
Frerich Raabe's avatar
Frerich Raabe committed
631
        s = m_splitter->playingTrack().simplifyWhiteSpace();
632
    else
Frerich Raabe's avatar
Frerich Raabe committed
633
        s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
634 635 636 637

    return s;
}

638 639
void JuK::updatePlaylistInfo()
{
Frerich Raabe's avatar
Frerich Raabe committed
640
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(), m_splitter->selectedPlaylistCount());
641 642 643 644
}

void JuK::play(const QString &file)
{
645
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
Frerich Raabe's avatar
Frerich Raabe committed
646
        return;
647 648 649 650

    float volume = float(m_sliderAction->getVolumeSlider()->value()) / float(m_sliderAction->getVolumeSlider()->maxValue());

    if(m_player->paused())
Frerich Raabe's avatar
Frerich Raabe committed
651
        m_player->stop();
652

653 654 655 656 657
    m_player->play(file, volume);

    // Make sure that the m_player actually starts before doing anything.

    if(m_player->playing()) {
658 659 660
        actionCollection()->action("pause")->setEnabled(true);
        actionCollection()->action("stop")->setEnabled(true);
        actionCollection()->action("forward")->setEnabled(true);
661

Frerich Raabe's avatar
Frerich Raabe committed
662
        m_backAction->setEnabled(true);
663

Frerich Raabe's avatar
Frerich Raabe committed
664 665 666
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
667

Frerich Raabe's avatar
Frerich Raabe committed
668
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
669

Frerich Raabe's avatar
Frerich Raabe committed
670
        emit signalNewSong(playingString());
671

Frerich Raabe's avatar
Frerich Raabe committed
672 673
        if(m_systemTray)
            m_systemTray->slotPlay();
674 675
    }
    else
Frerich Raabe's avatar
Frerich Raabe committed
676
        stop();
677 678
}

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
KAction *JuK::createSplitterAction(const QString &text, const char *slot, const char *name, 
				   const QString &pix, const KShortcut &shortcut)
{
    KAction *action;

    if(pix.isNull())
	action = new KAction(text, shortcut, actionCollection(), name);
    else
	action = new KAction(text, pix, shortcut, actionCollection(), name);

    m_splitterConnections.append(SplitterConnection(action, slot));
    
    return action;
}

694 695 696 697
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

698
void JuK::slotPlaylistChanged()
699
{
700
    if(m_splitter->collectionListSelected() || !m_splitter->hasListSelected()) {
701 702 703 704
        actionCollection()->action("file_save")->setEnabled(false);
        actionCollection()->action("file_save_as")->setEnabled(false);
        actionCollection()->action("renamePlaylist")->setEnabled(false);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(false);
705 706
    }
    else {
707 708 709 710
        actionCollection()->action("file_save")->setEnabled(true);
        actionCollection()->action("file_save_as")->setEnabled(true);
        actionCollection()->action("renamePlaylist")->setEnabled(true);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(true);
711
    }
712 713 714 715 716
    if(m_splitter->hasListSelected())
        actionCollection()->action("duplicatePlaylist")->setEnabled(true);
    else
        actionCollection()->action("duplicatePlaylist")->setEnabled(false);
    
717 718 719 720

    updatePlaylistInfo();
}

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
////////////////////////////////////////////////////////////////////////////////
// edit menu
////////////////////////////////////////////////////////////////////////////////

void JuK::cut()
{
    invokeEditSlot("cut()", SLOT(cut()));
}

void JuK::copy()
{
    invokeEditSlot("copy()", SLOT(copy()));
}

void JuK::paste()
{
    invokeEditSlot("paste()", SLOT(paste()));
}

void JuK::clear()
{
    invokeEditSlot("clear()", SLOT(clear()));
}

void JuK::selectAll()
{
    invokeEditSlot("selectAll()", SLOT(selectAll()));
}

750 751 752 753
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

754
void JuK::slotShowGenreListEditor()
755 756 757 758
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
759

760
void JuK::slotToggleSystemTray(bool enabled)
761
{
762
    if(enabled && !m_systemTray)
763
	setupSystemTray();
764 765 766
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
767
	m_toggleDockOnCloseAction->setEnabled(false);
768 769 770
    }
}

771
void JuK::slotSetOutput(int output)
772
{
773
    stop();
774 775
    delete m_player;
    m_player = Player::createPlayer(output);
776 777
}

778 779 780 781 782
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

783
////////////////////////////////////////////////////////////////////////////////
784
// additional player slots
785 786
////////////////////////////////////////////////////////////////////////////////

787
void JuK::slotTrackPositionSliderClicked()
788
{
789
    m_trackPositionDragging = true;
790 791
}

792
void JuK::slotTrackPositionSliderReleased()
793
{
794
    if(!m_player)
795 796
	return;

797 798
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
799 800
}

801
void JuK::slotTrackPositionSliderUpdate(int position)
802
{
803
    if(!m_player)
804 805
	return;

806 807
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
808 809 810 811 812 813 814 815 816 817

    // The dragging flag is set, so just update the status label, rather than seeking
    if(m_player->playing() && m_trackPositionDragging && !m_noSeek) {
	// position from 0 to 1
	float positionFraction = float(position) / m_sliderAction->getTrackPositionSlider()->maxValue();
	float totalTime = float(m_player->totalTime());
	long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

	m_statusLabel->setItemCurrentTime(seekTime);
    }
818 819
}

820 821
// This method is called when the play timer has expired.

822
void JuK::slotPollPlay()
823
{
824
    if(!m_player)
825 826
	return;

827
    // Our locking mechanism.  Since this method adjusts the play slider, we
828
    // want to make sure that our adjustments
829
    m_noSeek = true;
830

831
    if(!m_player->playing()) {
832

833
        m_playTimer->stop();
834

835
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
836
    }
837 838 839 840
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
841 842 843
    }

    // Ok, this is weird stuff, but it works pretty well.  Ordinarily we don't
844
    // need to check up on our playing time very often, but in the span of the
845 846
    // last interval, we want to check a lot -- to figure out that we've hit the
    // end of the song as soon as possible.
847

848
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
849
        m_playTimer->changeInterval(50);
850

851
    m_noSeek = false;
852 853
}

854
void JuK::slotSetVolume(int volume)
855
{
856 857 858
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
859
    {
860
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
861 862
    }
}
863

864 865 866 867 868 869
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

870
#include "juk.moc"