playlistsplitter.cpp 23.5 KB
Newer Older
1 2 3 4 5
/***************************************************************************
                          playlistsplitter.cpp  -  description
                             -------------------
    begin                : Fri Sep 13 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 <kstandarddirs.h>
19
#include <kmessagebox.h>
20
#include <kinputdialog.h>
21
#include <kcmdlineargs.h>
22 23
#include <kdebug.h>

24
#include <qpopupmenu.h>
25

26
#include "playlistsplitter.h"
27
#include "searchwidget.h"
28
#include "directorylist.h"
29
#include "playlistsearch.h"
30
#include "dynamicplaylist.h"
31
#include "searchplaylist.h"
32
#include "historyplaylist.h"
33
#include "mediafiles.h"
34
#include "advancedsearchdialog.h"
35 36

////////////////////////////////////////////////////////////////////////////////
37
// helper functions
38 39
////////////////////////////////////////////////////////////////////////////////

40
void processEvents()
41
{
42 43 44
    static int processed = 0;
    if(processed == 0)
        kapp->processEvents();
45
    processed = (processed + 1) % 5;
46 47
}

48
////////////////////////////////////////////////////////////////////////////////
49
// public methods
50 51
////////////////////////////////////////////////////////////////////////////////

52
PlaylistSplitter::PlaylistSplitter(QWidget *parent, const char *name) :
53
    QSplitter(Qt::Horizontal, parent, name),
54 55
    m_playingItem(0), m_searchWidget(0), m_history(0),
    m_dynamicList(0), m_nextPlaylistItem(0)
56
{
57 58 59 60 61 62 63 64
#ifndef NO_DEBUG
    m_restore = KCmdLineArgs::parsedArgs()->isSet("restore");
#else
    m_restore = true;
#endif

    m_dirWatch = new KDirWatch();

65 66
    setupLayout();
    readConfig();
67 68

    m_editor->slotUpdateCollection();
69
}
70

71
PlaylistSplitter::~PlaylistSplitter()
72
{
Scott Wheeler's avatar
Scott Wheeler committed
73
    delete m_dirWatch;
74
    saveConfig();
75 76
}

77
QString PlaylistSplitter::uniquePlaylistName(const QString &startingWith, bool useParenthesis)
78
{
79
    if(!m_playlistBox)
80
	return QString::null;
81

82
    QStringList names = m_playlistBox->names();
83 84 85

    int playlistNumber = 1;

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

89 90 91
    if(useParenthesis) {
	while(names.contains(startingWith + " (" + QString::number(playlistNumber) + ")") != 0)
	    playlistNumber++;
92 93

	return startingWith + " (" + QString::number(playlistNumber) + ")";
94
    }
95
    else {
96 97
	while(names.contains(startingWith + ' ' + QString::number(playlistNumber)) != 0)
	    playlistNumber++;
98

99
	return startingWith + " " + QString::number(playlistNumber);
100
    }
101 102
}

103
QString PlaylistSplitter::playNextFile(bool random, bool loopPlaylist)
104
{
105 106
    PlaylistItem *i;

107
    // Four basic cases here:  (1) We've asked for a specific next item, (2) play
108
    // the item that's after the currently playing item, (3) play the selected
109
    // item or (4) play the first item in the list.
110

111
    // (1) we've asked for a specific next item
112
    if(m_nextPlaylistItem && m_nextPlaylistItem != m_playingItem) {
113 114 115
        i = m_nextPlaylistItem;
        m_nextPlaylistItem = 0;
    }
116
    // (2) play the item after the currently selected item
117
    else if(m_playingItem) {
118 119
        Playlist *p = static_cast<Playlist *>(m_playingItem->listView());
        i = p->nextItem(m_playingItem, random);
120
        if(!i && loopPlaylist)
121
            i = static_cast<PlaylistItem *>(p->firstChild());
122
    }
123 124
    // (3) play the selected item
    else if(playlistSelection().size() > 0) {
125
        i = playlistSelection().first();
126 127
        if(!i)
            i = static_cast<PlaylistItem *>(visiblePlaylist()->firstChild());
128
    }
129 130 131
    // (4) play the first item in the list
    else
        i = static_cast<PlaylistItem *>(visiblePlaylist()->firstChild());
132

133
    return play(i);
134 135
}

136
QString PlaylistSplitter::playPreviousFile(bool random)
137
{
138
    if(!m_playingItem)
139
	return QString::null;
140

141 142
    Playlist *p = static_cast<Playlist *>(m_playingItem->listView());
    PlaylistItem *i = p->previousItem(m_playingItem, random);
143

144
    return play(i);
145 146
}

147 148 149 150 151 152
void PlaylistSplitter::populatePlayHistoryMenu(QPopupMenu* menu, bool random)
{
    Playlist *p = static_cast<Playlist *>(m_playingItem->listView());
    PlaylistItemList list = p->historyItems(m_playingItem, random);
    menu->clear();
    int i = 0;
153
    for(PlaylistItemList::Iterator it = list.begin(); it != list.end(); ++it)
154 155 156
        menu->insertItem((*it)->tag()->track(), ++i);
}

157 158 159 160 161 162 163 164
QString PlaylistSplitter::playSelectedFile()
{
    if(playlistSelection().isEmpty())
	return QString::null;
    else
	return play(playlistSelection().first());
}

165 166 167 168
QString PlaylistSplitter::playFirstFile()
{
    Playlist *p = visiblePlaylist();
    PlaylistItem *i = static_cast<PlaylistItem *>(p->firstChild());
169

170
    return play(i);
171 172
}

173 174 175 176 177 178 179 180 181
QString PlaylistSplitter::playRandomFile()
{
    Playlist *p = visiblePlaylist();
    PlaylistItem *i = static_cast<PlaylistItem *>(p->firstChild());

    // Not exactly random (the first item won't be taken into account)
    return play(p->nextItem(i, true));
}

182 183
void PlaylistSplitter::stop()
{
184 185
    m_nextPlaylistItem = 0;

186 187 188 189 190
    if(!m_playingItem)
	return;

    Playlist *p = static_cast<Playlist *>(m_playingItem->listView());

191 192 193
    if(p)
	p->setPlaying(m_playingItem, false);

194
    m_playingItem = 0;
195 196 197 198
}

QString PlaylistSplitter::playingArtist() const
{
199 200 201 202
    if(m_playingItem) {
	int offset =  static_cast<Playlist *>(m_playingItem->listView())->columnOffset();
	return m_playingItem->text(PlaylistItem::ArtistColumn + offset);
    }
203
    else
204
	return QString::null;
205 206 207 208
}

QString PlaylistSplitter::playingTrack() const
{
209 210 211 212
    if(m_playingItem) {
	int offset =  static_cast<Playlist *>(m_playingItem->listView())->columnOffset();
	return m_playingItem->text(PlaylistItem::TrackColumn + offset);
    }
213
    else
214
	return QString::null;
215 216 217 218
}

QString PlaylistSplitter::playingList() const
{
219 220
    if(m_playingItem)
	return static_cast<Playlist *>(m_playingItem->listView())->name();
221
    else
222
	return QString::null;
223 224
}

225
void PlaylistSplitter::open(const QString &file)
226
{
227 228 229
    if(file.isEmpty())
	return;

230 231 232 233 234
    if(visiblePlaylist() == m_collection ||
       KMessageBox::questionYesNo(this,
				  i18n("Do you want to add this item to the current list or to the collection list?"),
				  QString::null,
				  KGuiItem(i18n("Current")),
235 236
				  KGuiItem(i18n("Collection"))) == KMessageBox::No)
    {
237
	slotAddToPlaylist(file, m_collection);
238
    }
239
    else
240
	slotAddToPlaylist(file, visiblePlaylist());
241 242
}

243
void PlaylistSplitter::open(const QStringList &files)
244
{
245 246
    if(files.isEmpty())
	return;
247 248 249 250 251 252 253

    if(visiblePlaylist() == m_collection ||
       KMessageBox::questionYesNo(this,
				  i18n("Do you want to add these items to the current list or to the collection list?"),
				  QString::null,
				  KGuiItem(i18n("Current")),
				  KGuiItem(i18n("Collection"))) == KMessageBox::No)
254
    {
255
	slotAddToPlaylist(files, m_collection);
256
    }
257
    else
258
	slotAddToPlaylist(files, visiblePlaylist());
259 260 261 262
}

Playlist *PlaylistSplitter::createPlaylist(const QString &name)
{
263
    Playlist *p = new Playlist(m_playlistStack, name);
264 265
    setupPlaylist(p, true);
    return p;
266 267
}

268 269 270 271
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

272
void PlaylistSplitter::slotOpen()
273
{
274
    open(MediaFiles::openDialog(this));
275 276
}

277
void PlaylistSplitter::slotOpenDirectory()
278
{
279
    DirectoryList *l = new DirectoryList(m_directoryList, this, "directoryList");
280

281
    m_directoryQueue.clear();
282
    m_directoryQueueRemove.clear();
283

284
    connect(l, SIGNAL(signalDirectoryAdded(const QString &)),
285
	    this, SLOT(slotQueueDirectory(const QString &)));
286
    connect(l, SIGNAL(signalDirectoryRemoved(const QString &)),
287
	    this, SLOT(slotQueueDirectoryRemove(const QString &)));
288 289

    if(l->exec() == QDialog::Accepted) {
290
	open(m_directoryQueue);
291 292
	for(QStringList::Iterator it = m_directoryQueue.begin(); it !=  m_directoryQueue.end(); it++)
	    m_dirWatch->addDir(*it, false, true);
293

294
	m_directoryList += m_directoryQueue;
295 296 297

	QStringList::Iterator it = m_directoryQueueRemove.begin();
	for(; it !=  m_directoryQueueRemove.end(); it++) {
298
	    m_dirWatch->removeDir(*it);
299
	    m_directoryList.remove(*it);
300
	}
301 302
    }
}
303

304
Playlist *PlaylistSplitter::slotCreatePlaylist()
305 306 307
{
    bool ok;

308
    // If this text is changed, please also change it in PlaylistBox::duplicate().
309

310
    QString name = KInputDialog::getText(i18n("Create New Playlist"),
Nadeem Hasan's avatar
Nadeem Hasan committed
311 312
	i18n("Please enter a name for the new playlist:"),
	uniquePlaylistName(), &ok);
313
    if(ok)
314
	return createPlaylist(name);
315
    else
316
	return 0;
317 318
}

319 320 321 322 323 324 325 326 327 328
Playlist *PlaylistSplitter::slotCreatePlaylistFromDir()
{
    const QString dirName = KFileDialog::getExistingDirectory();
    if(dirName.isEmpty())
        return 0;

    Playlist *playlist = slotCreatePlaylist();
    if(!playlist)
        return 0;

329
    slotAddToPlaylist(dirName, playlist);
330 331 332 333

    return playlist;
}

334
void PlaylistSplitter::slotSelectPlaying()
335
{
336
    if(!m_playingItem)
337 338
	return;

339
    Playlist *l = static_cast<Playlist *>(m_playingItem->listView());
340

341 342
    if(!l)
	return;
343

344
    l->clearSelection();
345 346
    l->setSelected(m_playingItem, true);
    l->ensureItemVisible(m_playingItem);
Nadeem Hasan's avatar
Nadeem Hasan committed
347

348 349
    if(l != visiblePlaylist())
	m_playlistBox->raise(l);
350 351
}

352
void PlaylistSplitter::slotDeleteSelectedItems()
353 354 355
{
    Playlist *p = visiblePlaylist();
    if(p)
356
	p->slotRemoveSelectedItems();
357 358
}

359
void PlaylistSplitter::slotAddToPlaylist(const QString &file, Playlist *list, PlaylistItem *after)
360
{
361 362 363
    if(!after)
	after = static_cast<PlaylistItem *>(list->lastItem());

364
    KApplication::setOverrideCursor(Qt::waitCursor);
365
    addImpl(file, list, after);
366
    list->emitCountChanged();
367
    KApplication::restoreOverrideCursor();
Nadeem Hasan's avatar
Nadeem Hasan committed
368

369 370 371 372
    if(m_editor)
	m_editor->slotUpdateCollection();
}

373 374 375 376 377
void PlaylistSplitter::slotDeletePlaylist()
{
    if(m_playingItem && m_playingItem->listView() == visiblePlaylist())
	m_playingItem = 0;

378
    m_playlistBox->deleteItems();
379 380
}

381
void PlaylistSplitter::slotAddToPlaylist(const QStringList &files, Playlist *list, PlaylistItem *after)
382
{
383 384 385
    if(!after)
	after = static_cast<PlaylistItem *>(list->lastItem());

386
    KApplication::setOverrideCursor(Qt::waitCursor);
387

388
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
389 390
        after = addImpl(*it, list, after);

391
    list->emitCountChanged();
392

393 394 395 396 397 398
    KApplication::restoreOverrideCursor();

    if(m_editor)
	m_editor->slotUpdateCollection();
}

399 400 401 402 403 404
void PlaylistSplitter::slotSetSearchVisible(bool visible)
{
    m_searchWidget->setShown(visible);
    redisplaySearch();
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418
void PlaylistSplitter::slotSetHistoryVisible(bool visible)
{
    if(visible && !m_history) {
	m_history = new HistoryPlaylist(m_playlistStack);
	setupPlaylist(m_history, false, "history", true);
	return;
    }

    if(!visible && m_history) {
	m_playlistBox->deleteItem(m_history);
	m_history = 0;
    }
}

419 420
void PlaylistSplitter::slotAdvancedSearch()
{
421 422
    AdvancedSearchDialog *d =
	new AdvancedSearchDialog(uniquePlaylistName(i18n("Search Playlist")), this);
423
    AdvancedSearchDialog::Result r = d->exec();
424
    delete d;
425 426 427 428 429

    if(r.result == AdvancedSearchDialog::Accepted) {
	SearchPlaylist *p = new SearchPlaylist(r.search, m_playlistStack, r.playlistName);
	setupPlaylist(p, true, "find");
    }
430
}
431

432
void PlaylistSplitter::slotGuessTagInfo(TagGuesser::Type type)
433
{
434
    visiblePlaylist()->slotGuessTagInfo(type);
435 436 437 438
    if(m_editor)
        m_editor->slotRefresh();
}

439 440 441 442 443 444 445
void PlaylistSplitter::slotRenameFile()
{
    visiblePlaylist()->slotRenameFile();
    if(m_editor)
        m_editor->slotRefresh();
}

446 447 448 449 450 451
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void PlaylistSplitter::setupLayout()
{
452 453
    setOpaqueResize(true);

454
    m_playlistBox = new PlaylistBox(this, "playlistBox");
455

456 457 458
    connect(m_playlistBox, SIGNAL(signalCreateSearchList(const PlaylistSearch &, const QString &, const QString &)),
            this, SLOT(slotCreateSearchList(const PlaylistSearch &, const QString &, const QString &)));

459 460 461
    connect(m_playlistBox, SIGNAL(signalCreatePlaylist(const QStringList &)),
	    this, SLOT(slotCreatePlaylist(const QStringList &)));

462 463 464 465 466
    // 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.
467

468 469
    m_playlistStack = new QWidgetStack(editorSplitter, "playlistStack");
    m_editor = new TagEditor(editorSplitter, "tagEditor");
470 471 472

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

473
    editorSplitter->setResizeMode(m_editor, QSplitter::FollowSizeHint);
474

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

478
    connect(m_playlistBox, SIGNAL(signalCurrentChanged(const PlaylistList &)),
479
	    this, SLOT(slotChangePlaylist(const PlaylistList &)));
480

481
    connect(m_playlistBox, SIGNAL(signalDoubleClicked()), this, SIGNAL(signalListBoxDoubleClicked()));
482

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

488
    CollectionList::initialize(m_playlistStack, m_restore);
489
    m_collection = CollectionList::instance();
490
    setupPlaylist(m_collection, true, "folder_sound", true);
491
    connect(m_collection, SIGNAL(signalCollectionChanged()), m_editor, SLOT(slotUpdateCollection()));
492 493

    // Create the search widget -- this must be done after the CollectionList is created.
494
    m_searchWidget = new SearchWidget(editorSplitter, "searchWidget");
495
    editorSplitter->moveToFirst(m_searchWidget);
496
    connect(m_searchWidget, SIGNAL(signalQueryChanged()), this, SLOT(slotShowSearchResults()));
497 498 499
    connect(CollectionList::instance(), SIGNAL(signalVisibleColumnsChanged()),
	    this, SLOT(slotVisibleColumnsChanged()));

500
    // Show the collection on startup.
501
    m_playlistBox->setSelected(0, true);
502 503 504 505
}

void PlaylistSplitter::readConfig()
{
506 507 508 509
    KConfig *config = KGlobal::config();
    { // block for Playlists group
	KConfigGroupSaver saver(config, "Playlists");

510 511 512 513 514 515
	QValueList<int> splitterSizes = config->readIntListEntry("PlaylistSplitterSizes");
	if(splitterSizes.isEmpty()) {
	    splitterSizes.append(100);
	    splitterSizes.append(640);
	}
	setSizes(splitterSizes);
516

517
	if(m_restore) {
518

519
	    readPlaylists();
520

521
	    m_directoryList = config->readListEntry("DirectoryList");
522
	    QTimer::singleShot(0, this, SLOT(slotScanDirectories()));
523

524
	    connect(m_dirWatch, SIGNAL(dirty(const QString &)),
525
		    this, SLOT(slotDirChanged(const QString &)));
526

527 528
	    QStringList::Iterator it = m_directoryList.begin();
            for(; it != m_directoryList.end(); ++it)
529 530 531
		m_dirWatch->addDir(*it, false, true);

	    m_dirWatch->startScan();
532
	}
533 534 535

	// restore the list of hidden and shown columns

536
	if(m_collection) {
537
	    for(int i = 0; i < m_collection->columns(); i++)
538
		m_columnNames.append(m_collection->columnText(i));
539
	}
540

541
    }
542
}
543 544 545 546

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

548
    // Save the list of open playlists.
Nadeem Hasan's avatar
Nadeem Hasan committed
549

550
    if(m_restore && m_playlistBox) {
551

552
	savePlaylists();
553

554 555
	{ // block for Playlists group
	    KConfigGroupSaver saver(config, "Playlists");
556
	    config->writeEntry("DirectoryList", m_directoryList);
557
	    config->writeEntry("SortColumn", m_collection->sortColumn());
558
	    config->writeEntry("PlaylistSplitterSizes", sizes());
559 560
	}
    }
561 562
}

563
PlaylistItem *PlaylistSplitter::addImpl(const QString &file, Playlist *list, PlaylistItem *after)
564 565 566 567 568 569
{
    processEvents();
    QFileInfo fileInfo(QDir::cleanDirPath(file));
    if(fileInfo.exists()) {
        if(fileInfo.isDir()) {
            QDir dir(fileInfo.filePath());
570
            QStringList dirContents = dir.entryList();
571 572
            for(QStringList::Iterator it = dirContents.begin(); it != dirContents.end(); ++it)
                if(*it != "." && *it != "..")
573
                    after = addImpl(fileInfo.filePath() + QDir::separator() + *it, list, after);
574 575
        }
        else {
576
            if(MediaFiles::isMediaFile(file))
577
		after = list->createItem(fileInfo, QString::null, after, false);
578
	    else if(MediaFiles::isPlaylistFile(file))
579 580
		openPlaylist(fileInfo.absFilePath());
        }
Nadeem Hasan's avatar
Nadeem Hasan committed
581
    }
582
    return after;
583 584
}

585
void PlaylistSplitter::setupPlaylist(Playlist *p, bool raise, const char *icon, bool sortedFirst)
586
{
587 588
    connect(p, SIGNAL(signalSelectionChanged(const PlaylistItemList &)),
	    m_editor, SLOT(slotSetItems(const PlaylistItemList &)));
589 590 591 592 593 594 595

    connect(p, SIGNAL(doubleClicked(QListViewItem *)),
	    this, SIGNAL(signalActivated()));

    connect(p, SIGNAL(returnPressed(QListViewItem *)), 
	    this, SIGNAL(signalActivated()));

596
    connect(p, SIGNAL(signalCountChanged(Playlist *)),
597
	    this, SLOT(slotPlaylistCountChanged(Playlist *)));
598

599
    connect(p, SIGNAL(signalAboutToRemove(PlaylistItem *)),
600
	    this, SLOT(slotPlaylistItemRemoved(PlaylistItem *)));
601

602 603
    connect(p, SIGNAL(signalFilesDropped(const QStringList &, Playlist *, PlaylistItem *)),
	    this, SLOT(slotAddToPlaylist(const QStringList &, Playlist *, PlaylistItem *)));
604

605 606
    connect(p, SIGNAL(signalSetNext(PlaylistItem *)),
	    this, SLOT(slotSetNextItem(PlaylistItem *)));
607

608 609 610
    connect(p, SIGNAL(itemRenamed(QListViewItem *)),
	    m_editor, SLOT(slotRefresh()));

611 612 613
    connect(p, SIGNAL(signalCreatePlaylist(const PlaylistItemList &)),
	    this, SLOT(slotCreatePlaylist(const PlaylistItemList &)));

614
    if(icon)
615
	m_playlistBox->createItem(p, icon, raise, sortedFirst);
616

617 618 619 620 621
    if(raise) {
	PlaylistList l;
	l.append(p);
	slotChangePlaylist(l);
    }
622 623
}

624 625 626
Playlist *PlaylistSplitter::openPlaylist(const QString &file)
{
    QFileInfo fileInfo(file);
627 628 629
    if(!fileInfo.exists() ||
       !fileInfo.isFile() ||
       !fileInfo.isReadable() ||
630 631
       m_playlistFiles.insert(fileInfo.absFilePath()))
    {
632
	return 0;
633
    }
634

635
    Playlist *p = new Playlist(file, m_playlistStack, fileInfo.baseName(true));
636
    setupPlaylist(p);
637
    return p;
638 639
}

640 641 642 643 644 645 646
QString PlaylistSplitter::play(PlaylistItem *item)
{
    stop();

    if(!item)
	return QString::null;

647 648
    Playlist *p = static_cast<Playlist *>(item->listView());

649
    if(!p)
650 651
	return QString::null;

652 653
    p->setPlaying(item, true);

654 655
    m_playingItem = item;

656
    if(m_history && p != m_history) {
657 658 659 660 661
	PlaylistItemList l;
	l.append(item);
	m_history->createItems(l);
    }

662 663 664
    return item->absFilePath();
}

665 666 667 668 669 670 671 672 673 674
void PlaylistSplitter::redisplaySearch()
{
    if(!m_searchWidget->isVisible() || visiblePlaylist()->search().isEmpty())
	visiblePlaylist()->setItemsVisible(visiblePlaylist()->items(), true);
    else {
	Playlist::setItemsVisible(visiblePlaylist()->search().matchedItems(), true);
	Playlist::setItemsVisible(visiblePlaylist()->search().unmatchedItems(), false);
    }
}

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
void PlaylistSplitter::readPlaylists()
{
    QString playlistsFile = KGlobal::dirs()->saveLocation("appdata") + "playlists";

    QFile f(playlistsFile);

    if(f.open(IO_ReadOnly)) {
	QDataStream s(&f);
	while(!s.atEnd()) {
	    Playlist *p = new Playlist(m_playlistStack);
	    s >> *p;

	    // check to see if we've alredy loaded this item before continuing

	    if(p->fileName().isEmpty() || !m_playlistFiles.insert(p->fileName()))
		setupPlaylist(p);
	    else
		delete p;
	}
    }
}

void PlaylistSplitter::savePlaylists()
{
    QString playlistsFile = KGlobal::dirs()->saveLocation("appdata") + "playlists";
    QFile f(playlistsFile);

    if(f.open(IO_WriteOnly)) {

	QDataStream s(&f);

	PlaylistList l = m_playlistBox->playlists();

	for(PlaylistList::Iterator it = l.begin(); it != l.end(); it++) {
	    if(*it && *it != m_history)
		s << *(*it);
	}

	f.close();
    }
}

717 718 719 720
////////////////////////////////////////////////////////////////////////////////
// private slots
////////////////////////////////////////////////////////////////////////////////

721
void PlaylistSplitter::slotChangePlaylist(const PlaylistList &l)
722
{
723 724
    if(l.isEmpty()) {
	emit signalPlaylistChanged();
725
	return;
726
    }
727

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    // Save the current dynamic list so that we can delete it when we're done
    // showing the next list.  The two situations are that we're either showing
    // an existing, non-dynamic list or that we're creating a dynamic list; in 
    // both cases we want to get rid of the current one.
    //
    // If in fact the currently visible list *is not* a dynamic list, then
    // m_dyanmicList will simply be zero, making deleting it at the end of this
    // method just a no-op.
    //
    // And finally, because we will end up doing a recursive call to this method
    // to show the dynamic playlist (second case calls the first case), we want
    // to make sure that in that case we don't delete the very thing we're
    // being asked to show.  (Hence the conditional assignment.)

    Playlist *current = l.first() != m_dynamicList ? m_dynamicList : 0;
743

744
    m_nextPlaylistItem = 0;
745 746 747

    // First case:  We're just showing one, currently existing list.

748 749 750
    if(l.count() == 1) {
	m_playlistStack->raiseWidget(l.first());
	m_editor->slotSetItems(playlistSelection());
751 752 753

	if(m_dynamicList != l.first())
	   m_dynamicList = 0;
754 755 756 757 758

	if(m_searchWidget) {
	    m_searchWidget->setSearch(l.first()->search());
	    redisplaySearch();
	}
759
    }
760 761 762 763

    // Second case: There are multiple playlists in our list, so we need to create
    // a new "dynamic list" that is the union of these playlists.

764
    else {
765
	m_dynamicList = new DynamicPlaylist(l, m_playlistStack, i18n("Dynamic List"));
766 767 768 769 770

	// Note that this call will end up making a recursive call to this
	// method, but in that call since there will only be one list, it will
	// take the "first case" above.
	
771 772 773
	setupPlaylist(m_dynamicList, true, 0);
    }

774 775 776 777
    if(current) {
	m_playingItem = 0;
	delete current;
    }
778 779

    emit signalPlaylistChanged();
780 781
}

782
void PlaylistSplitter::slotPlaylistCountChanged(Playlist *p)
783
{
784 785
    if(p && p == m_playlistStack->visibleWidget())
	emit signalSelectedPlaylistCountChanged(p->childCount());
786 787
}

788
void PlaylistSplitter::slotPlaylistItemRemoved(PlaylistItem *item)
789
{
790 791
    if(item == m_playingItem)
	m_playingItem = 0;
792 793 794

    if(item == m_nextPlaylistItem)
	m_nextPlaylistItem = 0;
795 796
}

797 798 799 800 801 802 803 804
void PlaylistSplitter::slotCreatePlaylist(const QStringList &files)
{
    Playlist *p = slotCreatePlaylist();
    if(p)
	slotAddToPlaylist(files, p);
}


805
void PlaylistSplitter::slotCreatePlaylist(const PlaylistItemList &items)
806
{
807 808 809
    if(items.isEmpty())
	return;

810
    Playlist *playlist = slotCreatePlaylist();
811

812
    if(!playlist)
813
        return;
814

815
    playlist->createItems(items);
816 817
}

818
void PlaylistSplitter::slotShowSearchResults()
819 820 821 822
{
    PlaylistList playlists;
    playlists.append(visiblePlaylist());

823
    PlaylistSearch search = m_searchWidget->search(playlists);
824

825 826
    visiblePlaylist()->setSearch(search);
    redisplaySearch();
827 828
}

829 830
void PlaylistSplitter::slotVisibleColumnsChanged()
{
831 832 833
    m_searchWidget->updateColumns();
    // if(m_searchWidget->searchedColumns(0).count() > 1)
    slotShowSearchResults();
834 835
}

836 837 838 839 840 841 842 843 844
void PlaylistSplitter::slotCreateSearchList(const PlaylistSearch &search, 
					    const QString &searchCategory,
					    const QString &name)
{
    SearchPlaylist *p = new SearchPlaylist(search, m_playlistStack, name);
    m_playlistBox->createSearchItem(p, searchCategory);
    setupPlaylist(p, false, 0);
}

845
#include "playlistsplitter.moc"
Nadeem Hasan's avatar
Nadeem Hasan committed
846 847

// vim:ts=8