juk.cpp 13 KB
Newer Older
1 2 3 4 5 6
/***************************************************************************
                          juk.cpp  -  description
                             -------------------
    begin                : Mon Feb  4 23:40:41 EST 2002
    copyright            : (C) 2002 by Scott Wheeler
    email                : scott@slackorama.net
7
***************************************************************************/
8 9 10 11 12 13 14 15 16 17 18

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

#include <klocale.h>
19
#include <kiconloader.h>
20
#include <kcmdlineargs.h>
21 22
#include <kdebug.h>

23 24
#include <qinputdialog.h>

25
#include "juk.h"
26 27 28
#include "playlist.h"
#include "playlistsplitter.h"
#include "collectionlist.h"
29
#include "slideraction.h"
30 31 32 33 34

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

35
JuK::JuK(QWidget *parent, const char *name) : KMainWindow(parent, name, WDestructiveClose)
36
{
37 38
    // Expect segfaults if you change this order.

39
    setupLayout();
40
    setupActions();
41 42
    setupPlayer();
    readConfig();
43
    processArgs();
44 45 46 47
}

JuK::~JuK()
{
48
    delete(playTimer);
49 50 51 52 53 54
}

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

55 56
void JuK::setupLayout()
{
57
    splitter = new PlaylistSplitter(this, "playlistSplitter");
58 59 60 61 62 63 64 65
    setCentralWidget(splitter);

    // playlist item activation connection
    connect(splitter, SIGNAL(playlistDoubleClicked(QListViewItem *)), this, SLOT(playItem(QListViewItem *)));

    splitter->setFocus();
}

66 67
void JuK::setupActions()
{
68
    // file menu
69 70 71 72
    KStdAction::open(splitter, SLOT(open()), actionCollection());
    new KAction(i18n("Open &Directory..."), "fileopen", 0, splitter, SLOT(openDirectory()), actionCollection(), "openDirectory");
    KStdAction::save(splitter, SLOT(save()), actionCollection());
    new KAction(i18n("Delete"), "editdelete", 0, this, SLOT(remove()), actionCollection(), "remove");
73 74 75 76 77 78
    KStdAction::quit(this, SLOT(quit()), actionCollection());

    // edit menu
    KStdAction::cut(this, SLOT(cut()), actionCollection());
    KStdAction::copy(this, SLOT(copy()), actionCollection());
    KStdAction::paste(this, SLOT(paste()), actionCollection());
79
    KStdAction::selectAll(splitter, SLOT(selectAll()), actionCollection());
80

81 82
    // view menu
    showEditorAction = new KToggleAction(i18n("Show Tag Editor"), 0, actionCollection(), "showEditor");
83 84
    connect(showEditorAction, SIGNAL(toggled(bool)), splitter, SLOT(setEditorVisible(bool)));
    KStdAction::redisplay(splitter, SLOT(refresh()), actionCollection());
85

86
    // play menu
87
    randomPlayAction = new KToggleAction(i18n("Random Play"), 0, actionCollection(), "randomPlay");
88 89 90 91
    playAction = new KAction(i18n("&Play"), "1rightarrow", 0, this, SLOT(playFile()), actionCollection(), "playFile");
    pauseAction = new KAction(i18n("P&ause"), "player_pause", 0, this, SLOT(pauseFile()), actionCollection(), "pauseFile");
    stopAction = new KAction(i18n("&Stop"), "player_stop", 0, this, SLOT(stopFile()), actionCollection(), "stopFile");

92
    // playlist menu
93 94 95 96 97 98 99 100 101 102 103 104 105 106
    new KAction(i18n("New..."), "filenew", 0, splitter, SLOT(createPlaylist()), actionCollection(), "createPlaylist");
    new KAction(i18n("Open..."), "fileopen", 0, splitter, SLOT(openPlaylist()), actionCollection(), "openPlaylist");

    savePlaylistAction = new KAction(i18n("Save"), "filesave", 0, splitter, SLOT(savePlaylist()), actionCollection(), "savePlaylist");
    saveAsPlaylistAction = new KAction(i18n("Save As..."), "filesaveas", 0, splitter, SLOT(saveAsPlaylist()), 
				       actionCollection(), "saveAsPlaylist");
    renamePlaylistAction = new KAction(i18n("Rename..."), 0, splitter, SLOT(renamePlaylist()), 
				       actionCollection(), "renamePlaylist");
    new KAction(i18n("Duplicate..."), "editcopy", 0, splitter, SLOT(duplicatePlaylist()), actionCollection(), "duplicatePlaylist");
    deleteItemPlaylistAction = new KAction(i18n("Delete"), "editdelete", 0, splitter, SLOT(deleteItemPlaylist()), actionCollection(), "deleteItemPlaylist");
    
    playlistChanged(0);
    connect(splitter, SIGNAL(playlistChanged(Playlist *)), this, SLOT(playlistChanged(Playlist *)));

107

108 109 110 111
    // just in the toolbar
    sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");

    createGUI();
112 113 114 115

    // set the slider to the proper orientation and make it stay that way
    sliderAction->updateOrientation();
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), sliderAction, SLOT(updateOrientation(QDockWindow *)));
116 117 118 119
}

