juk.cpp 28.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

Frerich Raabe's avatar
Frerich Raabe committed
23
#include <qmetaobject.h>
24
#include <qslider.h>
25

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

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

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

45
    readSettings();
46 47 48 49 50 51

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

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

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

JuK::~JuK()
{
68

69 70 71 72 73 74
}

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

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

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

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

88 89
    connect(m_splitter, SIGNAL(signalSelectedPlaylistCountChanged(int)), m_statusLabel, SLOT(setPlaylistCount(int)));
    connect(m_statusLabel, SIGNAL(jumpButtonClicked()), m_splitter, SLOT(slotSelectPlaying()));
90

91
    m_splitter->setFocus();
92

93
    resize(750, 500);
94 95
}

96 97
void JuK::setupActions()
{
98
    //////////////////////////////////////////////////
99
    // file menu
100
    //////////////////////////////////////////////////
101

Scott Wheeler's avatar
Scott Wheeler committed
102 103
    createSplitterAction(i18n("New Playlist..."),    SLOT(slotCreatePlaylist()),    "file_new",           "filenew",  "CTRL+n");
    createSplitterAction(i18n("Open..."),            SLOT(slotOpen()),              "file_open",          "fileopen", "CTRL+o");
104 105 106
    createSplitterAction(i18n("Open &Directory..."), SLOT(slotOpenDirectory()),     "openDirectory",      "fileopen");
    createSplitterAction(i18n("&Rename..."),         SLOT(slotRenamePlaylist()),    "renamePlaylist");
    createSplitterAction(i18n("D&uplicate..."),      SLOT(slotDuplicatePlaylist()), "duplicatePlaylist");
Scott Wheeler's avatar
Scott Wheeler committed
107
    createSplitterAction(i18n("Save"),               SLOT(slotSavePlaylist()),      "file_save",          "filesave", "CTRL+s");
108 109
    createSplitterAction(i18n("Save As..."),         SLOT(slotSaveAsPlaylist()),    "file_save_as",       "filesaveas");
    createSplitterAction(i18n("R&emove"),            SLOT(slotDeletePlaylist()),    "deleteItemPlaylist", "edittrash");
110

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

113
    //////////////////////////////////////////////////
114
    // edit menu
115 116 117 118
    //////////////////////////////////////////////////

    KStdAction::cut(this,   SLOT(cut()),   actionCollection());
    KStdAction::copy(this,  SLOT(copy()),  actionCollection());
119
    KStdAction::paste(this, SLOT(paste()), actionCollection());
120

121
    new KAction(i18n("C&lear"), "editclear", 0, this, SLOT(clear()), actionCollection(), "clear");
122

123
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());
124

125
    //////////////////////////////////////////////////
126
    // view menu
127
    //////////////////////////////////////////////////
128

129 130
    m_showSearchAction = new KToggleAction(i18n("Show &Search Bar"), "filefind", 0, actionCollection(), "showSearch");
    m_showEditorAction = new KToggleAction(i18n("Show &Tag Editor"), "edit",     0, actionCollection(), "showEditor");
131

132
    createSplitterAction(i18n("Refresh Items"), SLOT(slotRefresh()), "refresh", "reload");
133

134
    //////////////////////////////////////////////////
135
    // play menu
136 137
    //////////////////////////////////////////////////

138
    m_randomPlayAction = new KToggleAction(i18n("&Random Play"), 0, actionCollection(), "randomPlay");
139 140 141 142 143

    new KAction(i18n("&Play"),  "player_play",  0, this, SLOT(play()),  actionCollection(), "play");
    new KAction(i18n("P&ause"), "player_pause", 0, this, SLOT(pause()), actionCollection(), "pause");
    new KAction(i18n("&Stop"),  "player_stop",  0, this, SLOT(stop()),  actionCollection(), "stop");

144
    m_backAction = new KToolBarPopupAction(i18n("Skip &Back"), "player_start", 0, this, SLOT(back()), actionCollection(), "back");
145
    connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()),  this, SLOT(slotPopulateBackMenu()));
146
    connect(m_backAction->popupMenu(), SIGNAL(activated(int)), this, SLOT(back(int)));
147 148 149

    new KAction(i18n("Skip &Forward"), "player_end", 0, this, SLOT(forward()), actionCollection(), "forward");

