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 26.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 <kcmdlineargs.h>
19
#include <kstatusbar.h>
20
#include <kdebug.h>
21
#include <kmessagebox.h>
22

23
#include <qslider.h>
24

25
#include "juk.h"
26
#include "slideraction.h"
27
#include "statuslabel.h"
28 29
#include "splashscreen.h"
#include "genrelisteditor.h"
30
#include "systemtray.h"
31
#include "keydialog.h"
32
#include "tagguesserconfigdlg.h"
33 34 35 36 37

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

38
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose),
39
					      DCOPObject("Player"),
40
					      m_shuttingDown(false)
41
{
42 43
    // Expect segfaults if you change this order.

44
    readSettings();
45 46 47 48 49 50

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

51
    setupLayout();
52
    setupActions();
53
    slotPlaylistChanged();
54
    readConfig();
55
    setupPlayer();
56
    setupSystemTray();
57
    setupGlobalAccels();
58
    processArgs();
59

60
    SplashScreen::finishedLoading();
Scott Wheeler's avatar
Scott Wheeler committed
61
    QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
62 63 64 65
}

JuK::~JuK()
{
66

67 68 69 70 71 72
}

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

73 74
void JuK::setupLayout()
{
75 76
    m_splitter = new PlaylistSplitter(this, m_restore, "playlistSplitter");
    setCentralWidget(m_splitter);
77 78

    // playlist item activation connection
79
    connect(m_splitter, SIGNAL(signalDoubleClicked()), this, SLOT(slotPlaySelectedFile()));
80
    connect(m_splitter, SIGNAL(signalListBoxDoubleClicked()), this, SLOT(startPlayingPlaylist()));
81

82
    // create status bar
83 84
    m_statusLabel = new StatusLabel(statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
85

86 87
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)), m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()), m_splitter, SLOT(slotSelectPlaying()));
88

89
    m_splitter->setFocus();
90

91
    resize(750, 500);
92 93
}

94 95
void JuK::setupActions()
{
96
    // file menu
97 98 99
    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");
100

101
    m_renamePlaylistAction = new KAction(i18n("&Rename..."), 0, m_splitter, SLOT(slotRenamePlaylist()),
102
					 actionCollection(), "renamePlaylist");
103
    new KAction(i18n("D&uplicate..."), "editcopy", 0, m_splitter, SLOT(slotDuplicatePlaylist()), actionCollection(), "duplicatePlaylist");
104

105 106
    m_savePlaylistAction = KStdAction::save(m_splitter, SLOT(slotSavePlaylist()), actionCollection());
    m_saveAsPlaylistAction = KStdAction::saveAs(m_splitter, SLOT(slotSaveAsPlaylist()), actionCollection());
107
    m_deleteItemPlaylistAction = new KAction(i18n("R&emove"), "edittrash", 0, m_splitter, SLOT(slotDeletePlaylist()),
108
					     actionCollection(), "deleteItemPlaylist");
109

110
    KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
111 112

    // edit menu
113
    KStdAction::cut(this, SLOT(cut()), actionCollection());
114 115
    KStdAction::copy(this, SLOT(copy()), actionCollection());
    KStdAction::paste(this, SLOT(paste()), actionCollection());
116
    new KAction(i18n("C&lear"), "editclear", 0, this, SLOT(clear()), actionCollection(), "clear");
117
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
118

119
    // view menu
120 121 122
    m_showSearchAction = new KToggleAction(i18n("Show &Search Bar"), "filefind", 0, actionCollection(), "showSearch");
    connect(m_showSearchAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetSearchVisible(bool)));

123
    m_showEditorAction = new KToggleAction(i18n("Show &Tag Editor"), "edit", 0, actionCollection(), "showEditor");
124
    connect(m_showEditorAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetEditorVisible(bool)));
125

126 127
    KStdAction::redisplay(m_splitter, SLOT(slotRefresh()), actionCollection());
    actionCollection()->insert(m_splitter->columnVisibleAction());
128

129
    // play menu
130
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0, actionCollection(), "randomPlay");
131 132 133
    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");
134 135 136
    m_backAction = new KToolBarPopupAction(i18n("Skip &Back"), "player_start", 0, this, SLOT(back()), actionCollection(), "back");
    connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotPopulateBackMenu()));
    connect(m_backAction->popupMenu(), SIGNAL(activated(int)), this, SLOT(back(int)));
137
    m_forwardAction = new KAction(i18n("Skip &Forward"), "player_end", 0, this, SLOT(forward()), actionCollection(), "forward");
