juk.cpp 13.6 KB
Newer Older
1 2
/***************************************************************************
    begin                : Mon Feb  4 23:40:41 EST 2002
3
    copyright            : (C) 2002 - 2004 by Scott Wheeler
4
    email                : wheeler@kde.org
5
***************************************************************************/
6 7 8 9 10 11 12 13 14 15

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

16 17
#include <config.h>

18 19 20 21 22 23
#include <kcmdlineargs.h>
#include <kstatusbar.h>
#include <kdebug.h>
#include <kmessagebox.h>


24 25 26 27 28 29 30
#include "juk.h"
#include "slideraction.h"
#include "statuslabel.h"
#include "splashscreen.h"
#include "systemtray.h"
#include "keydialog.h"
#include "tagguesserconfigdlg.h"
31
#include "filerenamerconfigdlg.h"
32
#include "actioncollection.h"
33
#include "cache.h"
34 35
#include "playlistsplitter.h"
#include "collectionlist.h"
36

37 38
using namespace ActionCollection;

39 40 41 42
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

Scott Wheeler's avatar
Scott Wheeler committed
43
JuK::JuK(QWidget *parent, const char *name) :
Scott Wheeler's avatar
Scott Wheeler committed
44
    KMainWindow(parent, name, WDestructiveClose),
45
    m_player(PlayerManager::instance()),
46
    m_shuttingDown(false)
47
{
48 49
    // Expect segfaults if you change this order.

50
    readSettings();
51

52
    if(m_showSplash && !m_startDocked) {
53 54 55 56
	SplashScreen::instance()->show();
	kapp->processEvents();
    }

57
    setupActions();
58
    setupLayout();
59
    createGUI();
60
    readConfig();
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

    m_sliderAction->slotUpdateOrientation();
69 70 71 72
}

JuK::~JuK()
{
73

74 75
}

76 77 78 79 80
KActionCollection *JuK::actionCollection() const
{
    return ActionCollection::actions();
}

81 82 83 84
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

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

90 91
    m_statusLabel = new StatusLabel(m_splitter->playlist(), statusBar());
    statusBar()->addWidget(m_statusLabel, 1);
92 93
    PlayerManager::instance()->setStatusLabel(m_statusLabel);

94
    m_splitter->setFocus();
95
    resize(750, 500);
96 97
}

