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 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(this, 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

345
    createSplitterAction(i18n("Refresh Items"), SLOT(slotRefresh()), "refresh", "reload");
346

347
    //////////////////////////////////////////////////
348
    // play menu
349 350
    //////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364
    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");
365

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

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

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

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

378
    //////////////////////////////////////////////////
379
    // tagger menu
380 381
    //////////////////////////////////////////////////

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

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

Scott Wheeler's avatar
Scott Wheeler committed
391
    KAction *a;
392

393 394 395 396 397
    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
398

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

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

    //////////////////////////////////////////////////
405
    // settings menu
406 407
    //////////////////////////////////////////////////

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

411
    setStandardToolBarMenuEnabled(true);
412

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

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

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

Scott Wheeler's avatar
Scott Wheeler committed
428 429 430

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

432
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
433

434
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
435 436
        m_outputSelectAction->setCurrentItem(0);
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
437
    }
438

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

442 443
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

444
    //////////////////////////////////////////////////
445
    // just in the toolbar
446 447
    //////////////////////////////////////////////////

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

    createGUI();
452 453

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

457 458 459 460 461 462
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
463 464 465 466 467 468 469 470
    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 *)));
    connect(m_splitter, SIGNAL(signalPlaylistChanged()),
	    this, SLOT(slotPlaylistChanged()));
471 472
}

473
void JuK::setupSystemTray()
474
{
475
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
Frerich Raabe's avatar
Frerich Raabe committed
476 477
        m_systemTray = new SystemTray(this, "systemTray");
        m_systemTray->show();
478

Scott Wheeler's avatar
Scott Wheeler committed
479 480
        connect(this, SIGNAL(signalNewSong(const QString&)), 
		m_systemTray, SLOT(slotNewSong(const QString&)));
481

Frerich Raabe's avatar
Frerich Raabe committed
482 483 484 485
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
486

Frerich Raabe's avatar
Frerich Raabe committed
487
        m_toggleDockOnCloseAction->setEnabled(true);
488

Frerich Raabe's avatar
Frerich Raabe committed
489
        connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
490
    }
491
    else {
Frerich Raabe's avatar
Frerich Raabe committed
492 493
        m_systemTray = 0;
        m_toggleDockOnCloseAction->setEnabled(false);
494
    }
495 496
}

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

507
    m_playTimer = new QTimer(this);
508
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
509

Scott Wheeler's avatar
Scott Wheeler committed
510 511 512 513 514 515 516 517 518 519
    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()));
520
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
521

Scott Wheeler's avatar
Scott Wheeler committed
522 523
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)),
		this, SLOT(slotSetVolume(int)));
524
    }
525

526
    int playerType = 0;
527
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
528 529
        playerType = m_outputSelectAction->currentItem();
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
530 531
    }

532
    m_player = Player::createPlayer(playerType);
533 534
}

535

536 537 538
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
539 540 541 542 543 544 545 546 547
    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()));
548

549 550 551 552 553
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

554 555 556 557
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
558

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

562
    m_splitter->open(files);
563 564
}

565 566 567
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
Frerich Raabe's avatar
Frerich Raabe committed
568
        e->accept();
569 570 571
    KMainWindow::keyPressEvent(e);
}

