juk.cpp 29.6 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 19 20 21 22 23 24 25 26 27
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kstatusbar.h>
#include <kdebug.h>
#include <kmessagebox.h>

#include <qmetaobject.h>
#include <qslider.h>
#include <qmime.h>

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

37 38 39 40
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
41 42 43 44
JuK::JuK(QWidget *parent, const char *name) :
    DCOPObject("Player"),
    KMainWindow(parent, name, WDestructiveClose),
    m_shuttingDown(false)
45
{
46 47
    // Expect segfaults if you change this order.

48
    readSettings();
49 50 51 52 53 54

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

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

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

JuK::~JuK()
{
71

72 73
}

74 75 76 77 78 79 80 81 82
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

void JuK::setVolume(float volume)
{
    if(m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
    {
Frerich Raabe's avatar
Frerich Raabe committed
83
        slotSetVolume(int(volume / 100) * m_sliderAction->getVolumeSlider()->maxValue());
84 85 86 87 88 89 90 91 92 93 94
    }
}

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

95 96 97 98 99 100
void JuK::slotGuessTagInfo(int i)
{
    int index = m_guessMenu->popupMenu()->indexOf(i);
    m_splitter->slotGuessTagInfo(TagGuesser::Type(index));
}

101 102 103
void JuK::play()
{
    if(!m_player)
Scott Wheeler's avatar
Scott Wheeler committed
104
	return;
105 106 107

    if(m_player->paused()) {
        m_player->play();
108
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
Scott Wheeler's avatar
Scott Wheeler committed
109

110 111 112
	// Here, before doing anything, we want to make sure that the m_player did
	// in fact start.

Scott Wheeler's avatar
Scott Wheeler committed
113 114 115 116
	if(m_player->playing()) {
	    actionCollection()->action("pause")->setEnabled(true);
	    actionCollection()->action("stop")->setEnabled(true);
	    m_playTimer->start(m_pollInterval);
117 118
	    if(m_systemTray)
		m_systemTray->slotPlay();
Scott Wheeler's avatar
Scott Wheeler committed
119
	}
120 121 122 123
    }
    else if(m_player->playing())
	m_player->seekPosition(0);
    else
Scott Wheeler's avatar
Scott Wheeler committed
124 125
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				      m_loopPlaylistAction->isChecked()));
126 127 128 129 130 131 132 133 134
}

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

    m_playTimer->stop();
    m_player->pause();
135
    m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
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
    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()
{
Scott Wheeler's avatar
Scott Wheeler committed
180 181
    m_splitter->populatePlayHistoryMenu(m_backAction->popupMenu(),
					m_randomPlayAction->isChecked());
182 183 184 185
}

void JuK::forward()
{
Scott Wheeler's avatar
Scott Wheeler committed
186 187
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				  m_loopPlaylistAction->isChecked()));
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
}

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() +
Scott Wheeler's avatar
Scott Wheeler committed
219
	    m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
220 221 222 223 224 225 226 227 228
	slotSetVolume(volume);
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

void JuK::volumeDown()
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() -
Scott Wheeler's avatar
Scott Wheeler committed
229
	    m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
	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);
}

251 252 253 254 255 256
void JuK::openFile(const QStringList &files)
{
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
	openFile(*it);
}

257 258 259 260
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

261 262
void JuK::setupLayout()
{
263
    m_splitter = new PlaylistSplitter(this, "playlistSplitter");
264
    setCentralWidget(m_splitter);
265 266

    // playlist item activation connection
Scott Wheeler's avatar
Scott Wheeler committed
267 268 269 270
    connect(m_splitter, SIGNAL(signalActivated()),
	    this, SLOT(slotPlaySelectedFile()));
    connect(m_splitter, SIGNAL(signalListBoxDoubleClicked()),
	    this, SLOT(startPlayingPlaylist()));
271

272
    // create status bar
273 274
    m_statusLabel = new StatusLabel(statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
275

Scott Wheeler's avatar
Scott Wheeler committed
276 277 278 279
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)),
	    m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()),
	    m_splitter, SLOT(slotSelectPlaying()));
