juk.cpp 22.4 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 43 44 45 46

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

47 48
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose),
					      m_shuttingDown(false)
49
{
50 51 52
    SplashScreen::instance()->show();
    kapp->processEvents();
 
53 54
    // Expect segfaults if you change this order.

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

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

JuK::~JuK()
{
71

72 73 74 75 76 77
}

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

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

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

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

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

94
    m_splitter->setFocus();
95

96
    resize(750, 500);
97 98
}

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

106
    m_renamePlaylistAction = new KAction(i18n("Rename..."), 0, m_splitter, SLOT(slotRenamePlaylist()), 
107
					 actionCollection(), "renamePlaylist");
108
    new KAction(i18n("Duplicate..."), "editcopy", 0, m_splitter, SLOT(slotDuplicatePlaylist()), actionCollection(), "duplicatePlaylist");
109
    
110 111 112
    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()), 
113
					     actionCollection(), "deleteItemPlaylist");
114

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

    // edit menu
118
    KStdAction::cut(this, SLOT(cut()), actionCollection());
119 120 121 122
    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());
123

124
    // view menu
125 126 127 128
    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());
129
    
130
    // play menu
131
    m_randomPlayAction = new KToggleAction(i18n("Random Play"), 0, actionCollection(), "randomPlay");
132 133 134 135 136
    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");
137

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

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

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

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

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

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

157
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
158

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

164 165
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

166
    // just in the toolbar
167
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");
168 169

    createGUI();
170 171

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

175
    connect(m_splitter, SIGNAL(signalPlaylistChanged()), this, SLOT(slotPlaylistChanged()));
176 177
}

178
void JuK::setupSystemTray()
179
{
180 181 182
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
	m_systemTray = new SystemTray(this, "systemTray");
	m_systemTray->show();
183

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

	connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
194
    }
195
    else {
196
	m_systemTray = 0;
197 198
	m_toggleDockOnCloseAction->setEnabled(false);
    }
199 200
}

201 202
void JuK::setupPlayer()
{
203 204
    m_trackPositionDragging = false;
    m_noSeek = false;
205
    m_volmute = false;
206 207 208 209
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
210

211
    m_playTimer = new QTimer(this);
212
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
213

214
    if(m_sliderAction && m_sliderAction->getTrackPositionSlider() && m_sliderAction->getVolumeSlider()) {
215 216 217
        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()));
218
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
219

220
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(slotSetVolume(int)));
221
    }
222 223
    
    int playerType = 0;
224 225
    if(m_outputSelectAction) {
	playerType = m_outputSelectAction->currentItem();
226
	connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
227 228
    }

229
    m_player = Player::createPlayer(playerType);
230 231
}

232

233 234 235 236 237 238 239 240 241 242
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()));
243

244 245 246 247 248
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

249 250 251 252 253 254 255 256
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
    
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

257
    m_splitter->open(files);
258 259
}

260 261 262 263 264 265 266
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
	e->accept();
    KMainWindow::keyPressEvent(e);
}

