juk.cpp 12.3 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 19

/***************************************************************************
 *                                                                         *
 *   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>
#include <kfiledialog.h>
20
#include <kiconloader.h>
21
#include <kcmdlineargs.h>
22 23
#include <kdebug.h>

24 25
#include <qinputdialog.h>

26 27 28 29 30 31 32 33
#include "juk.h"

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

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

36 37 38 39
    setupActions();
    setupLayout();
    setupPlayer();
    readConfig();
40
    processArgs();
41 42 43 44
}

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

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

void JuK::setupActions()
{
55 56 57 58
    // file menu
    KStdAction::open(this, SLOT(openFile()), actionCollection());
    (void) new KAction(i18n("Open &Directory..."), "fileopen", 0, this, SLOT(openDirectory()), actionCollection(), "openDirectory");
    KStdAction::save(this, SLOT(saveFile()), actionCollection());
59
    (void) new KAction(i18n("Delete"), "edittrash", 0, this, SLOT(remove()), actionCollection(), "remove");
60 61 62 63 64 65 66 67
    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());
    KStdAction::selectAll(this, SLOT(selectAll()), actionCollection());

68 69 70
    // view menu
    showEditorAction = new KToggleAction(i18n("Show Tag Editor"), 0, actionCollection(), "showEditor");

71 72 73 74 75
    // play menu
    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");

76 77 78
    // playlist menu
    (void) new KAction(i18n("New Playlist..."), "filenew", 0, this, SLOT(createPlaylist()), actionCollection(), "createPlaylist");

79 80 81 82
    // just in the toolbar
    sliderAction = new SliderAction(i18n("Track Position"), actionCollection(), "trackPositionAction");

    createGUI();
83 84 85 86
}

void JuK::setupLayout()
{
87
    // automagically save and restore settings
88
    setAutoSaveSettings();
89

90 91
    splitter = new PlaylistSplitter(this, "playlistSplitter");
    setCentralWidget(splitter);
92
    connect(showEditorAction, SIGNAL(toggled(bool)), splitter, SLOT(setEditorVisible(bool)));
93

94 95 96
    // set the slider to the proper orientation and make it stay that way
    sliderAction->updateOrientation();
    connect(this, SIGNAL(dockWindowPositionChanged(QDockWindow *)), sliderAction, SLOT(updateOrientation(QDockWindow *)));
97

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

    splitter->setFocus();
102 103 104 105
}

void JuK::setupPlayer()
{
106 107
    trackPositionDragging = false;
    noSeek = false;
108 109 110 111 112 113 114 115 116 117 118
    pauseAction->setEnabled(false);
    stopAction->setEnabled(false);

    playTimer=new QTimer(this);
    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);
119

120 121
        connect(sliderAction->getVolumeSlider(), SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
    }
122 123
}

124 125 126 127 128 129 130 131
void JuK::processArgs()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    QStringList files;
    
    for(int i = 0; i < args->count(); i++)
	files.append(args->arg(i));

132
    splitter->open(files);
133 134
}

135 136
void JuK::readConfig()
{
137 138 139 140 141 142 143
    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);
        }
144
    }
145 146 147 148 149 150
    { // view Settings
        KConfigGroupSaver saver(config, "View");
	bool showEditor = config->readBoolEntry("ShowEditor", true);
	showEditorAction->setChecked(showEditor);
	splitter->setEditorVisible(showEditor);
    }
151 152 153 154
}

void JuK::saveConfig()
{
155 156 157 158 159 160
    KConfig *config = KGlobal::config();
    { // player settings
        KConfigGroupSaver saver(config, "Player");
        if(sliderAction && sliderAction->getVolumeSlider())
            config->writeEntry("Volume", sliderAction->getVolumeSlider()->value());
    }
161 162 163 164
    { // view settings
        KConfigGroupSaver saver(config, "View");
	config->writeEntry("ShowEditor", showEditorAction->isChecked());
    }
165 166
}

167 168 169 170 171 172 173 174 175 176 177 178
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// private action slot implementations - file menu
////////////////////////////////////////////////////////////////////////////////

void JuK::openFile()
{
179
    QStringList files = KFileDialog::getOpenFileNames(QString::null, "*.mp3|MPEG Audio (*.mp3)");
180
    splitter->open(files);
181 182 183 184
}

void JuK::openDirectory()
{
185
    splitter->open(KFileDialog::getExistingDirectory());
186 187
}

188 189
void JuK::saveFile()
{
190
    splitter->save();
191 192
}

193
void JuK::remove()
194
{
195 196
    QPtrList<PlaylistItem> items(splitter->playlistSelection());
    PlaylistItem *item = items.first();
197
    while(item) {
198 199 200
	if(item == playingItem)
	    playingItem = 0;
	item = items.next();
201
    }
202 203
    
    splitter->remove();
204 205
}

206 207
void JuK::quit()
{
208
    delete(this);
209 210
}

211 212 213 214 215 216
////////////////////////////////////////////////////////////////////////////////
// edit menu
////////////////////////////////////////////////////////////////////////////////

void JuK::cut()
{
217
    QPtrList<PlaylistItem> items = splitter->playlistSelection();
Scott Wheeler's avatar
Scott Wheeler committed
218

219 220 221 222 223
    PlaylistItem *item = items.first();
    while(item) {
	if(item == playingItem)
	    playingItem = 0;
	item = items.next();
224 225
    }

226
    splitter->clearSelectedItems();
227 228
}

229
void JuK::selectAll(bool select)
230
{
231
    splitter->selectAll(select);
232 233 234 235 236 237 238 239
}

////////////////////////////////////////////////////////////////////////////////
// player menu
////////////////////////////////////////////////////////////////////////////////

void JuK::playFile()
{
240 241 242 243 244 245 246 247 248
    if(player.paused()) {
        player.play();
        if(player.playing()) {
            playAction->setEnabled(false);
            pauseAction->setEnabled(true);
            stopAction->setEnabled(true);
            playTimer->start(pollInterval);
        }
    }
249 250
    else if(splitter) {
        QPtrList<PlaylistItem> items = splitter->playlistSelection();
251
        if(items.count() > 0)
252
            playItem(items.at(0));
253
        else
254
            playItem(splitter->playlistFirstItem());
255
    }
256 257 258 259
}

void JuK::pauseFile()
{
260 261 262 263
    playTimer->stop();
    player.pause();
    playAction->setEnabled(true);
    pauseAction->setEnabled(false);
264 265 266 267
}

void JuK::stopFile()
{
268 269 270 271 272 273 274
    playTimer->stop();
    player.stop();
    playAction->setEnabled(true);
    pauseAction->setEnabled(false);
    stopAction->setEnabled(false);
    sliderAction->getTrackPositionSlider()->setValue(0);
    sliderAction->getTrackPositionSlider()->setEnabled(false);
275 276
    if(playingItem)
        playingItem->setPixmap(0, 0);
277 278
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
////////////////////////////////////////////////////////////////////////////////
// playlist menu
////////////////////////////////////////////////////////////////////////////////

void JuK::createPlaylist()
{
    if(splitter) {
	bool ok;
	QString name = QInputDialog::getText(i18n("New Playlist..."), i18n("Please enter a name for the new playlist:"), 
					     QLineEdit::Normal, splitter->uniquePlaylistName(), &ok);
	if(ok)
	    splitter->createPlaylist(name);
    }
}

////////////////////////////////////////////////////////////////////////////////
// additional player slots
////////////////////////////////////////////////////////////////////////////////

298 299
void JuK::trackPositionSliderClick()
{
300
    trackPositionDragging=true;
301 302 303 304
}

void JuK::trackPositionSliderRelease()
{
305 306
    trackPositionDragging=false;
    player.seekPosition(sliderAction->getTrackPositionSlider()->value());
307 308 309 310
}

void JuK::trackPositionSliderUpdate(int position)
{
311
    if(player.playing() && !trackPositionDragging && !noSeek)
312
        player.seekPosition(position);
313 314 315 316
}

void JuK::pollPlay()
{
317 318 319
    noSeek = true;
    if(!player.playing()) {
        playTimer->stop();
320
        if(player.paused())
321 322
            pauseFile();
        else {
323
            if(playingItem && dynamic_cast<PlaylistItem *>(playingItem->itemBelow())) {
324
                playingItem->setPixmap(0, 0);
325
                playingItem = dynamic_cast<PlaylistItem *>(playingItem->itemBelow());
326 327 328 329 330 331 332 333 334 335
                sliderAction->getTrackPositionSlider()->setValue(0);
                player.play(playingItem->absFilePath(), player.getVolume());
                if(player.playing()) {
                    playTimer->start(pollInterval);
                    playingItem->setPixmap(0, QPixmap(UserIcon("playing")));
                }
            }
            else
                stopFile();
        }
336
    }
337
    else if(!trackPositionDragging)
338
        sliderAction->getTrackPositionSlider()->setValue(player.position());
339

340 341
    if(player.playing() && float(player.totalTime() - player.currentTime()) < pollInterval * 2)
        playTimer->changeInterval(50);
342

343
    noSeek=false;
344 345 346 347
}

void JuK::setVolume(int volume)
{
348 349 350
    if(sliderAction && sliderAction->getVolumeSlider() &&
       sliderAction->getVolumeSlider()->maxValue() > 0 &&
       volume >= 0 && sliderAction->getVolumeSlider()->maxValue() >= volume)
351
    {
352
        player.setVolume(float(volume) / float(sliderAction->getVolumeSlider()->maxValue()));
353 354
    }
}
355 356 357

void JuK::playItem(QListViewItem *item)
{
358
    PlaylistItem *fileListItem = dynamic_cast<PlaylistItem *>(item);
359 360
    if(fileListItem)
        playItem(fileListItem);
361 362
}

363
void JuK::playItem(PlaylistItem *item)
364
{
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    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);
        }
380 381
    }
}
382 383 384 385 386 387

void JuK::playTaggerItem(QListViewItem *item)
{

}

388
void JuK::playTaggerItem(PlaylistItem *item)
389 390 391
{

}
392 393

#include "juk.moc"