void JuK::setupPlayer()
{
120 121
    trackPositionDragging = false;
    noSeek = false;
122 123 124
    pauseAction->setEnabled(false);
    stopAction->setEnabled(false);

125
    playTimer = new QTimer(this);
126 127 128 129 130 131 132
    connect(playTimer, SIGNAL(timeout()), this, SLOT(pollPlay()));

    if(sliderAction && sliderAction->getTrackPositionSlider() && sliderAction->getVolumeSlider()) {
        connect(sliderAction->getTrackPositionSlider(), SIGNAL(valueChanged(int)), this, SLOT(trackPositionSliderUpdate(int)));
        connect(sliderAction->getTrackPositionSlider(), SIGNAL(sliderPressed()), this, SLOT(trackPositionSliderClick()));
        connect(sliderAction->getTrackPositionSlider(), SIGNAL(sliderReleased()), this, SLOT(trackPositionSliderRelease()));
        sliderAction->getTrackPositionSlider()->setEnabled(false);
133

134 135
        connect(sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
    }
136 137
}

138 139 140 141 142 143 144 145
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
    
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

146
    splitter->open(files);
147 148
}

149 150
void JuK::readConfig()
{
151 152 153
    // Automagically save and restore many window settings.
    setAutoSaveSettings();

154 155 156 157 158 159 160
    KConfig *config = KGlobal::config();
    { // player settings
        KConfigGroupSaver saver(config, "Player");
        if(sliderAction && sliderAction->getVolumeSlider()) {
            int volume = config->readNumEntry("Volume", sliderAction->getVolumeSlider()->maxValue());
            sliderAction->getVolumeSlider()->setValue(volume);
        }
161 162 163 164
	if(randomPlayAction) {
	    bool randomPlay = config->readBoolEntry("RandomPlay", false);
	    randomPlayAction->setChecked(randomPlay);
	}
165
    }
166 167 168 169 170 171
    { // view Settings
        KConfigGroupSaver saver(config, "View");
	bool showEditor = config->readBoolEntry("ShowEditor", true);
	showEditorAction->setChecked(showEditor);
	splitter->setEditorVisible(showEditor);
    }
172 173 174 175
}

void JuK::saveConfig()
{
176 177 178 179 180
    KConfig *config = KGlobal::config();
    { // player settings
        KConfigGroupSaver saver(config, "Player");
        if(sliderAction && sliderAction->getVolumeSlider())
            config->writeEntry("Volume", sliderAction->getVolumeSlider()->value());
181 182
	if(randomPlayAction)
	    config->writeEntry("RandomPlay", randomPlayAction->isChecked());
183
    }
184 185 186 187
    { // view settings
        KConfigGroupSaver saver(config, "View");
	config->writeEntry("ShowEditor", showEditorAction->isChecked());
    }
188 189
}

190 191 192
bool JuK::queryClose()
{
    saveConfig();
193
    delete(splitter);
194 195 196
    return(true);
}

197 198 199 200
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

201
void JuK::playlistChanged(Playlist *list)
202
{
203 204 205 206 207 208 209 210 211 212 213 214
    if(!list || list == CollectionList::instance()) {
	savePlaylistAction->setEnabled(false);
	saveAsPlaylistAction->setEnabled(false);
	renamePlaylistAction->setEnabled(false);
	deleteItemPlaylistAction->setEnabled(false);	
    }
    else {
	savePlaylistAction->setEnabled(true);
	saveAsPlaylistAction->setEnabled(true);
	renamePlaylistAction->setEnabled(true);
	deleteItemPlaylistAction->setEnabled(true);
    }
215 216
}

217 218 219
////////////////////////////////////////////////////////////////////////////////
// private action slot implementations - file menu
////////////////////////////////////////////////////////////////////////////////
220

221
void JuK::remove()
222
{
223
    PlaylistItemList items(splitter->playlistSelection());
224
    PlaylistItem *item = items.first();
225
    while(item) {
226 227 228
	if(item == playingItem)
	    playingItem = 0;
	item = items.next();
229
    }
230 231
    
    splitter->remove();
232 233
}

234 235
void JuK::quit()
{
236 237 238
    // delete(this);
    // kapp->quit();
    close();
239 240
}

241 242 243 244 245 246
////////////////////////////////////////////////////////////////////////////////
// edit menu
////////////////////////////////////////////////////////////////////////////////