138
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), 0, 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 145 146 147 148

    KActionMenu *guessMenu = new KActionMenu(i18n("&Guess Tag Information"), "", actionCollection(), "guessTag");
    guessMenu->insert(new KAction(i18n("From &File"), 0, "CTRL+g", m_splitter,
                                  SLOT(slotGuessTagInfoFile()), actionCollection(), "guessTagFile"));
    guessMenu->insert(new KAction(i18n("From &Internet"), 0, "CTRL+i", m_splitter,
                                  SLOT(slotGuessTagInfoInternet()), actionCollection(), "guessTagInternet"));
149
    //new KAction(i18n("&Rename File"), 0, "CTRL+r", m_splitter, SLOT(slotRenameFile()), actionCollection(), "renameFile");
150

151
    // settings menu
152
    new KToggleAction(i18n("Show Menu Bar"), "CTRL+m", this, SLOT(slotToggleMenuBar()), actionCollection(), "toggleMenuBar");
153
    setStandardToolBarMenuEnabled(true);
154

155 156
    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");
157

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

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

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

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

167 168
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
169 170
        m_outputSelectAction->setCurrentItem(0);
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
171
    }
172

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

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

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

    createGUI();
181 182

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

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

189
void JuK::setupSystemTray()
190
{
191
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
Frerich Raabe's avatar
Frerich Raabe committed
192 193
        m_systemTray = new SystemTray(this, "systemTray");
        m_systemTray->show();
194

Frerich Raabe's avatar
Frerich Raabe committed
195
        connect(this, SIGNAL(signalNewSong(const QString&)), m_systemTray, SLOT(slotNewSong(const QString&)));
196

Frerich Raabe's avatar
Frerich Raabe committed
197 198 199 200
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
201

Frerich Raabe's avatar
Frerich Raabe committed
202
        m_toggleDockOnCloseAction->setEnabled(true);
203

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

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

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

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

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

234
    int playerType = 0;
235
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
236 237
        playerType = m_outputSelectAction->currentItem();
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
238 239
    }

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

243

244 245 246
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
247 248 249 250 251 252 253 254 255
    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()));
256

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

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

267
    for(int i = 0; i < args->count(); i++)
Frerich Raabe's avatar
Frerich Raabe committed
268
        files.append(args->arg(i));
269

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

273 274 275
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
Frerich Raabe's avatar
Frerich Raabe committed
276
        e->accept();
277 278 279
    KMainWindow::keyPressEvent(e);
}

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

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

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

Frerich Raabe's avatar
Frerich Raabe committed
309 310
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
        m_loopPlaylistAction->setChecked(loopPlaylist);
311
    }
312
    { // view settings
313
        KConfigGroupSaver saver(config, "View");
314 315 316 317 318

        bool showSearch = config->readBoolEntry("ShowSearch", true);
        m_showSearchAction->setChecked(showSearch);
        m_splitter->slotSetSearchVisible(showSearch);

Frerich Raabe's avatar
Frerich Raabe committed
319 320 321
        bool showEditor = config->readBoolEntry("ShowEditor", false);
        m_showEditorAction->setChecked(showEditor);
        m_splitter->slotSetEditorVisible(showEditor);
322
    }
323 324
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
325

Frerich Raabe's avatar
Frerich Raabe committed
326 327
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
328

Frerich Raabe's avatar
Frerich Raabe committed
329 330
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
331

Frerich Raabe's avatar
Frerich Raabe committed
332 333
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
334

Frerich Raabe's avatar
Frerich Raabe committed
335 336
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
337
    }
338

339
    m_restoreOnLoadAction->setChecked(m_restore);
340
    m_toggleSplashAction->setChecked(m_showSplash);
341 342 343 344
}

void JuK::saveConfig()
{
345
    KConfig *config = KGlobal::config();
346
    { // m_player settings
347
        KConfigGroupSaver saver(config, "Player");
348 349
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
Frerich Raabe's avatar
Frerich Raabe committed
350 351 352 353
        if(m_randomPlayAction)
            config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
        if(m_loopPlaylistAction)
            config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
354
    }
355 356
    { // view settings
        KConfigGroupSaver saver(config, "View");
357

Frerich Raabe's avatar
Frerich Raabe committed
358
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
359
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
360
    }
361 362
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
Frerich Raabe's avatar
Frerich Raabe committed
363 364 365 366 367 368 369
        config->writeEntry("RestoreOnLoad", m_restoreOnLoadAction->isChecked());
        config->writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
        config->writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
        config->writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
        config->writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
        if(m_outputSelectAction)
            config->writeEntry("MediaSystem", m_outputSelectAction->currentItem());
370
    }
371
    config->sync();
372 373
}

374
bool JuK::queryExit()
375
{
376
    stop();
377
    delete m_player;
378
    Cache::instance()->save();
379
    saveConfig();
380
    delete m_splitter;
381
    return true;
382 383
}

