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

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

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

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

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

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

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

47
    readSettings();
48 49 50 51 52 53

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

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

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

JuK::~JuK()
{
70

71 72
}

73 74 75 76 77 78 79 80 81
////////////////////////////////////////////////////////////////////////////////
// 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
82
        slotSetVolume(int(volume / 100) * m_sliderAction->getVolumeSlider()->maxValue());
83 84 85 86 87 88 89 90 91 92 93
    }
}

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

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

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

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

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

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

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

    m_playTimer->stop();
    m_player->pause();
134
    m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    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
179 180
    m_splitter->populatePlayHistoryMenu(m_backAction->popupMenu(),
					m_randomPlayAction->isChecked());
181 182 183 184
}

void JuK::forward()
{
Scott Wheeler's avatar
Scott Wheeler committed
185 186
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(),
				  m_loopPlaylistAction->isChecked()));
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
}

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
218
	    m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
219 220 221 222 223 224 225 226 227
	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
228
	    m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	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);
}

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

256 257 258 259
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

280
    m_splitter->setFocus();
281

282
    resize(750, 500);
283 284
}

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

Scott Wheeler's avatar
Scott Wheeler committed
291 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
    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");
318

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

321
    //////////////////////////////////////////////////
322
    // edit menu
323 324 325 326
    //////////////////////////////////////////////////

    KStdAction::cut(this,   SLOT(cut()),   actionCollection());
    KStdAction::copy(this,  SLOT(copy()),  actionCollection());
327
    KStdAction::paste(this, SLOT(paste()), actionCollection());
328

Scott Wheeler's avatar
Scott Wheeler committed
329 330
    new KAction(i18n("C&lear"), "editclear", 0, this, SLOT(clear()),
		actionCollection(), "clear");
331

332
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
333

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

337
    //////////////////////////////////////////////////
338
    // view menu
339
    //////////////////////////////////////////////////
340

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

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

348
    //////////////////////////////////////////////////
349
    // play menu
350 351
    //////////////////////////////////////////////////

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

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

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

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

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

379
    //////////////////////////////////////////////////
380
    // tagger menu
381 382
    //////////////////////////////////////////////////

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

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

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

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

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

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

    //////////////////////////////////////////////////
406
    // settings menu
407 408
    //////////////////////////////////////////////////

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

412
    setStandardToolBarMenuEnabled(true);
413

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

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

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

Scott Wheeler's avatar
Scott Wheeler committed
429 430 431

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

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

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

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

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

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

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

    createGUI();
453 454

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

458 459 460 461 462 463
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
464 465 466 467 468 469 470 471
    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()));
472 473
}

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

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

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

488
        m_toggleDockOnCloseAction->setEnabled(true);
489

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

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

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

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

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

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

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

536

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

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

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

560
    for(int i = 0; i < args->count(); i++)
561
        files.append(args->arg(i));
562

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

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

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

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

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

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

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

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

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

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

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

628 629
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
630
    }
631

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

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

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

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

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

689
void JuK::invokeEditSlot(const char *slotName, const char *slot)
690 691
{
    QObject *object = focusWidget();
692

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

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

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

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

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

713
    if(m_splitter->playingArtist().isEmpty())
714
        s = m_splitter->playingTrack().simplifyWhiteSpace();
715
    else
Scott Wheeler's avatar
Scott Wheeler committed
716 717
        s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " +
	    m_splitter->playingTrack().simplifyWhiteSpace();
718 719 720 721

    return s;
}

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

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

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

    if(m_player->paused())
737
        m_player->stop();
738

739 740 741 742 743
    m_player->play(file, volume);

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

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

748
        m_backAction->setEnabled(true);
749

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

754
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
755

756
        emit signalNewSong(playingString());
757

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

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

781 782 783 784
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

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

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

    updatePlaylistInfo();
}

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 841 842
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

843 844 845 846
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

876
////////////////////////////////////////////////////////////////////////////////
877
// additional player slots
878 879
////////////////////////////////////////////////////////////////////////////////

880
void JuK::slotTrackPositionSliderClicked()
881
{
882
    m_trackPositionDragging = true;
883 884
}

885
void JuK::slotTrackPositionSliderReleased()
886
{
887
    if(!m_player)
888 889
	return;

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

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

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

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

	m_statusLabel->setItemCurrentTime(seekTime);
    }
912 913
}

914 915
// This method is called when the play timer has expired.

916
void JuK::slotPollPlay()
917
{
918
    if(!m_player)
919 920
	return;

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

925
    if(!m_player->playing()) {
926

927
        m_playTimer->stop();
928

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

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

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

950
    m_noSeek = false;
951 952
}

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

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

970
#include "juk.moc"