playlistsplitter.cpp 12.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/***************************************************************************
                          playlistsplitter.cpp  -  description
                             -------------------
    begin                : Fri Sep 13 2002
    copyright            : (C) 2002 by Scott Wheeler
    email                : scott@slackorama.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 <kiconloader.h>
19
#include <kapplication.h>
20
#include <klocale.h>
21 22
#include <kdebug.h>

23 24
#include <qinputdialog.h>

25
#include "playlistsplitter.h"
26 27 28
#include "playlist.h"
#include "collectionlist.h"
#include "tageditor.h"
29 30

////////////////////////////////////////////////////////////////////////////////
31
// helper functions
32 33
////////////////////////////////////////////////////////////////////////////////

34
void processEvents()
35
{
36 37 38
    static int processed = 0;
    if(processed == 0)
        kapp->processEvents();
39
    processed = (processed + 1) % 5;
40 41
}

42
////////////////////////////////////////////////////////////////////////////////
43
// public methods
44 45
////////////////////////////////////////////////////////////////////////////////

46
PlaylistSplitter::PlaylistSplitter(QWidget *parent, const char *name) : QSplitter(Qt::Horizontal, parent, name)
47
{
48 49 50 51 52
    setupLayout();
    readConfig();
    mediaExtensions.append("mp3");
    mediaExtensions.append("ogg");
    listExtensions.append("m3u");
53
}
54

55
PlaylistSplitter::~PlaylistSplitter()
56
{
57
    saveConfig();
58 59
}

60
QString PlaylistSplitter::uniquePlaylistName()
61
{
62
    return(uniquePlaylistName(i18n("Playlist")));
63 64
}

65
QString PlaylistSplitter::uniquePlaylistName(const QString &startingWith, bool useParenthesis)
66 67 68 69 70 71 72 73 74 75 76
{
    if(!playlistBox)
	return(QString::null);

    QStringList names = playlistBox->names();

    int playlistNumber = 1;

    // while the list contains more than zero instances of the generated 
    // string...

77 78 79 80 81 82 83 84 85 86 87 88 89
    if(useParenthesis) {
	while(names.contains(startingWith + " (" + QString::number(playlistNumber) + ")") != 0)
	    playlistNumber++;
	
	return(startingWith + " (" + QString::number(playlistNumber) + ")");	
    }
    else
    {
	while(names.contains(startingWith + ' ' + QString::number(playlistNumber)) != 0)
	    playlistNumber++;
	
	return(startingWith + " " + QString::number(playlistNumber));
    }
90 91
}

92
PlaylistItemList PlaylistSplitter::playlistSelection() const
93 94 95 96 97 98 99 100 101 102 103 104
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
    return(p->selectedItems());
}

PlaylistItem *PlaylistSplitter::playlistFirstItem() const
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
    PlaylistItem *i = static_cast<PlaylistItem *>(p->firstChild());
    return(i);
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
QString PlaylistSplitter::extensionsString(const QStringList &extensions, const QString &type)
{
    QStringList l;

    for(QStringList::ConstIterator it = extensions.begin(); it != extensions.end(); ++it)
	l.append(QString("*." + (*it)));

    // i.e. "*.m3u, *.mp3|Media Files"

    QString s = l.join(" ");

    if(type != QString::null)
	s =  + "|" + type;

    return(s);
}

122
QStringList PlaylistSplitter::playlistExtensions() const
123
{
124
    return(listExtensions);
125 126
}

127 128 129 130
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

131 132
void PlaylistSplitter::open()
{
133 134
    QStringList files = KFileDialog::getOpenFileNames(QString::null, 
						      extensionsString((mediaExtensions + listExtensions), i18n("Media Files")));
135 136 137 138 139 140 141 142
    open(files);
}

void PlaylistSplitter::openDirectory()
{
    open(KFileDialog::getExistingDirectory());
}

143 144
void PlaylistSplitter::open(const QStringList &files)
{
145
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
146
    if(p)
147
	add(files, p);
148 149 150 151
}

void PlaylistSplitter::open(const QString &file)
{
152
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
153
    if(p)
154
	add(file, p);
155
}
156

157 158 159 160
void PlaylistSplitter::save()
{
    if(editor)
	editor->save();
161 162 163 164 165
}

void PlaylistSplitter::remove()
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
166 167 168 169 170 171 172 173 174
    if(p)
	p->remove();
}

void PlaylistSplitter::refresh()
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
    if(p)
	p->refresh();
175 176 177 178 179 180 181 182 183 184 185 186 187
}

void PlaylistSplitter::setEditorVisible(bool visible)
{
    if(visible)
	editor->show();
    else
	editor->hide();
}

void PlaylistSplitter::clearSelectedItems()
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
188 189
    if(p)
	p->clearItems(p->selectedItems()); 
190 191 192 193 194
}

void PlaylistSplitter::selectAll(bool select)
{
    Playlist *p = static_cast<Playlist *>(playlistStack->visibleWidget());
195 196 197 198 199 200 201 202
    if(p)
	p->selectAll(select);
}

Playlist *PlaylistSplitter::createPlaylist()
{
    bool ok;

203
    // If this text is changed, please also change it in PlaylistBox::duplicate().
204 205 206 207 208 209 210 211 212 213 214

    QString name = QInputDialog::getText(i18n("New Playlist..."), i18n("Please enter a name for the new playlist:"),
					 QLineEdit::Normal, uniquePlaylistName(), &ok);
    if(ok)
	return(createPlaylist(name));
    else
	return(0);
}

Playlist *PlaylistSplitter::createPlaylist(const QString &name)
{
215
    Playlist *p = new Playlist(this, playlistStack, name.latin1());
216
    new PlaylistBoxItem(playlistBox, SmallIcon("midi", 32), name, p);
217

218 219 220
    connect(p, SIGNAL(selectionChanged(const PlaylistItemList &)), editor, SLOT(setItems(const PlaylistItemList &)));
    connect(p, SIGNAL(doubleClicked(QListViewItem *)), this, SIGNAL(playlistDoubleClicked(QListViewItem *)));
    connect(p, SIGNAL(collectionChanged()), editor, SLOT(updateCollection()));
221
    playlistBox->sort();
222 223 224 225 226 227 228 229
    return(p);
}

void PlaylistSplitter::openPlaylist()
{
    QStringList files = KFileDialog::getOpenFileNames(QString::null, "*.m3u");

    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
230
	openPlaylist(*it);
231 232 233 234 235
}

Playlist *PlaylistSplitter::openPlaylist(const QString &playlistFile)
{
    QFileInfo file(playlistFile);
236
    if(!file.exists() || !file.isFile() || !file.isReadable() || playlistFiles.contains(file.absFilePath()))
237
	return(0);
238 239 240

    playlistFiles.append(file.absFilePath());
    
241
    Playlist *p = new Playlist(this, playlistFile, playlistStack, file.baseName(true).latin1());
242 243 244
    connect(p, SIGNAL(selectionChanged(const PlaylistItemList &)), editor, SLOT(setItems(const PlaylistItemList &)));
    connect(p, SIGNAL(doubleClicked(QListViewItem *)), this, SIGNAL(playlistDoubleClicked(QListViewItem *)));
    connect(p, SIGNAL(collectionChanged()), editor, SLOT(updateCollection()));
245 246
    new PlaylistBoxItem(playlistBox, SmallIcon("midi", 32), p->name(), p);
    playlistBox->sort();
247
    return(p);
248 249
}

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
void PlaylistSplitter::add(const QString &file, Playlist *list)
{
    KApplication::setOverrideCursor(Qt::waitCursor);
    addImpl(file, list);
    KApplication::restoreOverrideCursor();
    
    if(editor)
	editor->updateCollection();
}

void PlaylistSplitter::add(const QStringList &files, Playlist *list)
{
    KApplication::setOverrideCursor(Qt::waitCursor);
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
        addImpl(*it, list);
    KApplication::restoreOverrideCursor();

    if(editor)
	editor->updateCollection();
}

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void PlaylistSplitter::setupLayout()
{
    playlistBox = new PlaylistBox(this, "playlistBox");

    // Create a splitter to go between the playlists and the editor.

    QSplitter *editorSplitter = new QSplitter(Qt::Vertical, this, "editorSplitter");

    // Create the playlist and the editor.

    playlistStack = new QWidgetStack(editorSplitter, "playlistStack");
    editor = new TagEditor(editorSplitter, "tagEditor");

    // Make the editor as small as possible (or at least as small as recommended)

    editorSplitter->setResizeMode(editor, QSplitter::FollowSizeHint);

    // Make the connection that will update the selected playlist when a 
    // selection is made in the playlist box.

295 296 297 298 299
    connect(playlistBox, SIGNAL(currentChanged(PlaylistBoxItem *)), 
	    this, SLOT(changePlaylist(PlaylistBoxItem *)));

    connect(playlistBox, SIGNAL(doubleClicked(PlaylistBoxItem *)), 
	    this, SLOT(playlistBoxDoubleClicked(PlaylistBoxItem *)));
300 301 302 303 304 305

    // Create the collection list; this should always exist.  This has a 
    // slightly different creation process than normal playlists (since it in
    // fact is a subclass) so it is created here rather than by using 
    // createPlaylist().

306
    CollectionList::initialize(this, playlistStack);
307 308 309 310 311
    collection = CollectionList::instance();

    PlaylistBoxItem *collectionBoxItem = new PlaylistBoxItem(playlistBox, SmallIcon("folder_sound", 32), 
							     i18n("Music Collection"), collection);

312 313
    connect(collection, SIGNAL(selectionChanged(const PlaylistItemList &)), 
	    editor, SLOT(setItems(const PlaylistItemList &)));
314
    connect(collection, SIGNAL(doubleClicked(QListViewItem *)), this, SIGNAL(playlistDoubleClicked(QListViewItem *)));
315
    connect(collection, SIGNAL(collectionChanged()), editor, SLOT(updateCollection()));
316 317 318 319 320 321 322

    // Show the collection on startup.
    playlistBox->setSelected(collectionBoxItem, true);
}

void PlaylistSplitter::readConfig()
{
323 324 325 326 327 328 329 330 331
    KConfig *config = KGlobal::config();
    { // block for Playlists group
	KConfigGroupSaver saver(config, "Playlists");

	QStringList external = config->readListEntry("ExternalPlaylists");
	for(QStringList::Iterator it = external.begin(); it != external.end(); ++it)
	    openPlaylist(*it);

	QStringList internal = config->readListEntry("InternalPlaylists");
332 333 334 335 336
	for(QStringList::Iterator it = internal.begin(); it != internal.end(); ++it) {
	    Playlist *p = openPlaylist(*it);
	    if(p)
		p->setInternal(true);
	}
337 338 339 340 341 342 343
    }
}	


void PlaylistSplitter::saveConfig()
{
    KConfig *config = KGlobal::config();
344

345 346 347 348 349
    // Save the list of open playlists.
    
    if(playlistBox) {
	QStringList internalPlaylists;
	QStringList externalPlaylists;
350 351 352 353

	// Start at item 1.  We want to skip the collection list.

	for(uint i = 1; i < playlistBox->count(); i++) {
354 355 356 357
	    PlaylistBoxItem *item = static_cast<PlaylistBoxItem *>(playlistBox->item(i));
	    if(item && item->playlist()) {
		Playlist *p = item->playlist();
		if(p->isInternalFile()) {
358 359
		    p->save(true);
		    internalPlaylists.append(p->fileName());
360 361 362 363 364 365 366
		}
		else
		    externalPlaylists.append(p->fileName());
	    }		
	}
	{ // block for Playlists group
	    KConfigGroupSaver saver(config, "Playlists");
367 368
	    config->writeEntry("InternalPlaylists", internalPlaylists);
	    config->writeEntry("ExternalPlaylists", externalPlaylists);
369 370
	}
    }
371 372
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
void PlaylistSplitter::addImpl(const QString &file, Playlist *list)
{
    processEvents();
    QFileInfo fileInfo(QDir::cleanDirPath(file));
    if(fileInfo.exists()) {
        if(fileInfo.isDir()) {
            QDir dir(fileInfo.filePath());
            QStringList dirContents=dir.entryList();
            for(QStringList::Iterator it = dirContents.begin(); it != dirContents.end(); ++it)
                if(*it != "." && *it != "..")
                    addImpl(fileInfo.filePath() + QDir::separator() + *it, list);
        }
        else {
            QString extension = fileInfo.extension(false);
            if(mediaExtensions.contains(extension) > 0)
		list->createItem(fileInfo);
	    else if(listExtensions.contains(extension) > 0)
		openPlaylist(fileInfo.absFilePath());
        }
    }    
}

395 396 397 398 399 400 401 402 403
////////////////////////////////////////////////////////////////////////////////
// private slots
////////////////////////////////////////////////////////////////////////////////

void PlaylistSplitter::changePlaylist(PlaylistBoxItem *item)
{
    if(item && item->playlist()) {
	playlistStack->raiseWidget(item->playlist());
	editor->setItems(playlistSelection());
404
	emit(playlistChanged(item->playlist()));
405 406 407
    }
}

408 409 410 411 412 413
void PlaylistSplitter::playlistBoxDoubleClicked(PlaylistBoxItem *item)
{
    if(item && item->playlist() && item->playlist()->firstChild())
	emit(playlistDoubleClicked(item->playlist()->firstChild()));
}

414
#include "playlistsplitter.moc"