juk.cpp 30 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 18

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

#include "juk.h"
19
#include "slideraction.h"
20
#include "statuslabel.h"
21 22
#include "splashscreen.h"
#include "genrelisteditor.h"
23
#include "systemtray.h"
24
#include "keydialog.h"
25
#include "tagguesserconfigdlg.h"
26

27 28 29 30 31 32 33 34 35 36
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kstatusbar.h>
#include <kdebug.h>
#include <kmessagebox.h>

#include <qmetaobject.h>
#include <qslider.h>
#include <qmime.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
    //////////////////////////////////////////////////

    KStdAction::cut(this,   SLOT(cut()),   actionCollection());
    KStdAction::copy(this,  SLOT(copy()),  actionCollection());
328
    KStdAction::paste(this, SLOT(paste()), actionCollection());
329
    KStdAction::clear(this, 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) {
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()) {
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

482 483 484 485
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
486

487
        m_toggleDockOnCloseAction->setEnabled(true);
488

489
        connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
490
    }
491
    else {
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) {
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++)
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)
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");
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
        }
598 599
        bool randomPlay = config->readBoolEntry("RandomPlay", false);
        m_randomPlayAction->setChecked(randomPlay);
600

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

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

618 619
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
620

621 622
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
623

624 625
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
626

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

649
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
650
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
651
    }
652 653
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
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
void JuK::invokeEditSlot(const char *slotName, const char *slot)
689 690
{
    QObject *object = focusWidget();
691

692
    if(!object || !slotName || !slot)
693
        return;
694

695 696
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
697

698
    if(l.find(slotName) == -1)
699
        return;
700

701 702 703
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
704 705
}

706 707 708
QString JuK::playingString() const
{
    QString s;
709 710
    if(!m_player->playing() && !m_player->paused())
	return i18n("No song playing");
711

712 713 714 715
    if(!m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - ";

    s += m_splitter->playingTrack().simplifyWhiteSpace();
716 717 718 719

    return s;
}

720 721
void JuK::updatePlaylistInfo()
{
Scott Wheeler's avatar
Scott Wheeler committed
722 723
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(),
				   m_splitter->selectedPlaylistCount());
724 725 726 727
}

void JuK::play(const QString &file)
{
728
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
729
        return;
730

Scott Wheeler's avatar
Scott Wheeler committed
731 732
    float volume = float(m_sliderAction->getVolumeSlider()->value()) /
	float(m_sliderAction->getVolumeSlider()->maxValue());
733 734

    if(m_player->paused())
735
        m_player->stop();
736

737 738 739 740 741
    m_player->play(file, volume);

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

    if(m_player->playing()) {
742 743 744
        actionCollection()->action("pause")->setEnabled(true);
        actionCollection()->action("stop")->setEnabled(true);
        actionCollection()->action("forward")->setEnabled(true);
745

746
        m_backAction->setEnabled(true);
747

748 749 750
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
751

752
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
753

754
        emit signalNewSong(playingString());
755

756 757
        if(m_systemTray)
            m_systemTray->slotPlay();
758 759
    }
    else
760
        stop();
761 762
}

Scott Wheeler's avatar
Scott Wheeler committed
763 764 765
KAction *JuK::createSplitterAction(const QString &text, const char *slot,
				   const char *name, const QString &pix,
				   const KShortcut &shortcut)
766 767 768 769 770 771 772 773 774 775 776 777 778
{
    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;
}

779 780 781 782
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

783
void JuK::slotPlaylistChanged()
784
{
785
    if(m_splitter->collectionListSelected() || !m_splitter->hasListSelected()) {
786 787 788
        actionCollection()->action("file_save")->setEnabled(false);
        actionCollection()->action("file_save_as")->setEnabled(false);
        actionCollection()->action("renamePlaylist")->setEnabled(false);
789
        actionCollection()->action("reloadPlaylist")->setEnabled(false);
790
        actionCollection()->action("deleteItemPlaylist")->setEnabled(false);
791 792
    }
    else {
793 794 795 796
        actionCollection()->action("file_save")->setEnabled(true);
        actionCollection()->action("file_save_as")->setEnabled(true);
        actionCollection()->action("renamePlaylist")->setEnabled(true);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(true);
797 798 799 800 801

	if(m_splitter->fileBasedListSelected() || m_splitter->dynamicListSelected())
	    actionCollection()->action("reloadPlaylist")->setEnabled(true);
	else
	    actionCollection()->action("reloadPlaylist")->setEnabled(false);
802
    }
803 804 805 806 807
    if(m_splitter->hasListSelected())
        actionCollection()->action("duplicatePlaylist")->setEnabled(true);
    else
        actionCollection()->action("duplicatePlaylist")->setEnabled(false);
    
808 809 810 811

    updatePlaylistInfo();
}

812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

841 842 843 844
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

845
void JuK::slotShowGenreListEditor()
846 847 848 849
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
850

851
void JuK::slotToggleSystemTray(bool enabled)
852
{
853
    if(enabled && !m_systemTray)
854
	setupSystemTray();
855 856 857
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
858
	m_toggleDockOnCloseAction->setEnabled(false);
859 860 861
    }
}

862
void JuK::slotSetOutput(int output)
863
{
864
    stop();
865 866
    delete m_player;
    m_player = Player::createPlayer(output);
867 868
}

869 870 871 872 873
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

874
////////////////////////////////////////////////////////////////////////////////
875
// additional player slots
876 877
////////////////////////////////////////////////////////////////////////////////

878
void JuK::slotTrackPositionSliderClicked()
879
{
880
    m_trackPositionDragging = true;
881 882
}

883
void JuK::slotTrackPositionSliderReleased()
884
{
885
    if(!m_player)
886 887
	return;

888 889
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
890 891
}

892
void JuK::slotTrackPositionSliderUpdate(int position)
893
{
894
    if(!m_player)
895 896
	return;

897 898
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
899 900 901 902

    // 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
903 904
	float positionFraction = float(position) /
	    m_sliderAction->getTrackPositionSlider()->maxValue();
905 906 907 908 909
	float totalTime = float(m_player->totalTime());
	long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

	m_statusLabel->setItemCurrentTime(seekTime);
    }
910 911
}

912 913
// This method is called when the play timer has expired.

914
void JuK::slotPollPlay()
915
{
916
    if(!m_player)
917 918
	return;

919
    // Our locking mechanism.  Since this method adjusts the play slider, we
920
    // want to make sure that our adjustments
921
    m_noSeek = true;
922

923
    if(!m_player->playing()) {
924

925
        m_playTimer->stop();
926

Scott Wheeler's avatar
Scott Wheeler committed
927 928
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				      m_loopPlaylistAction->isChecked()));
929
    }
930 931 932 933
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
934 935 936
    }

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

Scott Wheeler's avatar
Scott Wheeler committed
941 942 943 944
    if(m_player->playing() &&
       m_player->totalTime() > 0 &&
       float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
    {
945
        m_playTimer->changeInterval(50);
Scott Wheeler's avatar
Scott Wheeler committed
946
    }
947

948
    m_noSeek = false;
949 950
}

951
void JuK::slotSetVolume(int volume)
952
{
953 954 955
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
956
    {
Scott Wheeler's avatar
Scott Wheeler committed
957 958
        m_player->setVolume(float(volume) /
			    float(m_sliderAction->getVolumeSlider()->maxValue()));
959 960
    }
}
961

962 963 964 965 966 967
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

968
#include "juk.moc"