juk.cpp 24.2 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 <kapplication.h>
19
#include <klocale.h>
20
#include <kiconloader.h>
21
#include <kcmdlineargs.h>
22
#include <kstatusbar.h>
23
#include <kconfig.h>
24
#include <kdebug.h>
25
#include <kmessagebox.h>
26

27 28
#include <qtimer.h>
#include <qlistview.h>
29
#include <qinputdialog.h>
30
#include <qslider.h>
31 32
#include <qstrlist.h>
#include <qmetaobject.h>
33

34
#include "juk.h"
35
#include "slideraction.h"
36
#include "cache.h"
37
#include "statuslabel.h"
38 39
#include "splashscreen.h"
#include "genrelisteditor.h"
40
#include "systemtray.h"
41
#include "keydialog.h"
42
#include "tagguesserconfigdlg.h"
43 44 45 46 47

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

48 49
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose),
					      m_shuttingDown(false)
50
{
51 52
    // Expect segfaults if you change this order.

53
    readSettings();
54 55 56 57 58 59

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

60
    setupLayout();
61
    setupActions();
62
    slotPlaylistChanged();
63
    readConfig();
64
    setupPlayer();
65
    setupSystemTray();
66
    setupGlobalAccels();
67
    processArgs();
68

69
    SplashScreen::finishedLoading();
Scott Wheeler's avatar
Scott Wheeler committed
70
    QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
71 72 73 74
}

JuK::~JuK()
{
75

76 77 78 79 80 81
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

82 83
void JuK::setupLayout()
{
84 85
    m_splitter = new PlaylistSplitter(this, m_restore, "playlistSplitter");
    setCentralWidget(m_splitter);
86 87

    // playlist item activation connection
88 89
    connect(m_splitter, SIGNAL(signalDoubleClicked()), this, SLOT(slotPlaySelectedFile()));
    connect(m_splitter, SIGNAL(signalListBoxDoubleClicked()), this, SLOT(slotPlayFirstFile()));
90

91
    // create status bar
92 93
    m_statusLabel = new StatusLabel(statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
94

95 96
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)), m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()), m_splitter, SLOT(slotSelectPlaying()));
97

98
    m_splitter->setFocus();
99

100
    resize(750, 500);
101 102
}

103 104
void JuK::setupActions()
{
105
    // file menu
106 107 108
    KStdAction::openNew(m_splitter, SLOT(slotCreatePlaylist()), actionCollection());
    KStdAction::open(m_splitter, SLOT(slotOpen()), actionCollection());
    new KAction(i18n("Open &Directory..."), "fileopen", 0, m_splitter, SLOT(slotOpenDirectory()), actionCollection(), "openDirectory");
109

110
    m_renamePlaylistAction = new KAction(i18n("&Rename..."), 0, m_splitter, SLOT(slotRenamePlaylist()),
111
					 actionCollection(), "renamePlaylist");
112
    new KAction(i18n("D&uplicate..."), "editcopy", 0, m_splitter, SLOT(slotDuplicatePlaylist()), actionCollection(), "duplicatePlaylist");
113

114 115
    m_savePlaylistAction = KStdAction::save(m_splitter, SLOT(slotSavePlaylist()), actionCollection());
    m_saveAsPlaylistAction = KStdAction::saveAs(m_splitter, SLOT(slotSaveAsPlaylist()), actionCollection());
116
    m_deleteItemPlaylistAction = new KAction(i18n("R&emove"), "edittrash", 0, m_splitter, SLOT(slotDeletePlaylist()),
117
					     actionCollection(), "deleteItemPlaylist");
118

119
    KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
120 121

    // edit menu
122
    KStdAction::cut(this, SLOT(cut()), actionCollection());
123 124
    KStdAction::copy(this, SLOT(copy()), actionCollection());
    KStdAction::paste(this, SLOT(paste()), actionCollection());
125
    new KAction(i18n("C&lear"), "editclear", 0, this, SLOT(clear()), actionCollection(), "clear");
126
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
127

128
    // view menu
129
    m_showEditorAction = new KToggleAction(i18n("Show &Tag Editor"), "edit", 0, actionCollection(), "showEditor");
130 131 132
    connect(m_showEditorAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetEditorVisible(bool)));
    KStdAction::redisplay(m_splitter, SLOT(slotRefresh()), actionCollection());
    actionCollection()->insert(m_splitter->columnVisibleAction());