98 99
void JuK::setupActions()
{
100 101 102 103 104 105
    KStdAction::quit(this, SLOT(slotQuit()), actions());
    KStdAction::cut(kapp,   SLOT(cut()),   actions());
    KStdAction::copy(kapp,  SLOT(copy()),  actions());
    KStdAction::paste(kapp, SLOT(paste()), actions());
    KStdAction::clear(kapp, SLOT(clear()), actions());
    KStdAction::selectAll(kapp, SLOT(selectAll()), actions());
106

107 108
    m_showHistoryAction = new KToggleAction(i18n("Show &History"),    "history",  0, actions(), "showHistory");
    m_randomPlayAction =  new KToggleAction(i18n("&Random Play"),                 0, actions(), "randomPlay");
109

Stephan Binner's avatar
Stephan Binner committed
110
    m_showHistoryAction->setCheckedState(i18n("Hide &History"));
111

112 113 114
    new KAction(i18n("&Play"),  "player_play",  0, m_player, SLOT(play()),  actions(), "play");
    new KAction(i18n("P&ause"), "player_pause", 0, m_player, SLOT(pause()), actions(), "pause");
    new KAction(i18n("&Stop"),  "player_stop",  0, m_player, SLOT(stop()),  actions(), "stop");
Scott Wheeler's avatar
Scott Wheeler committed
115

116 117 118
    // m_backAction = new KToolBarPopupAction(i18n("Previous &Track"), "player_start", 0,
    //                                        this, SLOT(back()), actions(), "back");
    // TODO: switch this back to being a popup action
119

120
    new KAction(i18n("Previous &Track"), "player_start", 0, m_player, SLOT(back()),    actions(), "back");
121
    new KAction(i18n("&Next Track"),     "player_end",   0, m_player, SLOT(forward()), actions(), "forward");
122

123 124 125
    new KToggleAction(i18n("&Loop Playlist"), 0, 0, actions(), "loopPlaylist");

    // the following are not visible by default
126

127 128 129 130 131 132
    new KAction(i18n("Mute"),         "mute",        0, m_player, SLOT(mute()),        actions(), "mute");
    new KAction(i18n("Volume Up"),    "volumeUp",    0, m_player, SLOT(volumeUp()),    actions(), "volumeUp");
    new KAction(i18n("Volume Down"),  "volumeDown",  0, m_player, SLOT(volumeDown()),  actions(), "volumeDown");
    new KAction(i18n("Play / Pause"), "playPause",   0, m_player, SLOT(playPause()),   actions(), "playPause");
    new KAction(i18n("Seek Forward"), "seekForward", 0, m_player, SLOT(seekForward()), actions(), "seekForward");
    new KAction(i18n("Seek Back"),    "seekBack",    0, m_player, SLOT(seekBack()),    actions(), "seekBack");
Stephan Binner's avatar
Stephan Binner committed
133

134

135
    //////////////////////////////////////////////////
136
    // settings menu
137 138
    //////////////////////////////////////////////////

139
    setStandardToolBarMenuEnabled(true);
140

Scott Wheeler's avatar
Scott Wheeler committed
141
    m_toggleSplashAction =
142
	new KToggleAction(i18n("Show Splash Screen on Startup"),
Scott Wheeler's avatar
Scott Wheeler committed
143
			  KShortcut(), actions(), "showSplashScreen");
Stephan Binner's avatar
Stephan Binner committed
144
    m_toggleSplashAction->setCheckedState(i18n("Hide Splash Screen on Startup"));
Scott Wheeler's avatar
Scott Wheeler committed
145 146 147
    m_toggleSystemTrayAction =
	new KToggleAction(i18n("&Dock in System Tray"),
			  KShortcut(), actions(), "toggleSystemTray");
Stephan Binner's avatar
Stephan Binner committed
148
    m_toggleDockOnCloseAction =
Scott Wheeler's avatar
Scott Wheeler committed
149 150 151
	new KToggleAction(i18n("&Stay in System Tray on Close"),
			  KShortcut(), actions(), "dockOnClose");
    m_togglePopupsAction =
152
	new KToggleAction(i18n("Popup &Track Announcement"),
Scott Wheeler's avatar
Scott Wheeler committed
153
			  KShortcut(), this, 0, actions(), "togglePopups");
154

Scott Wheeler's avatar
Scott Wheeler committed
155 156
    connect(m_toggleSystemTrayAction, SIGNAL(toggled(bool)),
	    this, SLOT(slotToggleSystemTray(bool)));
157

Scott Wheeler's avatar
Scott Wheeler committed
158

159
    m_outputSelectAction = PlayerManager::playerSelectAction(actions());
160

161
    if(m_outputSelectAction)
162
        m_outputSelectAction->setCurrentItem(0);
163

Scott Wheeler's avatar
Scott Wheeler committed
164
    new KAction(i18n("&Tag Guesser..."), 0, 0, this, SLOT(slotConfigureTagGuesser()),
165
		actions(), "tagGuesserConfig");
166

167
    new KAction(i18n("&File Renamer..."), 0, 0, this, SLOT(slotConfigureFileRenamer()),
168
		actions(), "fileRenamerConfig");
169

170
    KStdAction::keyBindings(this, SLOT(slotEditKeys()), actions());
171

172
    //////////////////////////////////////////////////
173
    // just in the toolbar
174 175
    //////////////////////////////////////////////////

176
    m_sliderAction = new SliderAction(i18n("Track Position"), actions(),
Scott Wheeler's avatar
Scott Wheeler committed
177
				      "trackPositionAction");
178 179
}