280

281
    m_splitter->setFocus();
282

283
    resize(750, 500);
284 285
}

286 287
void JuK::setupActions()
{
288
    //////////////////////////////////////////////////
289
    // file menu
290
    //////////////////////////////////////////////////
291

Scott Wheeler's avatar
Scott Wheeler committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
    KActionMenu *newMenu = new KActionMenu(i18n("&New"), "filenew",
					   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));

    createSplitterAction(
	i18n("Open..."), SLOT(slotOpen()), "file_open", "fileopen", "CTRL+o");
    createSplitterAction(
	i18n("Open &Directory..."), SLOT(slotOpenDirectory()), "openDirectory", "fileopen");
    createSplitterAction(
	i18n("&Rename..."), SLOT(slotRenamePlaylist()), "renamePlaylist");
    createSplitterAction(
	i18n("D&uplicate..."), SLOT(slotDuplicatePlaylist()), "duplicatePlaylist");
    createSplitterAction(
	i18n("Save"), SLOT(slotSavePlaylist()), "file_save", "filesave", "CTRL+s");
    createSplitterAction(
	i18n("Save As..."), SLOT(slotSaveAsPlaylist()), "file_save_as", "filesaveas");
    createSplitterAction(
	i18n("R&emove"), SLOT(slotDeletePlaylist()), "deleteItemPlaylist", "edittrash");
    createSplitterAction(
	i18n("R&emove"), SLOT(slotDeletePlaylist()), "deleteItemPlaylist", "edittrash");
    createSplitterAction(
	i18n("Reload"), SLOT(slotReloadPlaylist()), "reloadPlaylist", "reload");
319

320
    KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
321

322
    //////////////////////////////////////////////////
323
    // edit menu
324 325
    //////////////////////////////////////////////////

326 327 328 329
    KStdAction::cut(kapp,   SLOT(cut()),   actionCollection());
    KStdAction::copy(kapp,  SLOT(copy()),  actionCollection());
    KStdAction::paste(kapp, SLOT(paste()), actionCollection());
    KStdAction::clear(kapp, SLOT(clear()), actionCollection());
330

331
    KStdAction::selectAll(kapp, SLOT(selectAll()), actionCollection());
332

333 334 335
    createSplitterAction(
	i18n("Advanced Search"), SLOT(slotAdvancedSearch()), "advancedSearch", "find");

336
    //////////////////////////////////////////////////
337
    // view menu
338
    //////////////////////////////////////////////////
339

Scott Wheeler's avatar
Scott Wheeler committed
340 341 342 343
    m_showSearchAction = new KToggleAction(i18n("Show &Search Bar"), "filefind",
					   0, actionCollection(), "showSearch");
    m_showEditorAction = new KToggleAction(i18n("Show &Tag Editor"), "edit",
					   0, actionCollection(), "showEditor");
344
    m_showHistoryAction = new KToggleAction(i18n("Show &History"), "history",
345
					   0, actionCollection(), "showHistory");
346

347
    createSplitterAction(i18n("Refresh Items"), SLOT(slotRefresh()), "refresh", "reload");
348

349
    //////////////////////////////////////////////////
350
    // play menu
351 352
    //////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0,
					   actionCollection(), "randomPlay");

    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");

    m_backAction = new KToolBarPopupAction(i18n("Skip &Back"), "player_start", 0,
					   this, SLOT(back()), actionCollection(), "back");
367

Scott Wheeler's avatar
Scott Wheeler committed
368 369
    connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()),
	    this, SLOT(slotPopulateBackMenu()));
370

Scott Wheeler's avatar
Scott Wheeler committed
371 372
    connect(m_backAction->popupMenu(), SIGNAL(activated(int)),
	    this, SLOT(back(int)));
373

