juk.cpp 24.6 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
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose),
49
					      DCOPObject ( "Player" ),
50
					      m_shuttingDown(false)
51
{
52 53
    // Expect segfaults if you change this order.

54
    readSettings();
55 56 57 58 59 60

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

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

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

JuK::~JuK()
{
76

77 78 79 80 81 82
}

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

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

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

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

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

99
    m_splitter->setFocus();
100

101
    resize(750, 500);
102 103
}

104 105
void JuK::setupActions()
{
106
    // file menu
107 108 109
    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");
110

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

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

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

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

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

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

144
    // tagger menu
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");
147
    new KAction(i18n("&Guess Tag Information"), 0, "CTRL+g", m_splitter, SLOT(slotGuessTagInfo()), actionCollection(), "guessTag");
148

149
    // settings menu
150 151 152
    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");

153 154
    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");
155

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

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

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

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

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

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

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

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

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

    createGUI();
180 181

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

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

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

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

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

201
	m_toggleDockOnCloseAction->setEnabled(true);
202 203

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

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

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

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

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

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

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

242

243 244 245
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
246 247 248 249 250 251 252 253 254
    KeyDialog::insert(m_accel, "PlayPause",  i18n("Play/Pause"),        this, SLOT(playPause()));
    KeyDialog::insert(m_accel, "Stop",       i18n("Stop Playing"),      this, SLOT(stop()));
    KeyDialog::insert(m_accel, "Back",       i18n("Back"),              this, SLOT(back()));
    KeyDialog::insert(m_accel, "Forward",    i18n("Forward"),           this, SLOT(forward()));
    KeyDialog::insert(m_accel, "SeekBack",   i18n("Seek Back"),         this, SLOT(seekBack()));
    KeyDialog::insert(m_accel, "SeekForward",i18n("Seek Forward"),      this, SLOT(seekForward()));
    KeyDialog::insert(m_accel, "VolumeUp",   i18n("Volume Up"),         this, SLOT(volumeUp()));
    KeyDialog::insert(m_accel, "VolumeDown", i18n("Volume Down"),       this, SLOT(volumeDown()));
    KeyDialog::insert(m_accel, "Mute",       i18n("Mute"),              this, SLOT(volumeMute()));
255

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return s;
}

420 421 422 423 424 425 426 427 428 429 430 431 432 433
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();
434

435 436 437 438 439 440 441
    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);
442

443 444
	m_backAction->setEnabled(true);
	m_forwardAction->setEnabled(true);
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
458
	stop();
459 460
}

461 462 463 464
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

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

    updatePlaylistInfo();
}

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

512
////////////////////////////////////////////////////////////////////////////////
513
// player menu
514 515
////////////////////////////////////////////////////////////////////////////////

516
void JuK::play()
517
{
518
    if(!m_player)
519 520
	return;

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

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

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

541
void JuK::pause()
542
{
543
    if(!m_player)
544 545
	return;

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

553
void JuK::stop()
554
{
555
    if(!m_player)
556 557
	return;

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

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

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

569
    m_splitter->stop();
570

571
    m_statusLabel->clear();
572

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

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

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

587
void JuK::seekBack()
588 589 590 591 592 593
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMAX(m_sliderAction->getTrackPositionSlider()->minValue(), position - 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

594
void JuK::seekForward()
595 596 597 598 599 600
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMIN(m_sliderAction->getTrackPositionSlider()->maxValue(), position + 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

601 602 603 604
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

634
////////////////////////////////////////////////////////////////////////////////
635
// additional player slots
636 637
////////////////////////////////////////////////////////////////////////////////

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

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

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

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

657 658
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
659 660 661 662 663 664 665 666 667 668

    // The dragging flag is set, so just update the status label, rather than seeking
    if(m_player->playing() && m_trackPositionDragging && !m_noSeek) {
	// position from 0 to 1
	float positionFraction = float(position) / m_sliderAction->getTrackPositionSlider()->maxValue();
	float totalTime = float(m_player->totalTime());
	long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

	m_statusLabel->setItemCurrentTime(seekTime);
    }
669 670
}

671
void JuK::playPause()
672 673 674 675 676
{
    if(!m_player)
	return;

    if(m_player->playing())
677
	pause();
678
    else
679
	play();
680 681
}

682
void JuK::volumeUp()
683 684 685 686
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() +
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
687
	setVolume(volume);
688 689 690 691
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

692
void JuK::volumeDown()
693 694 695 696
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() -
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
697
	setVolume(volume);
698 699 700 701
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

702
void JuK::volumeMute()
703 704
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
Scott Wheeler's avatar
Scott Wheeler committed
705
	if(m_muted)
706
	    setVolume(m_sliderAction->getVolumeSlider()->value());
707
	else
708 709
	    setVolume(0);
	    m_muted = !m_muted;
710 711 712
    }
}

713 714
// This method is called when the play timer has expired.

715
void JuK::slotPollPlay()
716
{
717
    if(!m_player)
718 719
	return;

720
    // Our locking mechanism.  Since this method adjusts the play slider, we
721
    // want to make sure that our adjustments
722
    m_noSeek = true;
723

724
    if(!m_player->playing()) {
725

726
        m_playTimer->stop();
727

728
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
729
    }
730 731 732 733
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
734 735 736
    }

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

741
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
742
        m_playTimer->changeInterval(50);
743

744
    m_noSeek = false;
745 746
}

747
void JuK::setVolume(int volume)
748
{
749 750 751
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
752
    {
753
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
754 755
    }
}
756

757 758 759 760 761 762
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

763 764 765 766 767
void JuK::openFile(const QString &file)
{
    m_splitter->open(file);
}
    
768
#include "juk.moc"