150
    m_loopPlaylistAction = new KToggleAction(i18n("&Loop Playlist"), 0, 0, actionCollection(), "loopPlaylist");
151

152
    //////////////////////////////////////////////////
153
    // tagger menu
154 155 156 157
    //////////////////////////////////////////////////

    createSplitterAction(i18n("&Save"),   SLOT(slotSaveTag()),             "saveItem",   "filesave", "CTRL+t");
    createSplitterAction(i18n("&Delete"), SLOT(slotDeleteSelectedItems()), "removeItem", "editdelete");
158 159

    KActionMenu *guessMenu = new KActionMenu(i18n("&Guess Tag Information"), "", actionCollection(), "guessTag");
160

161 162 163 164 165 166 167 168
    guessMenu->insert(
        createSplitterAction(i18n("From &Filename"), SLOT(slotGuessTagInfoFile()),     "guessTagFile",     0, "CTRL+f"));
    guessMenu->insert(
        createSplitterAction(i18n("From &Internet"), SLOT(slotGuessTagInfoInternet()), "guessTagInternet", 0, "CTRL+i"));

    // new KAction(i18n("&Rename File"), 0, "CTRL+r", m_splitter, SLOT(slotRenameFile()), actionCollection(), "renameFile"); // 4

    //////////////////////////////////////////////////
169
    // settings menu
170 171
    //////////////////////////////////////////////////

172
    new KToggleAction(i18n("Show Menu Bar"), "CTRL+m", this, SLOT(slotToggleMenuBar()), actionCollection(), "toggleMenuBar");
173

174
    setStandardToolBarMenuEnabled(true);
175

176 177 178 179 180
    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");
    m_toggleSystemTrayAction  = new KToggleAction(i18n("&Dock in System Tray"),          0, actionCollection(), "toggleSystemTray");
    m_toggleDockOnCloseAction = new KToggleAction(i18n("&Stay in System Tray on Close"), 0, actionCollection(), "dockOnClose");
    m_togglePopupsAction      = new KToggleAction(i18n("&Popup Track Announcement"),     0, this, 0, actionCollection(), "togglePopups");
181

182
    connect(m_toggleSystemTrayAction, SIGNAL(toggled(bool)), this, SLOT(slotToggleSystemTray(bool)));
183

184

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

187
    m_outputSelectAction = Player::playerSelectAction(actionCollection());
188

189
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
190 191
        m_outputSelectAction->setCurrentItem(0);
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
192
    }
193

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

196 197
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());

198
    //////////////////////////////////////////////////
199
    // just in the toolbar
200 201
    //////////////////////////////////////////////////

202
    m_sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");
203 204

    createGUI();
205 206

    // set the slider to the proper orientation and make it stay that way
207
    m_sliderAction->slotUpdateOrientation();
208 209
}

210 211 212 213 214 215
void JuK::setupSplitterConnections()
{
    QValueListConstIterator<SplitterConnection> it = m_splitterConnections.begin();
    for(; it != m_splitterConnections.end(); ++it)
        connect((*it).first, SIGNAL(activated()), m_splitter, (*it).second);

216 217
    actionCollection()->insert(m_splitter->columnVisibleAction());

218 219 220
    connect(m_showSearchAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetSearchVisible(bool)));
    connect(m_showEditorAction, SIGNAL(toggled(bool)), m_splitter, SLOT(slotSetEditorVisible(bool)));
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), m_sliderAction, SLOT(slotUpdateOrientation(QDockWindow *)));
221
    connect(m_splitter, SIGNAL(signalPlaylistChanged()), this, SLOT(slotPlaylistChanged()));
222 223
}

224
void JuK::setupSystemTray()
225
{
226
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
Frerich Raabe's avatar
Frerich Raabe committed
227 228
        m_systemTray = new SystemTray(this, "systemTray");
        m_systemTray->show();
229

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

Frerich Raabe's avatar
Frerich Raabe committed
232 233 234 235
        if(m_player && m_player->paused())
            m_systemTray->slotPause();
        else if(m_player && m_player->playing())
            m_systemTray->slotPlay();
236

Frerich Raabe's avatar
Frerich Raabe committed
237
        m_toggleDockOnCloseAction->setEnabled(true);
238

Frerich Raabe's avatar
Frerich Raabe committed
239
        connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
240
    }