Scott Wheeler's avatar
Scott Wheeler committed
374 375
    new KAction(i18n("Skip &Forward"), "player_end", 0, this, SLOT(forward()),
		actionCollection(), "forward");
376

Scott Wheeler's avatar
Scott Wheeler committed
377 378
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), 0, 0,
					     actionCollection(), "loopPlaylist");
379

380
    //////////////////////////////////////////////////
381
    // tagger menu
382 383
    //////////////////////////////////////////////////

384
    createSplitterAction(i18n("&Save"), SLOT(slotSaveTag()),
Scott Wheeler's avatar
Scott Wheeler committed
385 386 387
			 "saveItem",   "filesave", "CTRL+t");
    createSplitterAction(i18n("&Delete"), SLOT(slotDeleteSelectedItems()),
			 "removeItem", "editdelete");
388

389
    m_guessMenu = new KActionMenu(i18n("&Guess Tag Information"),
Scott Wheeler's avatar
Scott Wheeler committed
390 391
					     QString::null, actionCollection(),
					     "guessTag");
392

Scott Wheeler's avatar
Scott Wheeler committed
393
    KAction *a;
394

395 396 397 398 399
    a = new KAction(i18n("From &Filename"), "CTRL+f", actionCollection(), "guessTagFile");
    m_guessMenu->insert(a);

    a = new KAction(i18n("From &Internet"), "CTRL+i", actionCollection(), "guessTagInternet");
    m_guessMenu->insert(a);
Scott Wheeler's avatar
Scott Wheeler committed
400

401
    connect(m_guessMenu->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotGuessTagInfo(int)));
Scott Wheeler's avatar
Scott Wheeler committed
402 403 404

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

    //////////////////////////////////////////////////
407
    // settings menu
408 409
    //////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
410 411
    new KToggleAction(i18n("Show Menu Bar"), "CTRL+m", this,
		      SLOT(slotToggleMenuBar()), actionCollection(), "toggleMenuBar");
412

413
    setStandardToolBarMenuEnabled(true);
414

415
    m_toggleSplashAction = new KToggleAction(i18n("Show Splash Screen on Startp"),
Scott Wheeler's avatar
Scott Wheeler committed
416 417 418 419 420 421 422
					     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");
423

Scott Wheeler's avatar
Scott Wheeler committed
424 425
    m_togglePopupsAction = new KToggleAction(i18n("&Popup Track Announcement"),
					     0, this, 0, actionCollection(), "togglePopups");
426

Scott Wheeler's avatar
Scott Wheeler committed
427 428
    connect(m_toggleSystemTrayAction, SIGNAL(toggled(bool)),
	    this, SLOT(slotToggleSystemTray(bool)));
429

Scott Wheeler's avatar
Scott Wheeler committed
430 431 432

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

434
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
435

436
    if(m_outputSelectAction) {
437 438
        m_outputSelectAction->setCurrentItem(0);
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
439
    }
440

Scott Wheeler's avatar
Scott Wheeler committed
441 442
    new KAction(i18n("&Tag Guesser..."), 0, 0, this, SLOT(slotConfigureTagGuesser()),
		actionCollection(), "tagGuesserConfig");
443

444 445
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

446
    //////////////////////////////////////////////////
447
    // just in the toolbar
448 449
    //////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
450 451
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(),
				      "trackPositionAction");
452 453

    createGUI();
454 455

    // set the slider to the proper orientation and make it stay that way
456
    m_sliderAction->slotUpdateOrientation();
457 458
}

