Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

juk.cpp 24.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 <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("Duplicate..."), "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("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
    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 155
    m_toggleDockOnCloseAction = new KToggleAction(i18n("Stay in System Tray on Close"), 0, actionCollection(), "dockOnClose");

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 296
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem( config->readNumEntry("Output",0) );
297
        if(m_sliderAction->getVolumeSlider()) {
298 299
            int volume = config->readNumEntry("Volume", m_sliderAction->getVolumeSlider()->maxValue());
            m_sliderAction->getVolumeSlider()->setValue(volume);
300
        }
301 302
	bool randomPlay = config->readBoolEntry("RandomPlay", false);
	m_randomPlayAction->setChecked(randomPlay);
303 304
    const bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
    m_loopPlaylistAction->setChecked(loopPlaylist);
305
    }
306
    { // view settings
307
        KConfigGroupSaver saver(config, "View");
308
	bool showEditor = config->readBoolEntry("ShowEditor", false);
309 310
	m_showEditorAction->setChecked(showEditor);
	m_splitter->slotSetEditorVisible(showEditor);
311
    }
312 313
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
314

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

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

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

324 325
	if(m_outputSelectAction)
	    m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
326

327
    }
328

329
    m_restoreOnLoadAction->setChecked(m_restore);
330

331 332 333 334
}

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

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

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

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

391 392
    if(!object || !slotName || !slot)
	return;
393

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

397 398
    if(l.find(slotName) == -1)
	return;
399

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

405 406 407
QString JuK::playingString() const
{
    QString s;
408

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

    return s;
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430
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();
431

432 433 434 435 436 437 438
    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);
439

440 441
	m_backAction->setEnabled(true);
	m_forwardAction->setEnabled(true);
442

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
	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();
}

458 459 460 461
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

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

    updatePlaylistInfo();
}

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 505 506 507 508
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

509
////////////////////////////////////////////////////////////////////////////////
510
// player menu
511 512
////////////////////////////////////////////////////////////////////////////////

513
void JuK::slotPlay()
514
{
515
    if(!m_player)
516 517
	return;

518 519
    if(m_player->paused()) {
        m_player->play();
520

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

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

538
void JuK::slotPause()
539
{
540
    if(!m_player)
541 542
	return;

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

550
void JuK::slotStop()
551
{
552
    if(!m_player)
553 554
	return;

555 556
    m_playTimer->stop();
    m_player->stop();
557

558 559 560 561
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
562

563 564
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
565

566
    m_splitter->stop();
567

568
    m_statusLabel->clear();
569

570 571
    if(m_systemTray)
	m_systemTray->slotStop();
572 573
}

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

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

584 585 586 587 588 589 590 591 592 593 594 595 596 597
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);
}

598 599 600 601
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

631
////////////////////////////////////////////////////////////////////////////////
632
// additional player slots
633 634
////////////////////////////////////////////////////////////////////////////////

635
void JuK::slotTrackPositionSliderClicked()
636
{
637
    m_trackPositionDragging = true;
638 639
}

640
void JuK::slotTrackPositionSliderReleased()
641
{
642
    if(!m_player)
643 644
	return;

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

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

654 655
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
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 696 697 698 699
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;
    }
}

700 701
// This method is called when the play timer has expired.

702
void JuK::slotPollPlay()
703
{
704
    if(!m_player)
705 706
	return;

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

711
    if(!m_player->playing()) {
712

713
        m_playTimer->stop();
714

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

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

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

731
    m_noSeek = false;
732 733
}

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

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

750
#include "juk.moc"