180
void JuK::setupSystemTray()
181
{
182
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
Scott Wheeler's avatar
Scott Wheeler committed
183 184
	m_systemTray = new SystemTray(this, "systemTray");
	m_systemTray->show();
185

Scott Wheeler's avatar
Scott Wheeler committed
186
	m_toggleDockOnCloseAction->setEnabled(true);
187
	m_togglePopupsAction->setEnabled(true);
188

Scott Wheeler's avatar
Scott Wheeler committed
189
	connect(m_systemTray, SIGNAL(quitSelected()), this, SLOT(slotQuit()));
190
    }
191
    else {
Scott Wheeler's avatar
Scott Wheeler committed
192 193
	m_systemTray = 0;
	m_toggleDockOnCloseAction->setEnabled(false);
194
	m_togglePopupsAction->setEnabled(false);
195
    }
196 197
}

198 199 200
void JuK::setupGlobalAccels()
{
    m_accel = new KGlobalAccel(this);
201

202 203 204 205 206 207 208 209 210
    KeyDialog::insert(m_accel, "PlayPause",   i18n("Play / Pause"), action("playPause"),   SLOT(activate()));
    KeyDialog::insert(m_accel, "Stop",        i18n("Stop Playing"), action("stop"),        SLOT(activate()));
    KeyDialog::insert(m_accel, "Back",        i18n("Back"),         action("back"),        SLOT(activate()));
    KeyDialog::insert(m_accel, "Forward",     i18n("Forward"),      action("forward"),     SLOT(activate()));
    KeyDialog::insert(m_accel, "SeekBack",    i18n("Seek Back"),    action("seekBack"),    SLOT(activate()));
    KeyDialog::insert(m_accel, "SeekForward", i18n("Seek Forward"), action("seekForward"), SLOT(activate()));
    KeyDialog::insert(m_accel, "VolumeUp",    i18n("Volume Up"),    action("volumeUp"),    SLOT(activate()));
    KeyDialog::insert(m_accel, "VolumeDown",  i18n("Volume Down"),  action("volumeDown"),  SLOT(activate()));
    KeyDialog::insert(m_accel, "Mute",        i18n("Mute"),         action("mute"),        SLOT(activate()));
211
    KeyDialog::insert(m_accel, "ShowHide",    i18n("Show / Hide"),  this,                  SLOT(slotShowHide()));
212

213 214 215 216 217
    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

218 219 220 221
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
222

223
    for(int i = 0; i < args->count(); i++)
224
        files.append(args->arg(i));
225

226 227
    // TODO: make this work again
    // m_splitter->open(files);
228 229
}

230 231 232
void JuK::keyPressEvent(QKeyEvent *e)
{
    if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast)
233
        e->accept();
234 235 236
    KMainWindow::keyPressEvent(e);
}