void JuK::cut()
{
247
    PlaylistItemList items = splitter->playlistSelection();
Scott Wheeler's avatar
Scott Wheeler committed
248

249 250 251 252 253
    PlaylistItem *item = items.first();
    while(item) {
	if(item == playingItem)
	    playingItem = 0;
	item = items.next();
254 255
    }

256
    splitter->clearSelectedItems();
257 258
}

259 260 261 262 263 264
////////////////////////////////////////////////////////////////////////////////
// player menu
////////////////////////////////////////////////////////////////////////////////

void JuK::playFile()
{
265 266 267 268 269 270 271 272 273
    if(player.paused()) {
        player.play();
        if(player.playing()) {
            playAction->setEnabled(false);
            pauseAction->setEnabled(true);
            stopAction->setEnabled(true);
            playTimer->start(pollInterval);
        }
    }
274
    else if(splitter) {
275
        PlaylistItemList items = splitter->playlistSelection();
276
        if(items.count() > 0)
277
            playItem(items.at(0));
278
        else
279
            playItem(splitter->playlistFirstItem());
280
    }
281 282 283 284
}

void JuK::pauseFile()
{
285 286 287 288
    playTimer->stop();
    player.pause();
    playAction->setEnabled(true);
    pauseAction->setEnabled(false);
289 290 291 292
}

void JuK::stopFile()
{
293 294 295 296 297 298 299
    playTimer->stop();
    player.stop();
    playAction->setEnabled(true);
    pauseAction->setEnabled(false);
    stopAction->setEnabled(false);
    sliderAction->getTrackPositionSlider()->setValue(0);
    sliderAction->getTrackPositionSlider()->setEnabled(false);
300 301
    if(playingItem)
        playingItem->setPixmap(0, 0);
302 303
}

304 305 306 307
////////////////////////////////////////////////////////////////////////////////
// additional player slots
////////////////////////////////////////////////////////////////////////////////

308 309
void JuK::trackPositionSliderClick()
{
310
    trackPositionDragging = true;
311 312 313 314
}

void JuK::trackPositionSliderRelease()
{
315
    trackPositionDragging = false;
316
    player.seekPosition(sliderAction->getTrackPositionSlider()->value());
317 318 319 320
}

void JuK::trackPositionSliderUpdate(int position)
{
321
    if(player.playing() && !trackPositionDragging && !noSeek)
322
        player.seekPosition(position);
323 324 325 326
}

void JuK::pollPlay()
{
327 328
    noSeek = true;
    if(!player.playing()) {
329

330
        playTimer->stop();
331

332
        if(player.paused())
333
            pauseFile();
334
        else if(playingItem) {
335

336
	    PlaylistItem *next = Playlist::nextItem(playingItem, randomPlayAction->isChecked());
337 338
	    playingItem->setPixmap(0, 0);

339 340 341 342 343 344 345 346 347 348 349 350
	    if(next) {
		playingItem = next;
		sliderAction->getTrackPositionSlider()->setValue(0);
		player.play(playingItem->absFilePath(), player.getVolume());
		if(player.playing()) {
		    playTimer->start(pollInterval);
		    playingItem->setPixmap(0, QPixmap(UserIcon("playing")));
		}
	    }
	}
	else
	    stopFile();
351
    }
352
    else if(!trackPositionDragging)
353
        sliderAction->getTrackPositionSlider()->setValue(player.position());
354

355 356
    if(player.playing() && float(player.totalTime() - player.currentTime()) < pollInterval * 2)
        playTimer->changeInterval(50);
357

358
    noSeek = false;
359 360 361 362
}

void JuK::setVolume(int volume)
{
363 364 365
    if(sliderAction && sliderAction->getVolumeSlider() &&
       sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && sliderAction->getVolumeSlider()->maxValue() >= volume)
366
    {
367
        player.setVolume(float(volume) / float(sliderAction->getVolumeSlider()->maxValue()));
368 369
    }
}
370 371 372

void JuK::playItem(QListViewItem *item)
{
373
    PlaylistItem *fileListItem = dynamic_cast<PlaylistItem *>(item);
374 375
    if(fileListItem)
        playItem(fileListItem);
376 377
}

378
void JuK::playItem(PlaylistItem *item)
379
{
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    if(player.playing() || player.paused())
        stopFile();

    if(item) {
        playingItem = item;
        float volume = float(sliderAction->getVolumeSlider()->value()) / float(sliderAction->getVolumeSlider()->maxValue());
        player.play(playingItem->absFilePath(), volume);
        if(player.playing()) {
            playAction->setEnabled(false);
            pauseAction->setEnabled(true);
            stopAction->setEnabled(true);
            sliderAction->getTrackPositionSlider()->setEnabled(true);
            playingItem->setPixmap(0, QPixmap(UserIcon("playing")));
            playTimer->start(pollInterval);
        }
395 396
    }
}
397

398
#include "juk.moc"