459 460 461 462 463 464
void JuK::setupSplitterConnections()
{
    QValueListConstIterator<SplitterConnection> it = m_splitterConnections.begin();
    for(; it != m_splitterConnections.end(); ++it)
        connect((*it).first, SIGNAL(activated()), m_splitter, (*it).second);

Scott Wheeler's avatar
Scott Wheeler committed
465 466 467 468
    connect(m_showSearchAction, SIGNAL(toggled(bool)),
	    m_splitter, SLOT(slotSetSearchVisible(bool)));
    connect(m_showEditorAction, SIGNAL(toggled(bool)),
	    m_splitter, SLOT(slotSetEditorVisible(bool)));
469 470
    connect(m_showHistoryAction, SIGNAL(toggled(bool)),
	    m_splitter, SLOT(slotSetHistoryVisible(bool)));
Scott Wheeler's avatar
Scott Wheeler committed
471 472 473 474
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), 
	    m_sliderAction, SLOT(slotUpdateOrientation(QDockWindow *)));
    connect(m_splitter, SIGNAL(signalPlaylistChanged()),
	    this, SLOT(slotPlaylistChanged()));
475 476
}

477
void JuK::setupSystemTray()
478
{
479
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
480 481
        m_systemTray = new SystemTray(this, "systemTray");
        m_systemTray->show();
482

Scott Wheeler's avatar
Scott Wheeler committed
483 484
        connect(this, SIGNAL(signalNewSong(const QString&)), 
		m_systemTray, SLOT(slotNewSong(const QString&)));
485

486 487 488 489
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
490

491
        m_toggleDockOnCloseAction->setEnabled(true);
492

493
        connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
494
    }
495
    else {
496 497
        m_systemTray = 0;
        m_toggleDockOnCloseAction->setEnabled(false);
498
    }
499 500
}

501 502
void JuK::setupPlayer()
{
503 504
    m_trackPositionDragging = false;
    m_noSeek = false;
Scott Wheeler's avatar
Scott Wheeler committed
505
    m_muted = false;
506 507 508 509
    actionCollection()->action("pause")->setEnabled(false);
    actionCollection()->action("stop")->setEnabled(false);
    actionCollection()->action("back")->setEnabled(false);
    actionCollection()->action("forward")->setEnabled(false);
510

511
    m_playTimer = new QTimer(this);
512
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
513

Scott Wheeler's avatar
Scott Wheeler committed
514 515 516 517 518 519 520 521 522 523
    if(m_sliderAction &&
       m_sliderAction->getTrackPositionSlider() &&
       m_sliderAction->getVolumeSlider())
    {
        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()));
524
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
525

Scott Wheeler's avatar
Scott Wheeler committed
526 527
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)),
		this, SLOT(slotSetVolume(int)));
528
    }
529

530
    int playerType = 0;
531
    if(m_outputSelectAction) {
532 533
        playerType = m_outputSelectAction->currentItem();
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
534 535
    }

536
    m_player = Player::createPlayer(playerType);
537 538
}

539

540 541 542
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
543 544 545 546 547 548 549 550 551
    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()));
552

553 554 555 556 557
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

558 559 560 561
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
562

563
    for(int i = 0; i < args->count(); i++)
564
        files.append(args->arg(i));
565

566
    m_splitter->open(files);
567 568
}

569 570 571
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
572
        e->accept();
573 574 575
    KMainWindow::keyPressEvent(e);
}