267 268 269 270 271 272 273 274 275
/**
 * 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");
276
	m_restore = config->readBoolEntry("RestoreOnLoad", true);
277 278 279
    }
}

280 281
void JuK::readConfig()
{
282
    // Automagically save and m_restore many window settings.
283 284
    setAutoSaveSettings();

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

304
	bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
305
	m_toggleSystemTrayAction->setChecked(dockInSystemTray);
306
	
307 308 309
	bool dockOnClose = config->readBoolEntry("DockOnClose", true);
	m_toggleDockOnCloseAction->setChecked(dockOnClose);

310 311 312
	bool showPopups = config->readBoolEntry("TrackPopup", false);
	m_togglePopupsAction->setChecked(showPopups);

313 314
	if(m_outputSelectAction)
	    m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
315
	
316
    }
317

318
    m_restoreOnLoadAction->setChecked(m_restore);
319
    
320 321 322 323
}

void JuK::saveConfig()
{
324
    KConfig *config = KGlobal::config();
325
    { // m_player settings
326
        KConfigGroupSaver saver(config, "Player");
327 328 329 330
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
	if(m_randomPlayAction)
	    config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
331
    }
332 333
    { // view settings
        KConfigGroupSaver saver(config, "View");
334
	config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
335
    }
336 337
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
338 339 340 341
	config->writeEntry("RestoreOnLoad", m_restoreOnLoadAction->isChecked());
	config->writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
	config->writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
	config->writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
342 343
	if(m_outputSelectAction)
	    config->writeEntry("MediaSystem", m_outputSelectAction->currentItem());
344
    }
345 346
}

347
bool JuK::queryExit()
348
{
349
    slotStop();
350
    delete m_player;
351
    Cache::instance()->save();
352
    saveConfig();
353
    delete m_splitter;
354
    return true;
355 356
}

357 358
bool JuK::queryClose()
{
359
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
360 361 362 363 364 365 366 367 368 369 370
	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;
}

371 372 373 374 375 376 377 378 379 380 381 382 383
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;
    
384 385 386
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
387 388
}

389 390 391 392
QString JuK::playingString() const
{
    QString s;
    
393 394
    if(m_splitter->playingArtist().isEmpty())
	s = m_splitter->playingTrack().simplifyWhiteSpace();
395
    else
396
	s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
397 398 399 400

    return s;
}

401 402 403 404 405 406 407 408 409 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
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();
}

442 443 444 445
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

446
void JuK::slotPlaylistChanged()
447
{
448 449 450 451 452
    if(m_splitter->collectionListSelected()) {
	m_savePlaylistAction->setEnabled(false);
	m_saveAsPlaylistAction->setEnabled(false);
	m_renamePlaylistAction->setEnabled(false);
	m_deleteItemPlaylistAction->setEnabled(false);	
453 454
    }
    else {
455 456 457 458
	m_savePlaylistAction->setEnabled(true);
	m_saveAsPlaylistAction->setEnabled(true);
	m_renamePlaylistAction->setEnabled(true);
	m_deleteItemPlaylistAction->setEnabled(true);
459
    }
460 461 462 463

    updatePlaylistInfo();
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

493
////////////////////////////////////////////////////////////////////////////////
494
// player menu
495 496
////////////////////////////////////////////////////////////////////////////////

497
void JuK::slotPlay()
498
{
499
    if(!m_player)
500 501
	return;

502 503
    if(m_player->paused()) {
        m_player->play();
504

505
	// Here, before doing anything, we want to make sure that the m_player did
506 507
	// in fact start.

508 509 510
        if(m_player->playing()) {
            m_pauseAction->setEnabled(true);
            m_stopAction->setEnabled(true);
511
            m_playTimer->start(m_pollInterval);
512 513
	    if(m_systemTray)
		m_systemTray->slotPlay();
514 515
        }
    }
516 517
    else if(m_player->playing())
	m_player->seekPosition(0);
518
    else
519
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked()));
520 521
}

522
void JuK::slotPause()
523
{
524
    if(!m_player)
525 526
	return;

527 528 529 530 531
    m_playTimer->stop();
    m_player->pause();
    m_pauseAction->setEnabled(false);
    if(m_systemTray)
	m_systemTray->slotPause();
532 533
}

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

539 540
    m_playTimer->stop();
    m_player->stop();
541

542 543 544 545
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
546

547 548
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
549

550
    m_splitter->stop();
551

552
    m_statusLabel->clear();
553
    
554 555
    if(m_systemTray)
	m_systemTray->slotStop();
556 557
}

558
void JuK::slotBack()
559
{
560
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
561 562
}

563
void JuK::slotForward()
564
{
565
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked()));
566 567
}

568 569 570 571
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

572
void JuK::slotShowGenreListEditor()
573 574 575 576
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
577

578
void JuK::slotToggleSystemTray(bool enabled)
579
{
580
    if(enabled && !m_systemTray)
581
	setupSystemTray();
582 583 584
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
585
	m_toggleDockOnCloseAction->setEnabled(false);
586 587 588
    }
}

589
void JuK::slotSetOutput(int output)
590
{
591
    slotStop();
592 593
    delete m_player;
    m_player = Player::createPlayer(output);
594 595
}

596 597 598 599 600
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

601
////////////////////////////////////////////////////////////////////////////////
602
// additional player slots
603 604
////////////////////////////////////////////////////////////////////////////////

605
void JuK::slotTrackPositionSliderClicked()
606
{
607
    m_trackPositionDragging = true;
608 609
}

610
void JuK::slotTrackPositionSliderReleased()
611
{
612
    if(!m_player)
613 614
	return;

615 616
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
617 618
}

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

624 625
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
626 627
}

628 629 630 631 632 633 634 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
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;
    }
}

670 671
// This method is called when the play timer has expired.

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

677 678
    // Our locking mechanism.  Since this method adjusts the play slider, we 
    // want to make sure that our adjustments
679
    m_noSeek = true;
680

681
    if(!m_player->playing()) {
682

683
        m_playTimer->stop();
684

685 686
	if(!m_player->paused())
	    play(m_splitter->playNextFile(m_randomPlayAction->isChecked()));
687

688
    }
689 690 691 692
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
693 694 695 696 697 698
    }

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

700
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
701
        m_playTimer->changeInterval(50);
702

703
    m_noSeek = false;
704 705
}

706
void JuK::slotSetVolume(int volume)
707
{
708 709 710
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
711
    {
712
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
713 714
    }
}
715

716
#include "juk.moc"