juk.cpp 23.8 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 53
    SplashScreen::instance()->show();
    kapp->processEvents();
 
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("Duplicate..."), "editcopy", 0, m_splitter, SLOT(slotDuplicatePlaylist()), actionCollection(), "duplicatePlaylist");
110
    
111 112 113
    m_savePlaylistAction = KStdAction::save(m_splitter, SLOT(slotSavePlaylist()), actionCollection());
    m_saveAsPlaylistAction = KStdAction::saveAs(m_splitter, SLOT(slotSaveAsPlaylist()), actionCollection());
    m_deleteItemPlaylistAction = new KAction(i18n("Remove"), "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 122 123
    KStdAction::copy(this, SLOT(copy()), actionCollection());
    KStdAction::paste(this, SLOT(paste()), actionCollection());
    new KAction(i18n("Clear"), "editclear", 0, this, SLOT(clear()), actionCollection(), "clear");
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
124

125
    // view menu
126 127 128 129
    m_showEditorAction = new KToggleAction(i18n("Show Tag Editor"), "edit", 0, actionCollection(), "showEditor");
    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
    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");
143
    
144
    // settings menu
145 146 147
    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");

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

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

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

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

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

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

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

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

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

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

    createGUI();
174 175

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

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

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

188
	connect(this, SIGNAL(signalNewSong(const QString&)), m_systemTray, SLOT(slotNewSong(const QString&)));
189
	
190 191 192 193
	if(m_player && m_player->paused())
	    m_systemTray->slotPause();
	else if(m_player && m_player->playing())
	    m_systemTray->slotPlay();
194 195
	
	m_toggleDockOnCloseAction->setEnabled(true);
196 197

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

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

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

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

224
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
225
    }
226 227
    
    int playerType = 0;
228 229
    if(m_outputSelectAction) {
	playerType = m_outputSelectAction->currentItem();
230
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
231 232
    }

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

236

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

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

255 256 257 258 259 260 261 262
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
    
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

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

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

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

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

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

312
	bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
313
	m_toggleSystemTrayAction->setChecked(dockInSystemTray);
314
	
315 316 317
	bool dockOnClose = config->readBoolEntry("DockOnClose", true);
	m_toggleDockOnCloseAction->setChecked(dockOnClose);

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

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

326
    m_restoreOnLoadAction->setChecked(m_restore);
327
    
328 329 330 331
}

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

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

368 369
bool JuK::queryClose()
{
370
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
371 372 373 374 375 376 377 378 379 380 381
	KMessageBox::information(this,
				 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");
	hide();
	return false;
    }
    else
	return true;
}

382 383 384 385 386 387 388 389 390 391 392 393 394
void JuK::invokeEditSlot( const char *slotName, const char *slot )
{
    QObject *object = focusWidget();
    
    if(!object || !slotName || !slot)
	return;
    
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
  
    if(l.find(slotName) == -1)
	return;
    
395 396 397
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
398 399
}

400 401 402 403
QString JuK::playingString() const
{
    QString s;
    
404 405
    if(m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingTrack().simplifyWhiteSpace();
406
    else
407
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
408 409 410 411

    return s;
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
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();
    
    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);
	
	m_backAction->setEnabled(true);
	m_forwardAction->setEnabled(true);
	
	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();
}

453 454 455 456
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

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

    updatePlaylistInfo();
}

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

504
////////////////////////////////////////////////////////////////////////////////
505
// player menu
506 507
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

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

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

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

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

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

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

561
    m_splitter->stop();
562

563
    m_statusLabel->clear();
564
    
565 566
    if(m_systemTray)
	m_systemTray->slotStop();
567 568
}

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

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

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

593 594 595 596
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

626
////////////////////////////////////////////////////////////////////////////////
627
// additional player slots
628 629
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

649 650
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
651 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
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;
    }
}

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

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

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

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

708
        m_playTimer->stop();
709

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

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

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

726
    m_noSeek = false;
727 728
}

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

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

745
#include "juk.moc"