133

134
    // play menu
135
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0, actionCollection(), "randomPlay");
136 137 138 139 140
    m_playAction = new KAction(i18n("&Play"), "player_play", 0, this, SLOT(slotPlay()), actionCollection(), "play");
    m_pauseAction = new KAction(i18n("P&ause"), "player_pause", 0, this, SLOT(slotPause()), actionCollection(), "pause");
    m_stopAction = new KAction(i18n("&Stop"), "player_stop", 0, this, SLOT(slotStop()), actionCollection(), "stop");
    m_backAction = new KAction(i18n("Skip &Back"), "player_start", 0, this, SLOT(slotBack()), actionCollection(), "back");
    m_forwardAction = new KAction(i18n("Skip &Forward"), "player_end", 0, this, SLOT(slotForward()), actionCollection(), "forward");
141
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), "reload", 0, actionCollection(), "loopPlaylist");
142

143
    // tagger menu
144 145 146
    new KAction(i18n("&Save"), "filesave", "CTRL+t", m_splitter, SLOT(slotSaveTag()), actionCollection(), "saveItem");
    new KAction(i18n("&Delete"), "editdelete", 0, m_splitter, SLOT(slotDeleteSelectedItems()), actionCollection(), "removeItem");
    new KAction(i18n("&Guess Tag Information"), 0, m_splitter, SLOT(slotGuessTagInfo()), actionCollection(), "guessTag");
147

148
    // settings menu
149 150 151
    new KToggleAction(i18n("Show Menu Bar"), "CTRL+m", this, SLOT(slotToggleMenuBar()), actionCollection(), "toggleMenuBar");
    new KToggleAction(i18n("Show Tool Bar"), "CTRL+b", this, SLOT(slotToggleToolBar()), actionCollection(), "toggleToolBar");

152 153
    m_restoreOnLoadAction = new KToggleAction(i18n("&Restore Playlists on Load"), 0, actionCollection(), "restoreOnLoad");
    m_toggleSplashAction = new KToggleAction(i18n("Show Splash Screen on Startup"), 0, actionCollection(), "showSplashScreen");
154

155
    m_toggleSystemTrayAction = new KToggleAction(i18n("&Dock in System Tray"), KShortcut(), actionCollection(), "toggleSystemTray");
156
    connect(m_toggleSystemTrayAction, SIGNAL(toggled(bool)), this, SLOT(slotToggleSystemTray(bool)));
157

158
    m_toggleDockOnCloseAction = new KToggleAction(i18n("&Stay in System Tray on Close"), 0, actionCollection(), "dockOnClose");
159

160
    m_togglePopupsAction = new KToggleAction(i18n("&Popup Track Announcement"), 0, this, 0, actionCollection(), "togglePopups");
161

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

164
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
165

166 167
    if(m_outputSelectAction) {
	m_outputSelectAction->setCurrentItem(0);
168
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
169
    }
170

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

173 174
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

175
    // just in the toolbar
176
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");
177 178

    createGUI();
179 180

    // set the slider to the proper orientation and make it stay that way
181 182
    m_sliderAction->slotUpdateOrientation();
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), m_sliderAction, SLOT(slotUpdateOrientation(QDockWindow *)));
183

184
    connect(m_splitter, SIGNAL(signalPlaylistChanged()), this, SLOT(slotPlaylistChanged()));
185 186
}

187
void JuK::setupSystemTray()
188
{
189 190 191
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
	m_systemTray = new SystemTray(this, "systemTray");
	m_systemTray->show();
192

193
	connect(this, SIGNAL(signalNewSong(const QString&)), m_systemTray, SLOT(slotNewSong(const QString&)));
194

195 196 197 198
	if(m_player && m_player->paused())
	    m_systemTray->slotPause();
	else if(m_player && m_player->playing())
	    m_systemTray->slotPlay();
199

200
	m_toggleDockOnCloseAction->setEnabled(true);
201 202

	connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
203
    }