237 238 239 240 241 242 243 244 245
/**
 * 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");
246
        m_showSplash = config->readBoolEntry("ShowSplashScreen", true);
247
        m_startDocked = config->readBoolEntry("StartDocked", false);
248 249 250
    }
}

251 252
void JuK::readConfig()
{
253
    // Automagically save and m_restore many window settings.
254 255
    setAutoSaveSettings();

256
    KConfig *config = KGlobal::config();
257
    { // player settings
258
        KConfigGroupSaver saver(config, "Player");
259 260
        if(m_sliderAction->volumeSlider()) {
	    int maxVolume = m_sliderAction->volumeSlider()->maxValue();
Scott Wheeler's avatar
Scott Wheeler committed
261
	    int volume = config->readNumEntry("Volume", maxVolume);
262
            m_sliderAction->volumeSlider()->setVolume(volume);
263
        }
264 265
        bool randomPlay = config->readBoolEntry("RandomPlay", false);
        m_randomPlayAction->setChecked(randomPlay);
266

267
        bool loopPlaylist = config->readBoolEntry("LoopPlaylist", false);
268
        ActionCollection::action<KToggleAction>("loopPlaylist")->setChecked(loopPlaylist);
269
    }
270
    { // view settings
271
        KConfigGroupSaver saver(config, "View");
272

273 274 275
	// The history list will actually be created by the playlist restoration
	// code, but we want to remember the checkbox's setting and hope that
	// it's in synch with the code that does the real work.
276

277 278
	bool showHistory = config->readBoolEntry("ShowHistory", false);
	m_showHistoryAction->setChecked(showHistory);
279
    }
280 281
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
282

283 284
        bool dockInSystemTray = config->readBoolEntry("DockInSystemTray", true);
        m_toggleSystemTrayAction->setChecked(dockInSystemTray);
285

286 287
        bool dockOnClose = config->readBoolEntry("DockOnClose", true);
        m_toggleDockOnCloseAction->setChecked(dockOnClose);
288

289 290
        bool showPopups = config->readBoolEntry("TrackPopup", false);
        m_togglePopupsAction->setChecked(showPopups);
291

292 293
        if(m_outputSelectAction)
            m_outputSelectAction->setCurrentItem(config->readNumEntry("MediaSystem", 0));
294
    }
295

296
    m_toggleSplashAction->setChecked(m_showSplash);
297 298 299 300
}

void JuK::saveConfig()
{
301
    KConfig *config = KGlobal::config();
302
    { // player settings
303
        KConfigGroupSaver saver(config, "Player");
304
	config->writeEntry("Volume", m_sliderAction->volumeSlider()->volume());
305 306 307 308
	config->writeEntry("RandomPlay", m_randomPlayAction->isChecked());

	KToggleAction *a = ActionCollection::action<KToggleAction>("loopPlaylist");
	config->writeEntry("LoopPlaylist", a->isChecked());
309
    }
310 311
    { // view settings
        KConfigGroupSaver saver(config, "View");
312
	config->writeEntry("ShowHistory", m_showHistoryAction->isChecked());
313
    }
314 315
    { // general settings
        KConfigGroupSaver saver(config, "Settings");
316
        config->writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
317
        config->writeEntry("StartDocked", m_startDocked);
318 319 320 321 322
        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());
323
    }
324
    config->sync();
325 326
}

327
bool JuK::queryExit()
328
{
329 330
    m_startDocked = !isVisible();

331
    hide();
332
    action("stop")->activate();
333 334 335
    delete m_systemTray;
    m_systemTray = 0;

336
    Cache::instance()->save();
337
    saveConfig();
338
    delete m_splitter;
339
    return true;
340 341
}

342 343
bool JuK::queryClose()
{
344 345 346 347 348
    if(!m_shuttingDown &&
       !kapp->sessionSaving() &&
       m_systemTray &&
       m_toggleDockOnCloseAction->isChecked())
    {
349
	KMessageBox::information(this,
Scott Wheeler's avatar
Scott Wheeler committed
350 351 352
	    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");
353 354 355 356 357 358 359
	hide();
	return false;
    }
    else
	return true;
}

360 361 362 363
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

364 365 366 367 368
void JuK::slotShowHide()
{
    setShown(!isShown());
}

369 370 371 372 373
void JuK::slotQuit()
{
    kapp->quit();
}

374 375 376 377
////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

378
void JuK::slotToggleSystemTray(bool enabled)
379
{
380
    if(enabled && !m_systemTray)
381
	setupSystemTray();
382 383 384
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
385
	m_toggleDockOnCloseAction->setEnabled(false);
386
	m_togglePopupsAction->setEnabled(false);
387 388 389
    }
}

390 391
void JuK::slotEditKeys()
{
392
    KeyDialog::configure(m_accel, actions(), this);
393 394
}

395 396
void JuK::slotConfigureTagGuesser()
{
397
    TagGuesserConfigDlg(this).exec();
398 399
}

400 401
void JuK::slotConfigureFileRenamer()
{
402
    FileRenamerConfigDlg(this).exec();
403 404
}

405
#include "juk.moc"