juk.cpp 23.9 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
    SplashScreen::instance()->show();
    kapp->processEvents();
53

54 55
    // Expect segfaults if you change this order.

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

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

JuK::~JuK()
{
72

73 74 75 76 77 78
}

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

79 80
void JuK::setupLayout()
{
81 82
    m_splitter = new PlaylistSplitter(this, m_restore, "playlistSplitter");
    setCentralWidget(m_splitter);
83 84

    // playlist item activation connection
85 86
    connect(m_splitter, SIGNAL(signalDoubleClicked()), this, SLOT(slotPlaySelectedFile()));
    connect(m_splitter, SIGNAL(signalListBoxDoubleClicked()), this, SLOT(slotPlayFirstFile()));
87

88
    // create status bar
89 90
    m_statusLabel = new StatusLabel(statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
91

92 93
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)), m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()), m_splitter, SLOT(slotSelectPlaying()));
94

95
    m_splitter->setFocus();
96

97
    resize(750, 500);
98 99
}

100 101
void JuK::setupActions()
{
102
    // file menu
103 104 105
    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");
106

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

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

116
    KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
117 118

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

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

131
    // play menu
132
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0, actionCollection(), "randomPlay");
133 134 135 136 137
    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");
138
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), "reload", 0, actionCollection(), "loopPlaylist");
139

140
    // tagger menu
141 142 143
    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");
144

145
    // settings menu
146 147 148
    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");

149
    m_restoreOnLoadAction = new KToggleAction(i18n("&Restore Playlists on Load"),  0, actionCollection(), "restoreOnLoad");
150

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

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

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

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

160
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
161

162 163
    if(m_outputSelectAction) {
	m_outputSelectAction->setCurrentItem(0);
164
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
165
    }
166

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

169 170
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

171
    // just in the toolbar
172
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");
173 174

    createGUI();
175 176

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

180
    connect(m_splitter, SIGNAL(signalPlaylistChanged()), this, SLOT(slotPlaylistChanged()));
181 182
}

183
void JuK::setupSystemTray()
184
{
185 186 187
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
	m_systemTray = new SystemTray(this, "systemTray");
	m_systemTray->show();
188

189
	connect(this, SIGNAL(signalNewSong(const QString&)), m_systemTray, SLOT(slotNewSong(const QString&)));
190

191 192 193 194
	if(m_player && m_player->paused())
	    m_systemTray->slotPause();
	else if(m_player && m_player->playing())
	    m_systemTray->slotPlay();
195

196
	m_toggleDockOnCloseAction->setEnabled(true);
197 198

	connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
199
    }
200
    else {
201
	m_systemTray = 0;
202 203
	m_toggleDockOnCloseAction->setEnabled(false);
    }
204 205
}

206 207
void JuK::setupPlayer()
{
208 209
    m_trackPositionDragging = false;
    m_noSeek = false;
210
    m_volmute = false;
211 212 213 214
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
215

216
    m_playTimer = new QTimer(this);
217
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
218

219
    if(m_sliderAction && m_sliderAction->getTrackPositionSlider() && m_sliderAction->getVolumeSlider()) {
220 221 222
        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()));
223
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
224

225
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
226
    }
227

228
    int playerType = 0;
229 230
    if(m_outputSelectAction) {
	playerType = m_outputSelectAction->currentItem();
231
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
232 233
    }

234
    m_player = Player::createPlayer(playerType);
235 236
}

237

238 239 240
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
241 242 243 244 245 246 247 248 249
    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()));
250

251 252 253 254 255
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

256 257 258 259
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
260

261 262 263
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

264
    m_splitter->open(files);
265 266
}

267 268 269 270 271 272 273
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
	e->accept();
    KMainWindow::keyPressEvent(e);
}