576 577 578 579 580 581 582 583 584
/**
 * 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");
585
        m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
586 587 588
    }
}

589 590
void JuK::readConfig()
{
591
    // Automagically save and m_restore many window settings.
592 593
    setAutoSaveSettings();

594
    KConfig *config = KGlobal::config();
595
    { // player settings
596
        KConfigGroupSaver saver(config, "Player");
597
        if(m_sliderAction->getVolumeSlider()) {
Scott Wheeler's avatar
Scott Wheeler committed
598 599
	    int maxVolume = m_sliderAction->getVolumeSlider()->maxValue();
	    int volume = config->readNumEntry("Volume", maxVolume);
600
            m_sliderAction->getVolumeSlider()->setValue(volume);
601
        }
602 603
        bool randomPlay = config->readBoolEntry("RandomPlay", false);
        m_randomPlayAction->setChecked(randomPlay);
604

605 606
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
        m_loopPlaylistAction->setChecked(loopPlaylist);
607
    }
608
    { // view settings
609
        KConfigGroupSaver saver(config, "View");
610 611 612 613 614

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

615 616 617
        bool showEditor = config->readBoolEntry("ShowEditor", false);
        m_showEditorAction->setChecked(showEditor);
        m_splitter->slotSetEditorVisible(showEditor);
618 619 620 621

        bool showHistory = config->readBoolEntry("ShowHistory", false);
        m_showHistoryAction->setChecked(showHistory);
        m_splitter->slotSetHistoryVisible(showHistory);
622
    }
623 624
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
625

626 627
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
628

629 630
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
631

632 633
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
634

635 636
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
637
    }
638

639
    m_toggleSplashAction->setChecked(m_showSplash);
640 641 642 643
}

void JuK::saveConfig()
{
644
    KConfig *config = KGlobal::config();
645
    { // m_player settings
646
        KConfigGroupSaver saver(config, "Player");
647 648
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
649 650 651 652
        if(m_randomPlayAction)
            config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
        if(m_loopPlaylistAction)
            config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
653
    }
654 655
    { // view settings
        KConfigGroupSaver saver(config, "View");
656

657
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
658
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
659
        config->writeEntry("ShowHistory", m_showHistoryAction->isChecked());
660
    }
661 662
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
663 664 665 666 667 668
        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());
669
    }
670
    config->sync();
671 672
}

673
bool JuK::queryExit()
674
{
675
    stop();
676
    delete m_player;
677
    Cache::instance()->save();
678
    saveConfig();
679
    delete m_splitter;
680
    return true;
681 682
}

683 684
bool JuK::queryClose()
{
685
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
686
	KMessageBox::information(this,
Scott Wheeler's avatar
Scott Wheeler committed
687 688 689
	    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");
690 691 692 693 694 695 696
	hide();
	return false;
    }
    else
	return true;
}

697 698 699
QString JuK::playingString() const
{
    QString s;
700 701
    if(!m_player->playing() && !m_player->paused())
	return i18n("No song playing");
702

703 704 705 706
    if(!m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - ";

    s += m_splitter->playingTrack().simplifyWhiteSpace();
707 708 709 710

    return s;
}

711 712
void JuK::updatePlaylistInfo()
{
Scott Wheeler's avatar
Scott Wheeler committed
713 714
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(),
				   m_splitter->selectedPlaylistCount());
715 716 717 718
}

void JuK::play(const QString &file)
{
719
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
720
        return;
721

Scott Wheeler's avatar
Scott Wheeler committed
722 723
    float volume = float(m_sliderAction->getVolumeSlider()->value()) /
	float(m_sliderAction->getVolumeSlider()->maxValue());
724 725

    if(m_player->paused())
726
        m_player->stop();
727

728 729 730 731 732
    m_player->play(file, volume);

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

    if(m_player->playing()) {
733 734 735
        actionCollection()->action("pause")->setEnabled(true);
        actionCollection()->action("stop")->setEnabled(true);
        actionCollection()->action("forward")->setEnabled(true);
736

737
        m_backAction->setEnabled(true);
738

739 740 741
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
742

743
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
744

745
        emit signalNewSong(playingString());
746

747 748
        if(m_systemTray)
            m_systemTray->slotPlay();
749 750
    }
    else
751
        stop();
752 753
}

Scott Wheeler's avatar
Scott Wheeler committed
754 755 756
KAction *JuK::createSplitterAction(const QString &text, const char *slot,
				   const char *name, const QString &pix,
				   const KShortcut &shortcut)
757 758 759 760 761 762 763 764 765 766 767 768 769
{
    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;
}

770 771 772 773
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

774
void JuK::slotPlaylistChanged()
775
{
776 777 778 779
    if(m_splitter->collectionListSelected() ||
       !m_splitter->hasListSelected() ||
       m_splitter->readOnlyListSelected())
    {
780 781 782
        actionCollection()->action("file_save")->setEnabled(false);
        actionCollection()->action("file_save_as")->setEnabled(false);
        actionCollection()->action("renamePlaylist")->setEnabled(false);
783
        actionCollection()->action("reloadPlaylist")->setEnabled(false);
784
        actionCollection()->action("deleteItemPlaylist")->setEnabled(false);
785 786
    }
    else {
787 788 789 790
        actionCollection()->action("file_save")->setEnabled(true);
        actionCollection()->action("file_save_as")->setEnabled(true);
        actionCollection()->action("renamePlaylist")->setEnabled(true);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(true);
791 792 793 794 795

	if(m_splitter->fileBasedListSelected() || m_splitter->dynamicListSelected())
	    actionCollection()->action("reloadPlaylist")->setEnabled(true);
	else
	    actionCollection()->action("reloadPlaylist")->setEnabled(false);
796
    }
797 798 799 800 801
    if(m_splitter->hasListSelected())
        actionCollection()->action("duplicatePlaylist")->setEnabled(true);
    else
        actionCollection()->action("duplicatePlaylist")->setEnabled(false);
    
802 803 804
    updatePlaylistInfo();
}

805 806 807 808
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

809
void JuK::slotShowGenreListEditor()
810 811 812 813
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
814

815
void JuK::slotToggleSystemTray(bool enabled)
816
{
817
    if(enabled && !m_systemTray)
818
	setupSystemTray();
819 820 821
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
822
	m_toggleDockOnCloseAction->setEnabled(false);
823 824 825
    }
}

826
void JuK::slotSetOutput(int output)
827
{
828
    stop();
829 830
    delete m_player;
    m_player = Player::createPlayer(output);
831 832
}

833 834 835 836 837
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

838
////////////////////////////////////////////////////////////////////////////////
839
// additional player slots
840 841
////////////////////////////////////////////////////////////////////////////////

842
void JuK::slotTrackPositionSliderClicked()
843
{
844
    m_trackPositionDragging = true;
845 846
}

847
void JuK::slotTrackPositionSliderReleased()
848
{
849
    if(!m_player)
850 851
	return;

852 853
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
854 855
}

856
void JuK::slotTrackPositionSliderUpdate(int position)
857
{
858
    if(!m_player)
859 860
	return;

861 862
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
863 864 865 866

    // 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
Scott Wheeler's avatar
Scott Wheeler committed
867 868
	float positionFraction = float(position) /
	    m_sliderAction->getTrackPositionSlider()->maxValue();
869 870 871 872 873
	float totalTime = float(m_player->totalTime());
	long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

	m_statusLabel->setItemCurrentTime(seekTime);
    }
874 875
}

876 877
// This method is called when the play timer has expired.

878
void JuK::slotPollPlay()
879
{
880
    if(!m_player)
881 882
	return;

883
    // Our locking mechanism.  Since this method adjusts the play slider, we
884
    // want to make sure that our adjustments
885
    m_noSeek = true;
886

887
    if(!m_player->playing()) {
888

889
        m_playTimer->stop();
890

Scott Wheeler's avatar
Scott Wheeler committed
891 892
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				      m_loopPlaylistAction->isChecked()));
893
    }
894 895 896 897
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
898 899 900
    }

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

Scott Wheeler's avatar
Scott Wheeler committed
905 906 907 908
    if(m_player->playing() &&
       m_player->totalTime() > 0 &&
       float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
    {
909
        m_playTimer->changeInterval(50);
Scott Wheeler's avatar
Scott Wheeler committed
910
    }
911

912
    m_noSeek = false;
913 914
}

915
void JuK::slotSetVolume(int volume)
916
{
917 918 919
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
920
    {
Scott Wheeler's avatar
Scott Wheeler committed
921 922
        m_player->setVolume(float(volume) /
			    float(m_sliderAction->getVolumeSlider()->maxValue()));
923 924
    }
}
925

926 927 928 929 930 931
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

932
#include "juk.moc"