384 385
bool JuK::queryClose()
{
386
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
387 388
	KMessageBox::information(this,
				 i18n("<qt>Closing the main window will keep JuK running in the system tray. "
389
				      "Use Quit from the File menu to quit the application.</qt>"),
390 391 392 393 394 395 396 397
				 i18n("Docking in System Tray"), "hideOnCloseInfo");
	hide();
	return false;
    }
    else
	return true;
}

398 399 400
void JuK::invokeEditSlot( const char *slotName, const char *slot )
{
    QObject *object = focusWidget();
401

402
    if(!object || !slotName || !slot)
Frerich Raabe's avatar
Frerich Raabe committed
403
        return;
404

405 406
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
407

408
    if(l.find(slotName) == -1)
Frerich Raabe's avatar
Frerich Raabe committed
409
        return;
410

411 412 413
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
414 415
}

416 417 418
QString JuK::playingString() const
{
    QString s;
419

420
    if(m_splitter->playingArtist().isEmpty())
Frerich Raabe's avatar
Frerich Raabe committed
421
        s = m_splitter->playingTrack().simplifyWhiteSpace();
422
    else
Frerich Raabe's avatar
Frerich Raabe committed
423
        s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
424 425 426 427

    return s;
}

428 429
void JuK::updatePlaylistInfo()
{
Frerich Raabe's avatar
Frerich Raabe committed
430
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(), m_splitter->selectedPlaylistCount());
431 432 433 434
}

void JuK::play(const QString &file)
{
435
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
Frerich Raabe's avatar
Frerich Raabe committed
436
        return;
437 438 439 440

    float volume = float(m_sliderAction->getVolumeSlider()->value()) / float(m_sliderAction->getVolumeSlider()->maxValue());

    if(m_player->paused())
Frerich Raabe's avatar
Frerich Raabe committed
441
        m_player->stop();
442

443 444 445 446 447
    m_player->play(file, volume);

    // Make sure that the m_player actually starts before doing anything.

    if(m_player->playing()) {
Frerich Raabe's avatar
Frerich Raabe committed
448 449
        m_pauseAction->setEnabled(true);
        m_stopAction->setEnabled(true);
450

Frerich Raabe's avatar
Frerich Raabe committed
451 452
        m_backAction->setEnabled(true);
        m_forwardAction->setEnabled(true);
453

Frerich Raabe's avatar
Frerich Raabe committed
454 455 456
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
457

Frerich Raabe's avatar
Frerich Raabe committed
458
        m_statusLabel->setPlayingItemInfo(playingString(), m_splitter->playingList());
459

Frerich Raabe's avatar
Frerich Raabe committed
460
        emit signalNewSong(playingString());
461

Frerich Raabe's avatar
Frerich Raabe committed
462 463
        if(m_systemTray)
            m_systemTray->slotPlay();
464 465
    }
    else
Frerich Raabe's avatar
Frerich Raabe committed
466
        stop();
467 468
}

469 470 471 472
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

473
void JuK::slotPlaylistChanged()
474
{
475
    if(m_splitter->collectionListSelected()) {
Frerich Raabe's avatar
Frerich Raabe committed
476 477 478 479
        m_savePlaylistAction->setEnabled(false);
        m_saveAsPlaylistAction->setEnabled(false);
        m_renamePlaylistAction->setEnabled(false);
        m_deleteItemPlaylistAction->setEnabled(false);
480 481
    }
    else {
Frerich Raabe's avatar
Frerich Raabe committed
482 483 484 485
        m_savePlaylistAction->setEnabled(true);
        m_saveAsPlaylistAction->setEnabled(true);
        m_renamePlaylistAction->setEnabled(true);
        m_deleteItemPlaylistAction->setEnabled(true);
486
    }
487 488 489 490

    updatePlaylistInfo();
}

491 492 493 494 495 496 497 498
void JuK::startPlayingPlaylist()
{
    if(m_randomPlayAction->isChecked())
        play(m_splitter->playRandomFile());
    else
        play(m_splitter->playFirstFile());
}

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

528
////////////////////////////////////////////////////////////////////////////////
529
// player menu
530 531
////////////////////////////////////////////////////////////////////////////////

532
void JuK::play()
533
{
534
    if(!m_player)
Frerich Raabe's avatar
Frerich Raabe committed
535
    return;
536

537 538
    if(m_player->paused()) {
        m_player->play();
539

540
	// Here, before doing anything, we want to make sure that the m_player did
541 542
	// in fact start.

543 544 545
        if(m_player->playing()) {
            m_pauseAction->setEnabled(true);
            m_stopAction->setEnabled(true);
546
            m_playTimer->start(m_pollInterval);
547 548
	    if(m_systemTray)
		m_systemTray->slotPlay();
549 550
        }
    }
551 552
    else if(m_player->playing())
	m_player->seekPosition(0);
553
    else
554
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
555 556
}