274 275 276 277 278 279 280 281 282
/**
 * 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");
283
	m_restore = config->readBoolEntry("RestoreOnLoad", true);
284 285 286
    }
}

287 288
void JuK::readConfig()
{
289
    // Automagically save and m_restore many window settings.
290 291
    setAutoSaveSettings();

292
    KConfig *config = KGlobal::config();
293
    { // m_player settings
294
        KConfigGroupSaver saver(config, "Player");
295
        if(m_sliderAction->getVolumeSlider()) {
296 297
            int volume = config->readNumEntry("Volume", m_sliderAction->getVolumeSlider()->maxValue());
            m_sliderAction->getVolumeSlider()->setValue(volume);
298
        }
299 300
	bool randomPlay = config->readBoolEntry("RandomPlay", false);
	m_randomPlayAction->setChecked(randomPlay);
301 302
    const bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
    m_loopPlaylistAction->setChecked(loopPlaylist);
303
    }
304
    { // view settings
305
        KConfigGroupSaver saver(config, "View");
306
	bool showEditor = config->readBoolEntry("ShowEditor", false);
307 308
	m_showEditorAction->setChecked(showEditor);
	m_splitter->slotSetEditorVisible(showEditor);
309
    }
310 311
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
312

313
	bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
314
	m_toggleSystemTrayAction->setChecked(dockInSystemTray);
315

316 317 318
	bool dockOnClose = config->readBoolEntry("DockOnClose", true);
	m_toggleDockOnCloseAction->setChecked(dockOnClose);

319 320 321
	bool showPopups = config->readBoolEntry("TrackPopup", false);
	m_togglePopupsAction->setChecked(showPopups);

322 323
	if(m_outputSelectAction)
	    m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
324

325
    }
326

327
    m_restoreOnLoadAction->setChecked(m_restore);
328

329 330 331 332
}

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

359
bool JuK::queryExit()
360
{
361
    slotStop();
362
    delete m_player;
363
    Cache::instance()->save();
364
    saveConfig();
365
    delete m_splitter;
366
    return true;
367 368
}

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

383 384 385
void JuK::invokeEditSlot( const char *slotName, const char *slot )
{
    QObject *object = focusWidget();
386

387 388
    if(!object || !slotName || !slot)
	return;
389

390 391
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
392

393 394
    if(l.find(slotName) == -1)
	return;
395

396 397 398
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
399 400
}

401 402 403
QString JuK::playingString() const
{
    QString s;
404

405 406
    if(m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingTrack().simplifyWhiteSpace();
407
    else
408
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
409 410 411 412

    return s;
}

413 414 415 416 417 418 419 420 421 422 423 424 425 426
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();
427

428 429 430 431 432 433 434
    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);
435

436 437
	m_backAction->setEnabled(true);
	m_forwardAction->setEnabled(true);
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
	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();
}

454 455 456 457
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

458
void JuK::slotPlaylistChanged()
459
{
460 461 462 463
    if(m_splitter->collectionListSelected()) {
	m_savePlaylistAction->setEnabled(false);
	m_saveAsPlaylistAction->setEnabled(false);
	m_renamePlaylistAction->setEnabled(false);
464
	m_deleteItemPlaylistAction->setEnabled(false);
465 466
    }
    else {
467 468 469 470
	m_savePlaylistAction->setEnabled(true);
	m_saveAsPlaylistAction->setEnabled(true);
	m_renamePlaylistAction->setEnabled(true);
	m_deleteItemPlaylistAction->setEnabled(true);
471
    }
472 473 474 475

    updatePlaylistInfo();
}

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

505
////////////////////////////////////////////////////////////////////////////////
506
// player menu
507 508
////////////////////////////////////////////////////////////////////////////////

509
void JuK::slotPlay()
510
{
511
    if(!m_player)
512 513
	return;

514 515
    if(m_player->paused()) {
        m_player->play();
516

517
	// Here, before doing anything, we want to make sure that the m_player did
518 519
	// in fact start.

520 521 522
        if(m_player->playing()) {
            m_pauseAction->setEnabled(true);
            m_stopAction->setEnabled(true);
523
            m_playTimer->start(m_pollInterval);
524 525
	    if(m_systemTray)
		m_systemTray->slotPlay();
526 527
        }
    }
528 529
    else if(m_player->playing())
	m_player->seekPosition(0);
530
    else
531
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
532 533
}

534
void JuK::slotPause()
535
{
536
    if(!m_player)
537 538
	return;

539 540 541 542 543
    m_playTimer->stop();
    m_player->pause();
    m_pauseAction->setEnabled(false);
    if(m_systemTray)
	m_systemTray->slotPause();
544 545
}

546
void JuK::slotStop()
547
{
548
    if(!m_player)
549 550
	return;

551 552
    m_playTimer->stop();
    m_player->stop();
553

554 555 556 557
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
558

559 560
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
561

562
    m_splitter->stop();
563

564
    m_statusLabel->clear();
565

566 567
    if(m_systemTray)
	m_systemTray->slotStop();
568 569
}

570
void JuK::slotBack()
571
{
572
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
573 574
}

575
void JuK::slotForward()
576
{
577
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
578 579
}

580 581 582 583 584 585 586 587 588 589 590 591 592 593
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);
}

594 595 596 597
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

598
void JuK::slotShowGenreListEditor()
599 600 601 602
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
603

604
void JuK::slotToggleSystemTray(bool enabled)
605
{
606
    if(enabled && !m_systemTray)
607
	setupSystemTray();
608 609 610
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
611
	m_toggleDockOnCloseAction->setEnabled(false);
612 613 614
    }
}

615
void JuK::slotSetOutput(int output)
616
{
617
    slotStop();
618 619
    delete m_player;
    m_player = Player::createPlayer(output);
620 621
}

622 623 624 625 626
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

627
////////////////////////////////////////////////////////////////////////////////
628
// additional player slots
629 630
////////////////////////////////////////////////////////////////////////////////

631
void JuK::slotTrackPositionSliderClicked()
632
{
633
    m_trackPositionDragging = true;
634 635
}

636
void JuK::slotTrackPositionSliderReleased()
637
{
638
    if(!m_player)
639 640
	return;

641 642
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
643 644
}

645
void JuK::slotTrackPositionSliderUpdate(int position)
646
{
647
    if(!m_player)
648 649
	return;

650 651
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
652 653
}

654 655 656 657 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 694 695
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()) {
	if(m_volmute)
	    slotSetVolume(m_sliderAction->getVolumeSlider()->value());
	else
	    slotSetVolume(0);
	m_volmute = !m_volmute;
    }
}

696 697
// This method is called when the play timer has expired.

698
void JuK::slotPollPlay()
699
{
700
    if(!m_player)
701 702
	return;

703
    // Our locking mechanism.  Since this method adjusts the play slider, we
704
    // want to make sure that our adjustments
705
    m_noSeek = true;
706

707
    if(!m_player->playing()) {
708

709
        m_playTimer->stop();
710

711
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
712
    }
713 714 715 716
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
717 718 719
    }

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

724
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
725
        m_playTimer->changeInterval(50);
726

727
    m_noSeek = false;
728 729
}

730
void JuK::slotSetVolume(int volume)
731
{
732 733 734
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
735
    {
736
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
737 738
    }
}
739

740 741 742 743 744 745
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

746
#include "juk.moc"