241
    else {
Frerich Raabe's avatar
Frerich Raabe committed
242 243
        m_systemTray = 0;
        m_toggleDockOnCloseAction->setEnabled(false);
244
    }
245 246
}

247 248
void JuK::setupPlayer()
{
249 250
    m_trackPositionDragging = false;
    m_noSeek = false;
Scott Wheeler's avatar
Scott Wheeler committed
251
    m_muted = false;
252 253 254 255
    actionCollection()->action("pause")->setEnabled(false);
    actionCollection()->action("stop")->setEnabled(false);
    actionCollection()->action("back")->setEnabled(false);
    actionCollection()->action("forward")->setEnabled(false);
256

257
    m_playTimer = new QTimer(this);
258
    connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
259

260
    if(m_sliderAction && m_sliderAction->getTrackPositionSlider() && m_sliderAction->getVolumeSlider()) {
261 262 263
        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()));
264
        m_sliderAction->getTrackPositionSlider()->setEnabled(false);
265

266
        connect(m_sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
267
    }
268

269
    int playerType = 0;
270
    if(m_outputSelectAction) {
Frerich Raabe's avatar
Frerich Raabe committed
271 272
        playerType = m_outputSelectAction->currentItem();
        connect(m_outputSelectAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
273 274
    }

275
    m_player = Player::createPlayer(playerType);
276 277
}

278

279 280 281
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
282 283 284 285 286 287 288 289 290
    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()));
291

292 293 294 295 296
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

297 298 299 300
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
301

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

305
    m_splitter->open(files);
306 307
}

308 309 310
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
Frerich Raabe's avatar
Frerich Raabe committed
311
        e->accept();
312 313 314
    KMainWindow::keyPressEvent(e);
}