557
void JuK::pause()
558
{
559
    if(!m_player)
560 561
	return;

562 563 564 565 566
    m_playTimer->stop();
    m_player->pause();
    m_pauseAction->setEnabled(false);
    if(m_systemTray)
	m_systemTray->slotPause();
567 568
}

569
void JuK::stop()
570
{
571
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
572 573
	return;

574 575
    m_playTimer->stop();
    m_player->stop();
576

577 578 579 580
    m_pauseAction->setEnabled(false);
    m_stopAction->setEnabled(false);
    m_backAction->setEnabled(false);
    m_forwardAction->setEnabled(false);
581

582 583
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
584

585
    m_splitter->stop();
586

587
    m_statusLabel->clear();
588

589 590
    if(m_systemTray)
	m_systemTray->slotStop();
591 592
}

593
void JuK::back()
594
{
595
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
596 597
}

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
void JuK::back(int howMany)
{
    for (--howMany; howMany > 0; --howMany)
    {
        m_splitter->playPreviousFile(m_randomPlayAction->isChecked());
    }

    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
}

void JuK::slotPopulateBackMenu()
{
    m_splitter->populatePlayHistoryMenu(m_backAction->popupMenu(), m_randomPlayAction->isChecked());
}

613
void JuK::forward()
614
{
615
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
616 617
}

618
void JuK::seekBack()
619 620 621 622 623 624
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMAX(m_sliderAction->getTrackPositionSlider()->minValue(), position - 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

625
void JuK::seekForward()
626 627 628 629 630 631
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMIN(m_sliderAction->getTrackPositionSlider()->maxValue(), position + 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

632 633 634 635
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

636
void JuK::slotShowGenreListEditor()
637 638 639 640
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
641

642
void JuK::slotToggleSystemTray(bool enabled)
643
{
644
    if(enabled && !m_systemTray)
645
	setupSystemTray();
646 647 648
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
649
	m_toggleDockOnCloseAction->setEnabled(false);
650 651 652
    }
}

653
void JuK::slotSetOutput(int output)
654
{
655
    stop();
656 657
    delete m_player;
    m_player = Player::createPlayer(output);
658 659
}

660 661 662 663 664
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

665
////////////////////////////////////////////////////////////////////////////////
666
// additional player slots
667 668
////////////////////////////////////////////////////////////////////////////////

669
void JuK::slotTrackPositionSliderClicked()
670
{
671
    m_trackPositionDragging = true;
672 673
}

674
void JuK::slotTrackPositionSliderReleased()
675
{
676
    if(!m_player)
677 678
	return;

679 680
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
681 682
}

683
void JuK::slotTrackPositionSliderUpdate(int position)
684
{
685
    if(!m_player)
686 687
	return;

688 689
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
690 691 692 693 694 695 696 697 698 699

    // 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);
    }
700 701
}

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

    if(m_player->playing())
708
	pause();
709
    else
710
	play();
711 712
}

713
void JuK::volumeUp()
714 715 716 717
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() +
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
718
	setVolume(volume);
719 720 721 722
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

723
void JuK::volumeDown()
724 725 726 727
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() -
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
728
	setVolume(volume);
729 730 731 732
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

733
void JuK::volumeMute()
734 735
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
Scott Wheeler's avatar
Scott Wheeler committed
736
	if(m_muted)
737
	    setVolume(m_sliderAction->getVolumeSlider()->value());
738
	else
739 740
	    setVolume(0);
	    m_muted = !m_muted;
741 742 743
    }
}

744 745
// This method is called when the play timer has expired.

746
void JuK::slotPollPlay()
747
{
748
    if(!m_player)
749 750
	return;

751
    // Our locking mechanism.  Since this method adjusts the play slider, we
752
    // want to make sure that our adjustments
753
    m_noSeek = true;
754

755
    if(!m_player->playing()) {
756

757
        m_playTimer->stop();
758

759
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
760
    }
761 762 763 764
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
765 766 767
    }

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

772
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
773
        m_playTimer->changeInterval(50);
774

775
    m_noSeek = false;
776 777
}

778
void JuK::setVolume(int volume)
779
{
780 781 782
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
783
    {
784
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
785 786
    }
}
787

788 789 790 791 792 793
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

794 795 796 797
void JuK::openFile(const QString &file)
{
    m_splitter->open(file);
}
798

799
#include "juk.moc"