204
    else {
205
	m_systemTray = 0;
206 207
	m_toggleDockOnCloseAction->setEnabled(false);
    }
208 209
}

210 211
void JuK::setupPlayer()
{
212 213
    m_trackPositionDragging = false;
    m_noSeek = false;
Scott Wheeler's avatar
Scott Wheeler committed
214
    m_muted = false;
215 216 217 218
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
219

220
    m_playTimer = new QTimer(this);
221
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
222

223
    if(m_sliderAction && m_sliderAction->getTrackPositionSlider() && m_sliderAction->getVolumeSlider()) {
224 225 226
        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()));
227
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
228

229
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
230
    }
231

232
    int playerType = 0;
233 234
    if(m_outputSelectAction) {
	playerType = m_outputSelectAction->currentItem();
235
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
236 237
    }

238
    m_player = Player::createPlayer(playerType);
239 240
}

241

242 243 244
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
245 246 247 248 249 250 251 252 253
    KeyDialog::insert(m_accel, "PlayPause",  i18n("Play/Pause"),        this, SLOT(slotPlayPause()));
    KeyDialog::insert(m_accel, "Stop",       i18n("Stop Playing"),      this, SLOT(slotStop()));
    KeyDialog::insert(m_accel, "Back",       i18n("Back"),              this, SLOT(slotBack()));
    KeyDialog::insert(m_accel, "Forward",    i18n("Forward"),           this, SLOT(slotForward()));
    KeyDialog::insert(m_accel, "SeekBack",   i18n("Seek Back"),         this, SLOT(slotSeekBack()));
    KeyDialog::insert(m_accel, "SeekForward",i18n("Seek Forward"),      this, SLOT(slotSeekForward()));
    KeyDialog::insert(m_accel, "VolumeUp",   i18n("Volume Up"),         this, SLOT(slotVolumeUp()));
    KeyDialog::insert(m_accel, "VolumeDown", i18n("Volume Down"),       this, SLOT(slotVolumeDown()));
    KeyDialog::insert(m_accel, "Mute",       i18n("Mute"),              this, SLOT(slotVolumeMute()));
254

255 256 257 258 259
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

260 261 262 263
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
264

265 266 267
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

268
    m_splitter->open(files);
269 270
}

271 272 273 274 275 276 277
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
	e->accept();
    KMainWindow::keyPressEvent(e);
}

