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 23.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 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 240 241 242 243 244 245 246
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
    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, "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()));
247

248 249 250 251 252
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

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

261
    m_splitter->open(files);
262 263
}

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

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

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

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

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

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

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

324
    m_restoreOnLoadAction->setChecked(m_restore);
325
    
326 327 328 329
}

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

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

366 367
bool JuK::queryClose()
{
368
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
369 370 371 372 373 374 375 376 377 378 379
	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;
}

380 381 382 383 384 385 386 387 388 389 390 391 392
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;
    
393 394 395
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
396 397
}

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

    return s;
}

410 411 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
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();
}

451 452 453 454
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

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

    updatePlaylistInfo();
}

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

502
////////////////////////////////////////////////////////////////////////////////
503
// player menu
504 505
////////////////////////////////////////////////////////////////////////////////

506
void JuK::slotPlay()
507
{
508
    if(!m_player)
509 510
	return;

511 512
    if(m_player->paused()) {
        m_player->play();
513

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

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

531
void JuK::slotPause()
532
{
533
    if(!m_player)
534 535
	return;

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

543
void JuK::slotStop()
544
{
545
    if(!m_player)
546 547
	return;

548 549
    m_playTimer->stop();
    m_player->stop();
550

551 552 553 554
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
555

556 557
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
558

559
    m_splitter->stop();
560

561
    m_statusLabel->clear();
562
    
563 564
    if(m_systemTray)
	m_systemTray->slotStop();
565 566
}

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

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

577 578 579 580
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

581
void JuK::slotShowGenreListEditor()
582 583 584 585
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
586

587
void JuK::slotToggleSystemTray(bool enabled)
588
{
589
    if(enabled && !m_systemTray)
590
	setupSystemTray();
591 592 593
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
594
	m_toggleDockOnCloseAction->setEnabled(false);
595 596 597
    }
}

598
void JuK::slotSetOutput(int output)
599
{
600
    slotStop();
601 602
    delete m_player;
    m_player = Player::createPlayer(output);
603 604
}

605 606 607 608 609
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

610
////////////////////////////////////////////////////////////////////////////////
611
// additional player slots
612 613
////////////////////////////////////////////////////////////////////////////////

614
void JuK::slotTrackPositionSliderClicked()
615
{
616
    m_trackPositionDragging = true;
617 618
}

619
void JuK::slotTrackPositionSliderReleased()
620
{
621
    if(!m_player)
622 623
	return;

624 625
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
626 627
}

628
void JuK::slotTrackPositionSliderUpdate(int position)
629
{
630
    if(!m_player)
631 632
	return;

633 634
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
635 636
}

637 638 639 640 641 642 643 644 645 646 647 648 649 650 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
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;
    }
}

679 680
// This method is called when the play timer has expired.

681
void JuK::slotPollPlay()
682
{
683
    if(!m_player)
684 685
	return;

686 687
    // Our locking mechanism.  Since this method adjusts the play slider, we 
    // want to make sure that our adjustments
688
    m_noSeek = true;
689

690
    if(!m_player->playing()) {
691

692
        m_playTimer->stop();
693

694
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
695
    }
696 697 698 699
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
700 701 702 703 704 705
    }

    // 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.
706

707
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
708
        m_playTimer->changeInterval(50);
709

710
    m_noSeek = false;
711 712
}

713
void JuK::slotSetVolume(int volume)
714
{
715 716 717
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
718
    {
719
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
720 721
    }
}
722

723 724 725 726 727 728
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

729
#include "juk.moc"