315 316 317 318 319 320 321 322 323
/**
 * 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
324 325
        m_restore = config->readBoolEntry("RestoreOnLoad", true);
        m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
326 327 328
    }
}

329 330
void JuK::readConfig()
{
331
    // Automagically save and m_restore many window settings.
332 333
    setAutoSaveSettings();

334
    KConfig *config = KGlobal::config();
335
    { // player settings
336
        KConfigGroupSaver saver(config, "Player");
337
        if(m_sliderAction->getVolumeSlider()) {
338 339
            int volume = config->readNumEntry("Volume", m_sliderAction->getVolumeSlider()->maxValue());
            m_sliderAction->getVolumeSlider()->setValue(volume);
340
        }
Frerich Raabe's avatar
Frerich Raabe committed
341 342
        bool randomPlay = config->readBoolEntry("RandomPlay", false);
        m_randomPlayAction->setChecked(randomPlay);
343

Frerich Raabe's avatar
Frerich Raabe committed
344 345
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
        m_loopPlaylistAction->setChecked(loopPlaylist);
346
    }
347
    { // view settings
348
        KConfigGroupSaver saver(config, "View");
349 350 351 352 353

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

Frerich Raabe's avatar
Frerich Raabe committed
354 355 356
        bool showEditor = config->readBoolEntry("ShowEditor", false);
        m_showEditorAction->setChecked(showEditor);
        m_splitter->slotSetEditorVisible(showEditor);
357
    }
358 359
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
360

Frerich Raabe's avatar
Frerich Raabe committed
361 362
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
363

Frerich Raabe's avatar
Frerich Raabe committed
364 365
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
366

Frerich Raabe's avatar
Frerich Raabe committed
367 368
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
369

Frerich Raabe's avatar
Frerich Raabe committed
370 371
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
372
    }
373

374
    m_restoreOnLoadAction->setChecked(m_restore);
375
    m_toggleSplashAction->setChecked(m_showSplash);
376 377 378 379
}

void JuK::saveConfig()
{
380
    KConfig *config = KGlobal::config();
381
    { // m_player settings
382
        KConfigGroupSaver saver(config, "Player");
383 384
        if(m_sliderAction && m_sliderAction->getVolumeSlider())
            config->writeEntry("Volume", m_sliderAction->getVolumeSlider()->value());
Frerich Raabe's avatar
Frerich Raabe committed
385 386 387 388
        if(m_randomPlayAction)
            config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());
        if(m_loopPlaylistAction)
            config->writeEntry("LoopPlaylist", m_loopPlaylistAction->isChecked());
389
    }
390 391
    { // view settings
        KConfigGroupSaver saver(config, "View");
392

Frerich Raabe's avatar
Frerich Raabe committed
393
        config->writeEntry("ShowEditor", m_showEditorAction->isChecked());
394
        config->writeEntry("ShowSearch", m_showSearchAction->isChecked());
395
    }
396 397
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
Frerich Raabe's avatar
Frerich Raabe committed
398 399 400 401 402 403 404
        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());
405
    }
406
    config->sync();
407 408
}

409
bool JuK::queryExit()
410
{
411
    stop();
412
    delete m_player;
413
    Cache::instance()->save();
414
    saveConfig();
415
    delete m_splitter;
416
    return true;
417 418
}

419 420
bool JuK::queryClose()
{
421
    if(!m_shuttingDown && m_systemTray && m_toggleDockOnCloseAction->isChecked()) {
422 423
	KMessageBox::information(this,
				 i18n("<qt>Closing the main window will keep JuK running in the system tray. "
424
				      "Use Quit from the File menu to quit the application.</qt>"),
425 426 427 428 429 430 431 432
				 i18n("Docking in System Tray"), "hideOnCloseInfo");
	hide();
	return false;
    }
    else
	return true;
}

433 434 435
void JuK::invokeEditSlot( const char *slotName, const char *slot )
{
    QObject *object = focusWidget();
436

437
    if(!object || !slotName || !slot)
Frerich Raabe's avatar
Frerich Raabe committed
438
        return;
439

440 441
    QMetaObject *meta = object->metaObject();
    QStrList l = meta->slotNames(true);
442

443
    if(l.find(slotName) == -1)
Frerich Raabe's avatar
Frerich Raabe committed
444
        return;
445

446 447 448
    connect(this, SIGNAL(signalEdit()), object, slot);
    emit signalEdit();
    disconnect(this, SIGNAL(signalEdit()), object, slot);
449 450
}

451 452 453
QString JuK::playingString() const
{
    QString s;
454

455
    if(m_splitter->playingArtist().isEmpty())
Frerich Raabe's avatar
Frerich Raabe committed
456
        s = m_splitter->playingTrack().simplifyWhiteSpace();
457
    else
Frerich Raabe's avatar
Frerich Raabe committed
458
        s = m_splitter->playingArtist().simplifyWhiteSpace() + " - " + m_splitter->playingTrack().simplifyWhiteSpace();
459 460 461 462

    return s;
}

463 464
void JuK::updatePlaylistInfo()
{
Frerich Raabe's avatar
Frerich Raabe committed
465
    m_statusLabel->setPlaylistInfo(m_splitter->visiblePlaylistName(), m_splitter->selectedPlaylistCount());
466 467 468 469
}

void JuK::play(const QString &file)
{
470
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
Frerich Raabe's avatar
Frerich Raabe committed
471
        return;
472 473 474 475

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

    if(m_player->paused())
Frerich Raabe's avatar
Frerich Raabe committed
476
        m_player->stop();
477

478 479 480 481 482
    m_player->play(file, volume);

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

    if(m_player->playing()) {
483 484 485
        actionCollection()->action("pause")->setEnabled(true);
        actionCollection()->action("stop")->setEnabled(true);
        actionCollection()->action("forward")->setEnabled(true);
486

Frerich Raabe's avatar
Frerich Raabe committed
487
        m_backAction->setEnabled(true);
488

Frerich Raabe's avatar
Frerich Raabe committed
489 490 491
        m_sliderAction->getTrackPositionSlider()->setValue(0);
        m_sliderAction->getTrackPositionSlider()->setEnabled(true);
        m_playTimer->start(m_pollInterval);
492

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

Frerich Raabe's avatar
Frerich Raabe committed
495
        emit signalNewSong(playingString());
496

Frerich Raabe's avatar
Frerich Raabe committed
497 498
        if(m_systemTray)
            m_systemTray->slotPlay();
499 500
    }
    else
Frerich Raabe's avatar
Frerich Raabe committed
501
        stop();
502 503
}

504 505 506 507
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

508
void JuK::slotPlaylistChanged()
509
{
510
    if(m_splitter->collectionListSelected() || !m_splitter->hasListSelected()) {
511 512 513 514
        actionCollection()->action("file_save")->setEnabled(false);
        actionCollection()->action("file_save_as")->setEnabled(false);
        actionCollection()->action("renamePlaylist")->setEnabled(false);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(false);
515 516
    }
    else {
517 518 519 520
        actionCollection()->action("file_save")->setEnabled(true);
        actionCollection()->action("file_save_as")->setEnabled(true);
        actionCollection()->action("renamePlaylist")->setEnabled(true);
        actionCollection()->action("deleteItemPlaylist")->setEnabled(true);
521
    }
522 523 524 525 526
    if(m_splitter->hasListSelected())
        actionCollection()->action("duplicatePlaylist")->setEnabled(true);
    else
        actionCollection()->action("duplicatePlaylist")->setEnabled(false);
    
527 528 529 530

    updatePlaylistInfo();
}

531 532 533 534 535 536 537 538
void JuK::startPlayingPlaylist()
{
    if(m_randomPlayAction->isChecked())
        play(m_splitter->playRandomFile());
    else
        play(m_splitter->playFirstFile());
}

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
////////////////////////////////////////////////////////////////////////////////
// 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()));
}

568
////////////////////////////////////////////////////////////////////////////////
569
// player menu
570 571
////////////////////////////////////////////////////////////////////////////////

572
void JuK::play()
573
{
574
    if(!m_player)
Frerich Raabe's avatar
Frerich Raabe committed
575
    return;
576

577 578
    if(m_player->paused()) {
        m_player->play();
579

580
	// Here, before doing anything, we want to make sure that the m_player did
581 582
	// in fact start.

583
        if(m_player->playing()) {
584 585
            actionCollection()->action("pause")->setEnabled(true);
            actionCollection()->action("stop")->setEnabled(true);
586
            m_playTimer->start(m_pollInterval);
587 588
	    if(m_systemTray)
		m_systemTray->slotPlay();
589 590
        }
    }
591 592
    else if(m_player->playing())
	m_player->seekPosition(0);
593
    else
594
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
595 596
}

597
void JuK::pause()
598
{
599
    if(!m_player)
600 601
	return;

602 603
    m_playTimer->stop();
    m_player->pause();
604
    actionCollection()->action("pause")->setEnabled(false);
605 606
    if(m_systemTray)
	m_systemTray->slotPause();
607 608
}

609
void JuK::stop()
610
{
611
    if(!m_player || !m_sliderAction || !m_sliderAction->getVolumeSlider())
612 613
	return;

614 615
    m_playTimer->stop();
    m_player->stop();
616

617 618 619 620
    actionCollection()->action("pause")->setEnabled(false);
    actionCollection()->action("stop")->setEnabled(false);
    actionCollection()->action("back")->setEnabled(false);
    actionCollection()->action("forward")->setEnabled(false);
621

622 623
    m_sliderAction->getTrackPositionSlider()->setValue(0);
    m_sliderAction->getTrackPositionSlider()->setEnabled(false);
624

625
    m_splitter->stop();
626

627
    m_statusLabel->clear();
628

629 630
    if(m_systemTray)
	m_systemTray->slotStop();
631 632
}

633
void JuK::back()
634
{
635
    play(m_splitter->playPreviousFile(m_randomPlayAction->isChecked()));
636 637
}

638 639
void JuK::back(int howMany)
{
640
    for(--howMany; howMany > 0; --howMany)
641 642 643 644 645 646 647 648 649 650
        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());
}

651
void JuK::forward()
652
{
653
    play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
654 655
}

656
void JuK::seekBack()
657 658 659 660 661 662
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMAX(m_sliderAction->getTrackPositionSlider()->minValue(), position - 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

663
void JuK::seekForward()
664 665 666 667 668 669
{
    int position = m_sliderAction->getTrackPositionSlider()->value();
    position = QMIN(m_sliderAction->getTrackPositionSlider()->maxValue(), position + 10);
    emit m_sliderAction->getTrackPositionSlider()->setValue(position);
}

670 671 672 673
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

674
void JuK::slotShowGenreListEditor()
675 676 677 678
{
    GenreListEditor * editor = new GenreListEditor();
    editor->exec();
}
679

680
void JuK::slotToggleSystemTray(bool enabled)
681
{
682
    if(enabled && !m_systemTray)
683
	setupSystemTray();
684 685 686
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
687
	m_toggleDockOnCloseAction->setEnabled(false);
688 689 690
    }
}

691
void JuK::slotSetOutput(int output)
692
{
693
    stop();
694 695
    delete m_player;
    m_player = Player::createPlayer(output);
696 697
}

698 699 700 701 702
void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, actionCollection(), this);
}

703
////////////////////////////////////////////////////////////////////////////////
704
// additional player slots
705 706
////////////////////////////////////////////////////////////////////////////////

707
void JuK::slotTrackPositionSliderClicked()
708
{
709
    m_trackPositionDragging = true;
710 711
}

712
void JuK::slotTrackPositionSliderReleased()
713
{
714
    if(!m_player)
715 716
	return;

717 718
    m_trackPositionDragging = false;
    m_player->seekPosition(m_sliderAction->getTrackPositionSlider()->value());
719 720
}

721
void JuK::slotTrackPositionSliderUpdate(int position)
722
{
723
    if(!m_player)
724 725
	return;

726 727
    if(m_player->playing() && !m_trackPositionDragging && !m_noSeek)
        m_player->seekPosition(position);
728 729 730 731 732 733 734 735 736 737

    // 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);
    }
738 739
}

740
void JuK::playPause()
741 742 743 744 745
{
    if(!m_player)
	return;

    if(m_player->playing())
746
	pause();
747
    else
748
	play();
749 750
}

751
void JuK::volumeUp()
752 753 754 755
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() +
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% up
756
	setVolume(volume);
757 758 759 760
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

761
void JuK::volumeDown()
762 763 764 765
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
	int volume = m_sliderAction->getVolumeSlider()->value() -
	  m_sliderAction->getVolumeSlider()->maxValue() / 25; // 4% down
766
	setVolume(volume);
767 768 769 770
	m_sliderAction->getVolumeSlider()->setValue(volume);
    }
}

771
void JuK::volumeMute()
772 773
{
    if(m_sliderAction && m_sliderAction->getVolumeSlider()) {
Scott Wheeler's avatar
Scott Wheeler committed
774
	if(m_muted)
775
	    setVolume(m_sliderAction->getVolumeSlider()->value());
776
	else
777 778
	    setVolume(0);
	    m_muted = !m_muted;
779 780 781
    }
}

782 783
// This method is called when the play timer has expired.

784
void JuK::slotPollPlay()
785
{
786
    if(!m_player)
787 788
	return;

789
    // Our locking mechanism.  Since this method adjusts the play slider, we
790
    // want to make sure that our adjustments
791
    m_noSeek = true;
792

793
    if(!m_player->playing()) {
794

795
        m_playTimer->stop();
796

797
	play(m_splitter->playNextFile(m_randomPlayAction->isChecked(), m_loopPlaylistAction->isChecked()));
798
    }
799 800 801 802
    else if(!m_trackPositionDragging) {
        m_sliderAction->getTrackPositionSlider()->setValue(m_player->position());
	m_statusLabel->setItemTotalTime(m_player->totalTime());
	m_statusLabel->setItemCurrentTime(m_player->currentTime());
803 804 805
    }

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

810
    if(m_player->playing() && m_player->totalTime() > 0 && float(m_player->totalTime() - m_player->currentTime()) < m_pollInterval * 2)
811
        m_playTimer->changeInterval(50);
812

813
    m_noSeek = false;
814 815
}

816
void JuK::setVolume(int volume)
817
{
818 819 820
    if(m_player && m_sliderAction && m_sliderAction->getVolumeSlider() &&
       m_sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && m_sliderAction->getVolumeSlider()->maxValue() >= volume)
821
    {
822
        m_player->setVolume(float(volume) / float(m_sliderAction->getVolumeSlider()->maxValue()));
823 824
    }
}
825

826 827 828 829 830 831
void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg dlg(this);
    dlg.exec();
}

832 833 834 835
void JuK::openFile(const QString &file)
{
    m_splitter->open(file);
}
836

837 838 839 840 841 842 843 844 845 846
KAction *JuK::createSplitterAction(const QString &text, const char *slot, const char *name, 
                               const QString &pix, const KShortcut &shortcut)
{
    KAction *action;

    if(pix.isNull())
	action = new KAction(text, shortcut, actionCollection(), name);
    else
	action = new KAction(text, pix, shortcut, actionCollection(), name);

847
    m_splitterConnections.append(SplitterConnection(action, slot));
848 849 850 851
    
    return action;
}

852
#include "juk.moc"