278 279 280 281 282 283 284 285 286
/**
 * 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");
287
	m_restore = config->readBoolEntry("RestoreOnLoad", true);
288
	m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
289 290 291
    }
}

292 293
void JuK::readConfig()
{
294
    // Automagically save and m_restore many window settings.
295 296
    setAutoSaveSettings();

297
    KConfig *config = KGlobal::config();
298
    { // player settings
299
        KConfigGroupSaver saver(config, "Player");
300
        if(m_sliderAction->getVolumeSlider()) {
301 302
            int volume = config->readNumEntry("Volume", m_sliderAction->getVolumeSlider()->maxValue());
            m_sliderAction->getVolumeSlider()->setValue(volume);
303
        }
304 305
	bool randomPlay = config->readBoolEntry("RandomPlay", false);
	m_randomPlayAction->setChecked(randomPlay);
306 307 308

	bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
	m_loopPlaylistAction->setChecked(loopPlaylist);
309
    }
310
    { // view settings
311
        KConfigGroupSaver saver(config, "View");
312
	bool showEditor = config->readBoolEntry("ShowEditor", false);
313 314
	m_showEditorAction->setChecked(showEditor);
	m_splitter->slotSetEditorVisible(showEditor);
315
    }
316 317
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
318

319
	bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
320
	m_toggleSystemTrayAction->setChecked(dockInSystemTray);
321

322 323 324
	bool dockOnClose = config->readBoolEntry("DockOnClose", true);
	m_toggleDockOnCloseAction->setChecked(dockOnClose);

325 326 327
	bool showPopups = config->readBoolEntry("TrackPopup", false);
	m_togglePopupsAction->setChecked(showPopups);

328 329
	if(m_outputSelectAction)
	    m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
330
    }
331

332
    m_restoreOnLoadAction->setChecked(m_restore);
333
    m_toggleSplashAction->setChecked(m_showSplash);
334 335 336 337
}

void JuK::saveConfig()
{
338
    KConfig *config = KGlobal::config();
339
    { // m_player settings
340
        KConfigGroupSaver saver(config, "Player");
341 342 343 344
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
	if(m_randomPlayAction)
	    config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
345 346
	if(m_loopPlaylistAction)
	    config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
347
    }
348 349
    { // view settings
        KConfigGroupSaver saver(config, "View");
350
	config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
351
    }
352 353
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
354
	config->writeEntry("RestoreOnLoad", m_restoreOnLoadAction->isChecked());
355
	config->writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
356 357 358
	config->writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
	config->writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
	config->writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
359 360
	if(m_outputSelectAction)
	    config->writeEntry("MediaSystem", m_outputSelectAction->currentItem());
361
    }
362
    config->sync();
363 364
}

365
bool JuK::queryExit()
366
{
367
    slotStop();
368
    delete m_player;
369
    Cache::instance()->save();
370
    saveConfig();
371
    delete m_splitter;
372
    return true;
373 374
}

375 376
bool JuK::queryClose()
{
377
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
378 379
	KMessageBox::information(this,
				 i18n("<qt>Closing the main window will keep JuK running in the system tray. "
380
				      "Use Quit from the File menu to quit the application.</qt>"),
381 382 383 384 385 386 387 388
				 i18n("Docking in System Tray"), "hideOnCloseInfo");
	hide();
	return false;
    }
    else
	return true;
}

389 390 391
void JuK::invokeEditSlot( const char *slotName, const char *slot )
{
    QObject *object = focusWidget();
392

393 394
    if(!object || !slotName || !slot)
	return;
395

396 397
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
398

399 400
    if(l.find(slotName) == -1)
	return;
401

402 403 404
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
405 406
}

407 408 409
QString JuK::playingString() const
{
    QString s;
410

411 412
    if(m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingTrack().simplifyWhiteSpace();
413
    else
414
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
415 416 417 418

    return s;
}

419 420 421 422 423 424 425 426 427 428 429 430 431 432
void JuK::updatePlaylistInfo()
{
    m_statusLabel->setPlaylistInfo(m_splitter->selectedPlaylistName(), m_splitter->selectedPlaylistCount());
}

void JuK::play(const QString &file)
{
    if(!m_player)
	return;

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

    if(m_player->paused())
	m_player->stop();
433

434 435 436 437 438 439 440
    m_player->play(file, volume);

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

    if(m_player->playing()) {
	m_pauseAction->setEnabled(true);
	m_stopAction->setEnabled(true);
441

442 443
	m_backAction->setEnabled(true);
	m_forwardAction->setEnabled(true);
444

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	m_sliderAction->getTrackPositionSlider()->setValue(0);
	m_sliderAction->getTrackPositionSlider()->setEnabled(true);
	m_playTimer->start(m_pollInterval);

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

	emit signalNewSong(playingString());

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

460 461 462 463
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

464
void JuK::slotPlaylistChanged()
465
{
466 467 468 469
    if(m_splitter->collectionListSelected()) {
	m_savePlaylistAction->setEnabled(false);
	m_saveAsPlaylistAction->setEnabled(false);
	m_renamePlaylistAction->setEnabled(false);
470
	m_deleteItemPlaylistAction->setEnabled(false);
471 472
    }
    else {
473 474 475 476
	m_savePlaylistAction->setEnabled(true);
	m_saveAsPlaylistAction->setEnabled(true);
	m_renamePlaylistAction->setEnabled(true);
	m_deleteItemPlaylistAction->setEnabled(true);
477
    }
478 479 480 481

    updatePlaylistInfo();
}

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

511
////////////////////////////////////////////////////////////////////////////////
512
// player menu
513 514
////////////////////////////////////////////////////////////////////////////////

515
void JuK::slotPlay()
516
{
517
    if(!m_player)
518 519
	return;

520 521
    if(m_player->paused()) {
        m_player->play();
522

523
	// Here, before doing anything, we want to make sure that the m_player did
524 525
	// in fact start.

526 527 528
        if(m_player->playing()) {
            m_pauseAction->setEnabled(true);
            m_stopAction->setEnabled(true);
529
            m_playTimer->start(m_pollInterval);
530 531
	    if(m_systemTray)
		m_systemTray->slotPlay();
532 533
        }
    }
534 535
    else if(m_player->playing())
	m_player->seekPosition(0);
536
    else
537
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
538 539
}

540
void JuK::slotPause()
541
{
542
    if(!m_player)
543 544
	return;

545 546 547 548 549
    m_playTimer->stop();
    m_player->pause();
    m_pauseAction->setEnabled(false);
    if(m_systemTray)
	m_systemTray->slotPause();
550 551
}

552
void JuK::slotStop()
553
{
554
    if(!m_player)
555 556
	return;

557 558
    m_playTimer->stop();
    m_player->stop();
559

560 561 562 563
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
564

565 566
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
567

568
    m_splitter->stop();
569

570
    m_statusLabel->clear();
571

572 573
    if(m_systemTray)
	m_systemTray->slotStop();
574 575
}

576
void JuK::slotBack()
577
{
578
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
579 580
}

581
void JuK::slotForward()
582
{
583
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
584 585
}

586 587 588 589 590 591 592 593 594 595 596 597 598 599
void JuK::slotSeekBack()
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMAX(m_sliderAction->getTrackPositionSlider()->minValue(), position - 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

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

600 601 602 603
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

604
void JuK::slotShowGenreListEditor()
605 606 607 608
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
609

610
void JuK::slotToggleSystemTray(bool enabled)
611
{
612
    if(enabled && !m_systemTray)
613
	setupSystemTray();
614 615 616
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
617
	m_toggleDockOnCloseAction->setEnabled(false);
618 619 620
    }
}

621
void JuK::slotSetOutput(int output)
622
{
623
    slotStop();
624 625
    delete m_player;
    m_player = Player::createPlayer(output);
626 627
}

628 629 630 631 632
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

633
////////////////////////////////////////////////////////////////////////////////
634
// additional player slots
635 636
////////////////////////////////////////////////////////////////////////////////

637
void JuK::slotTrackPositionSliderClicked()
638
{
639
    m_trackPositionDragging = true;
640 641
}

642
void JuK::slotTrackPositionSliderReleased()
643
{
644
    if(!m_player)
645 646
	return;

647 648
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
649 650
}

651
void JuK::slotTrackPositionSliderUpdate(int position)
652
{
653
    if(!m_player)
654 655
	return;

656 657
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
658 659
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
void JuK::slotPlayPause()
{
    if(!m_player)
	return;

    if(m_player->playing())
	slotPause();
    else
	slotPlay();
}

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

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

void JuK::slotVolumeMute()
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
Scott Wheeler's avatar
Scott Wheeler committed
694
	if(m_muted)
695 696 697
	    slotSetVolume(m_sliderAction->getVolumeSlider()->value());
	else
	    slotSetVolume(0);
Scott Wheeler's avatar
Scott Wheeler committed
698
	m_muted = !m_muted;
699 700 701
    }
}

702 703
// This method is called when the play timer has expired.

704
void JuK::slotPollPlay()
705
{
706
    if(!m_player)
707 708
	return;

709
    // Our locking mechanism.  Since this method adjusts the play slider, we
710
    // want to make sure that our adjustments
711
    m_noSeek = true;
712

713
    if(!m_player->playing()) {
714

715
        m_playTimer->stop();
716

717
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
718
    }
719 720 721 722
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
723 724 725
    }

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

730
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
731
        m_playTimer->changeInterval(50);
732

733
    m_noSeek = false;
734 735
}

736
void JuK::slotSetVolume(int volume)
737
{
738 739 740
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
741
    {
742
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
743 744
    }
}
745

746 747 748 749 750 751
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

752
#include "juk.moc"