572 573 574 575 576 577 578 579 580
/**
 * 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
581
        m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
582 583 584
    }
}

585 586
void JuK::readConfig()
{
587
    // Automagically save and m_restore many window settings.
588 589
    setAutoSaveSettings();

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

Frerich Raabe's avatar
Frerich Raabe committed
601 602
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
        m_loopPlaylistAction->setChecked(loopPlaylist);
603
    }
604
    { // view settings
605
        KConfigGroupSaver saver(config, "View");
606 607 608 609 610

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

Frerich Raabe's avatar
Frerich Raabe committed
611 612 613
        bool showEditor = config->readBoolEntry("ShowEditor", false);
        m_showEditorAction->setChecked(showEditor);
        m_splitter->slotSetEditorVisible(showEditor);
614
    }
615 616
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
617

Frerich Raabe's avatar
Frerich Raabe committed
618 619
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
620

Frerich Raabe's avatar
Frerich Raabe committed
621 622
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
623

Frerich Raabe's avatar
Frerich Raabe committed
624 625
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
626

Frerich Raabe's avatar
Frerich Raabe committed
627 628
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
629
    }
630

631
    m_toggleSplashAction->setChecked(m_showSplash);
632 633 634 635
}

void JuK::saveConfig()
{
636
    KConfig *config = KGlobal::config();
637
    { // m_player settings
638
        KConfigGroupSaver saver(config, "Player");
639 640
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
Frerich Raabe's avatar
Frerich Raabe committed
641 642 643 644
        if(m_randomPlayAction)
            config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
        if(m_loopPlaylistAction)
            config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
645
    }
646 647
    { // view settings
        KConfigGroupSaver saver(config, "View");
648

Frerich Raabe's avatar
Frerich Raabe committed
649
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
650
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
651
    }
652 653
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
Frerich Raabe's avatar
Frerich Raabe committed
654 655 656 657 658 659
        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());
660
    }
661
    config->sync();
662 663
}

664
bool JuK::queryExit()
665
{
666
    stop();
667
    delete m_player;
668
    Cache::instance()->save();
669
    saveConfig();
670
    delete m_splitter;
671
    return true;
672 673
}

674 675
bool JuK::queryClose()
{
676
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
677
	KMessageBox::information(this,
Scott Wheeler's avatar
Scott Wheeler committed
678 679 680
	    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");
681 682 683 684 685 686 687
	hide();
	return false;
    }
    else
	return true;
}

688 689 690
QString JuK::playingString() const
{
    QString s;
691 692
    if(!m_player->playing() && !m_player->paused())
	return i18n("No song playing");
693

694 695 696 697
    if(!m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - ";

    s += m_splitter->playingTrack().simplifyWhiteSpace();
698 699 700 701

    return s;
}

702 703
void JuK::updatePlaylistInfo()
{
Scott Wheeler's avatar
Scott Wheeler committed
704 705
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(),
				   m_splitter->selectedPlaylistCount());
706 707 708 709
}

void JuK::play(const QString &file)
{
710
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
Frerich Raabe's avatar
Frerich Raabe committed
711
        return;
712

Scott Wheeler's avatar
Scott Wheeler committed
713 714
    float volume = float(m_sliderAction->getVolumeSlider()->value()) /
	float(m_sliderAction->getVolumeSlider()->maxValue());
715 716

    if(m_player->paused())
Frerich Raabe's avatar
Frerich Raabe committed
717
        m_player->stop();
718

719 720 721 722 723
    m_player->play(file, volume);

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

    if(m_player->playing()) {
724 725 726
        actionCollection()->action("pause")->setEnabled(true);
        actionCollection()->action("stop")->setEnabled(true);
        actionCollection()->action("forward")->setEnabled(true);
727

Frerich Raabe's avatar
Frerich Raabe committed
728
        m_backAction->setEnabled(true);
729

Frerich Raabe's avatar
Frerich Raabe committed
730 731 732
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
733

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

Frerich Raabe's avatar
Frerich Raabe committed
736
        emit signalNewSong(playingString());
737

Frerich Raabe's avatar
Frerich Raabe committed
738 739
        if(m_systemTray)
            m_systemTray->slotPlay();
740 741
    }
    else
Frerich Raabe's avatar
Frerich Raabe committed
742
        stop();
743 744
}

Scott Wheeler's avatar
Scott Wheeler committed
745 746 747
KAction *JuK::createSplitterAction(const QString &text, const char *slot,
				   const char *name, const QString &pix,
				   const KShortcut &shortcut)
748 749 750 751 752 753 754 755 756 757 758 759 760
{
    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;
}

761 762 763 764
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

765
void JuK::slotPlaylistChanged()
766
{
767 768 769 770
    if(m_splitter->collectionListSelected() ||
       !m_splitter->hasListSelected() ||
       m_splitter->readOnlyListSelected())
    {
771 772 773
        actionCollection()->action("file_save")->setEnabled(false);
        actionCollection()->action("file_save_as")->setEnabled(false);
        actionCollection()->action("renamePlaylist")->setEnabled(false);
774
        actionCollection()->action("reloadPlaylist")->setEnabled(false);
775
        actionCollection()->action("deleteItemPlaylist")->setEnabled(false);
776 777
    }
    else {
778 779 780 781
        actionCollection()->action("file_save")->setEnabled(true);
        actionCollection()->action("file_save_as")->setEnabled(true);
        actionCollection()->action("renamePlaylist")->setEnabled(true);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(true);
782 783 784 785 786

	if(m_splitter->fileBasedListSelected() || m_splitter->dynamicListSelected())
	    actionCollection()->action("reloadPlaylist")->setEnabled(true);
	else
	    actionCollection()->action("reloadPlaylist")->setEnabled(false);
787
    }
788 789 790 791 792
    if(m_splitter->hasListSelected())
        actionCollection()->action("duplicatePlaylist")->setEnabled(true);
    else
        actionCollection()->action("duplicatePlaylist")->setEnabled(false);
    
793 794 795
    updatePlaylistInfo();
}

796 797 798 799
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

800
void JuK::slotShowGenreListEditor()
801 802 803 804
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
805

806
void JuK::slotToggleSystemTray(bool enabled)
807
{
808
    if(enabled && !m_systemTray)
809
	setupSystemTray();
810 811 812
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
813
	m_toggleDockOnCloseAction->setEnabled(false);
814 815 816
    }
}

817
void JuK::slotSetOutput(int output)
818
{
819
    stop();
820 821
    delete m_player;
    m_player = Player::createPlayer(output);
822 823
}

824 825 826 827 828
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

829
////////////////////////////////////////////////////////////////////////////////
830
// additional player slots
831 832
////////////////////////////////////////////////////////////////////////////////

833
void JuK::slotTrackPositionSliderClicked()
834
{
835
    m_trackPositionDragging = true;
836 837
}

838
void JuK::slotTrackPositionSliderReleased()
839
{
840
    if(!m_player)
841 842
	return;

843 844
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
845 846
}

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

852 853
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
854 855 856 857

    // 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
858 859
	float positionFraction = float(position) /
	    m_sliderAction->getTrackPositionSlider()->maxValue();
860 861 862 863 864
	float totalTime = float(m_player->totalTime());
	long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

	m_statusLabel->setItemCurrentTime(seekTime);
    }
865 866
}

867 868
// This method is called when the play timer has expired.

869
void JuK::slotPollPlay()
870
{
871
    if(!m_player)
872 873
	return;

874
    // Our locking mechanism.  Since this method adjusts the play slider, we
875
    // want to make sure that our adjustments
876
    m_noSeek = true;
877

878
    if(!m_player->playing()) {
879

880
        m_playTimer->stop();
881

Scott Wheeler's avatar
Scott Wheeler committed
882 883
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				      m_loopPlaylistAction->isChecked()));
884
    }
885 886 887 888
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
889 890 891
    }

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

Scott Wheeler's avatar
Scott Wheeler committed
896 897 898 899
    if(m_player->playing() &&
       m_player->totalTime() > 0 &&
       float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
    {
900
        m_playTimer->changeInterval(50);
Scott Wheeler's avatar
Scott Wheeler committed
901
    }
902

903
    m_noSeek = false;
904 905
}

906
void JuK::slotSetVolume(int volume)
907
{
908 909 910
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
911
    {
Scott Wheeler's avatar
Scott Wheeler committed
912 913
        m_player->setVolume(float(volume) /
			    float(m_sliderAction->getVolumeSlider()->maxValue()));
914 915
    }
}
916

917 918 919 920 921 922
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

923
#include "juk.moc"