playlistbox.cpp 23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/**
 * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
16

17 18
#include "playlistbox.h"

19
#include <kiconloader.h>
20
#include <kmessagebox.h>
21
#include <kactioncollection.h>
Laurent Montel's avatar
Poirt  
Laurent Montel committed
22 23
#include <ktoggleaction.h>
#include <kselectaction.h>
24
#include <kconfiggroup.h>
Michael Pyne's avatar
Michael Pyne committed
25
#include <KSharedConfig>
26

Michael Pyne's avatar
Michael Pyne committed
27 28 29
#include <QAction>
#include <QIcon>
#include <QMenu>
30
#include <QPainter>
31
#include <QTimer>
Laurent Montel's avatar
Laurent Montel committed
32
#include <QDragLeaveEvent>
33
#include <QList>
Laurent Montel's avatar
Laurent Montel committed
34 35 36 37
#include <QDragMoveEvent>
#include <QKeyEvent>
#include <QDropEvent>
#include <QMouseEvent>
38
#include <QFileInfo>
39
#include <QTime>
40 41
#include <QApplication>
#include <QClipboard>
42
#include <QHeaderView>
43

44
#include "playlist.h"
45 46
#include "collectionlist.h"
#include "dynamicplaylist.h"
47
#include "upcomingplaylist.h"
48
#include "historyplaylist.h"
49
#include "viewmode.h"
50
#include "searchplaylist.h"
51
#include "treeviewitemplaylist.h"
52
#include "actioncollection.h"
53
#include "cache.h"
54
#include "tracksequencemanager.h"
55
#include "tagtransactionmanager.h"
56
#include "playermanager.h"
57
#include "dbuscollectionproxy.h"
Michael Pyne's avatar
Michael Pyne committed
58
#include "juk_debug.h"
59 60

using namespace ActionCollection;
61 62 63 64 65

////////////////////////////////////////////////////////////////////////////////
// PlaylistBox public methods
////////////////////////////////////////////////////////////////////////////////

66
PlaylistBox::PlaylistBox(PlayerManager *player, QWidget *parent, QStackedWidget *playlistStack) :
67
    QTreeWidget(parent),
68
    PlaylistCollection(player, playlistStack),
69
    m_viewModeIndex(0),
70
    m_hasSelection(false),
71
    m_doingMultiSelect(false),
72
    m_dropItem(0),
73
    m_showTimer(0)
74
{
75
    readConfig();
76
    setHeaderLabel("Playlists");
77 78
    setRootIsDecorated(false);
    setContextMenuPolicy(Qt::CustomContextMenu);
Kacper Kasper's avatar
Kacper Kasper committed
79
    setDropIndicatorShown(true);
80

81
    header()->blockSignals(true);
82
    header()->hide();
83
    header()->blockSignals(false);
84

85
    sortByColumn(0);
Laurent Montel's avatar
Laurent Montel committed
86

Kacper Kasper's avatar
Kacper Kasper committed
87 88
    viewport()->setAcceptDrops(true);
    setDropIndicatorShown(true);
89
    setSelectionMode(QAbstractItemView::ExtendedSelection);
Laurent Montel's avatar
Laurent Montel committed
90

Michael Pyne's avatar
Michael Pyne committed
91
    m_contextMenu = new QMenu(this);
92

93 94 95 96 97 98 99 100
    m_contextMenu->addAction( action("file_new") );
    m_contextMenu->addAction( action("renamePlaylist") );
    m_contextMenu->addAction( action("editSearch") );
    m_contextMenu->addAction( action("duplicatePlaylist") );
    m_contextMenu->addAction( action("reloadPlaylist") );
    m_contextMenu->addAction( action("deleteItemPlaylist") );
    m_contextMenu->addAction( action("file_save") );
    m_contextMenu->addAction( action("file_save_as") );
Laurent Montel's avatar
Laurent Montel committed
101

102
    m_contextMenu->addSeparator();
103

104
    // add the view modes stuff
Laurent Montel's avatar
Laurent Montel committed
105

106
    KSelectAction *viewModeAction =
Michael Pyne's avatar
Michael Pyne committed
107
        new KSelectAction( QIcon::fromTheme(QStringLiteral("view-choose")), i18n("View Modes"), ActionCollection::actions());
108
    ActionCollection::actions()->addAction("viewModeMenu", viewModeAction);
Laurent Montel's avatar
Laurent Montel committed
109

110 111
    ViewMode* viewmode = new ViewMode(this);
    m_viewModes.append(viewmode);
Michael Pyne's avatar
Michael Pyne committed
112
    viewModeAction->addAction(QIcon::fromTheme(QStringLiteral("view-list-details")), viewmode->name());
113

114 115
    CompactViewMode* compactviewmode = new CompactViewMode(this);
    m_viewModes.append(compactviewmode);
Michael Pyne's avatar
Michael Pyne committed
116
    viewModeAction->addAction(QIcon::fromTheme(QStringLiteral("view-list-text")), compactviewmode->name());
117

118 119
    // TODO: Fix the broken tree view mode
#if 0
120 121
    TreeViewMode* treeviewmode = new TreeViewMode(this);
    m_viewModes.append(treeviewmode);
Michael Pyne's avatar
Michael Pyne committed
122
    viewModeAction->addAction(QIcon::fromTheme(QStringLiteral("view-list-tree")), treeviewmode->name());
123
#endif
124

125 126
    CollectionList::initialize(this);

127
    viewModeAction->setCurrentItem(m_viewModeIndex);
128
    m_viewModes[m_viewModeIndex]->setShown(true);
Laurent Montel's avatar
Laurent Montel committed
129

130 131 132
    TrackSequenceManager::instance()->setCurrentPlaylist(CollectionList::instance());
    raise(CollectionList::instance());

133
    m_contextMenu->addAction( viewModeAction );
134
    connect(viewModeAction, SIGNAL(triggered(int)), this, SLOT(slotSetViewMode(int)));
135

136
    connect(this, SIGNAL(itemSelectionChanged()),
137
            this, SLOT(slotPlaylistChanged()));
Laurent Montel's avatar
Laurent Montel committed
138

139 140
    connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
            this, SLOT(slotDoubleClicked(QTreeWidgetItem*)));
Laurent Montel's avatar
Laurent Montel committed
141

142 143
    connect(this, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(slotShowContextMenu(QPoint)));
144

145 146 147 148
    TagTransactionManager *tagManager = TagTransactionManager::instance();
    connect(tagManager, SIGNAL(signalAboutToModifyTags()), SLOT(slotFreezePlaylists()));
    connect(tagManager, SIGNAL(signalDoneModifyingTags()), SLOT(slotUnfreezePlaylists()));

149
    setupUpcomingPlaylist();
150

Laurent Montel's avatar
Laurent Montel committed
151 152 153 154
    connect(CollectionList::instance(), SIGNAL(signalNewTag(QString,uint)),
            this, SLOT(slotAddItem(QString,uint)));
    connect(CollectionList::instance(), SIGNAL(signalRemovedTag(QString,uint)),
            this, SLOT(slotRemoveItem(QString,uint)));
155 156
    connect(CollectionList::instance(), SIGNAL(cachedItemsLoaded()),
            this, SLOT(slotLoadCachedPlaylists()));
157

158
    m_savePlaylistTimer = 0;
159

160
    KToggleAction *historyAction =
Michael Pyne's avatar
Michael Pyne committed
161
        new KToggleAction(QIcon::fromTheme(QStringLiteral("view-history")), i18n("Show &History"), ActionCollection::actions());
162 163 164 165
    ActionCollection::actions()->addAction("showHistory", historyAction);
    connect(historyAction, SIGNAL(triggered(bool)),
            this, SLOT(slotSetHistoryPlaylistEnabled(bool)));

166 167
    m_showTimer = new QTimer(this);
    connect(m_showTimer, SIGNAL(timeout()), SLOT(slotShowDropTarget()));
168 169 170

    // hook up to the D-Bus
    (void) new DBusCollectionProxy(this, this);
171 172 173 174
}

PlaylistBox::~PlaylistBox()
{
175 176
    PlaylistList l;
    CollectionList *collection = CollectionList::instance();
177 178
    for(QTreeWidgetItemIterator it(topLevelItem(0)); *it; ++it) {
        Item *item = static_cast<Item *>(*it);
179 180
        if(item->playlist() && item->playlist() != collection)
            l.append(item->playlist());
181
    }
182

183 184
    Cache::savePlaylists(l);
    saveConfig();
185 186
}

187 188 189
void PlaylistBox::raise(Playlist *playlist)
{
    if(!playlist)
190
        return;
191

192
    Item *i = m_playlistDict.value(playlist, 0);
193

194
    if(i) {
195
        clearSelection();
196
        setCurrentItem(i);
197

198
        setSingleItem(i);
199
        scrollToItem(currentItem());
200 201
    }
    else
202 203
        PlaylistCollection::raise(playlist);

204
    slotPlaylistChanged();
205 206
}

207
void PlaylistBox::duplicate()
208
{
209 210
    Item *item = static_cast<Item *>(currentItem());
    if(!item || !item->playlist())
211
        return;
212

213
    QString name = playlistNameDialog(i18nc("verb, copy the playlist", "Duplicate"), item->text(0));
214

215
    if(name.isNull())
216
        return;
217

218 219
    Playlist *p = new Playlist(this, name);
    p->createItems(item->playlist()->items());
220 221
}

222 223
void PlaylistBox::scanFolders()
{
Michael Pyne's avatar
Michael Pyne committed
224
    qCDebug(JUK_LOG) << "Starting folder scan";
225 226 227 228
    QTime stopwatch; stopwatch.start();

    PlaylistCollection::scanFolders();

Michael Pyne's avatar
Michael Pyne committed
229 230
    qCDebug(JUK_LOG) << "Folder scan complete, took" << stopwatch.elapsed() << "ms";
    qCDebug(JUK_LOG) << "Startup complete!";
231 232 233
    emit startupComplete();
}

234 235 236 237
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox public slots
////////////////////////////////////////////////////////////////////////////////

238 239
void PlaylistBox::paste()
{
240
    // TODO: Reimplement
241 242
}

243 244 245 246
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox protected methods
////////////////////////////////////////////////////////////////////////////////

247 248
void PlaylistBox::slotFreezePlaylists()
{
249
    setDynamicListsFrozen(true);
250 251 252 253
}

void PlaylistBox::slotUnfreezePlaylists()
{
254
    setDynamicListsFrozen(false);
255 256
}

257 258
void PlaylistBox::slotPlaylistDataChanged()
{
259 260
    if(m_savePlaylistTimer)
        m_savePlaylistTimer->start(); // Restarts the timer if it's already running.
261 262
}

263 264 265 266 267
void PlaylistBox::slotSetHistoryPlaylistEnabled(bool enable)
{
    setHistoryPlaylistEnabled(enable);
}

268 269
void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName)
{
270 271 272 273 274
    setupPlaylist(playlist, iconName, 0);
}

void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName, Item *parentItem)
{
Laurent Montel's avatar
Laurent Montel committed
275 276
    connect(playlist, SIGNAL(signalPlaylistItemsDropped(Playlist*)),
            SLOT(slotPlaylistItemsDropped(Playlist*)));
277

278
    PlaylistCollection::setupPlaylist(playlist, iconName);
279 280

    if(parentItem)
281
        new Item(parentItem, iconName, playlist->name(), playlist);
282
    else
283
        new Item(this, iconName, playlist->name(), playlist);
284 285
}

286
void PlaylistBox::removePlaylist(Playlist *playlist)
287
{
288
    // Could be false if setup() wasn't run yet.
289
    if(m_playlistDict.contains(playlist)) {
290
        removeNameFromDict(m_playlistDict[playlist]->text(0));
291 292
        delete m_playlistDict[playlist]; // Delete the Item*
    }
293

294 295
    removeFileFromDict(playlist->fileName());
    m_playlistDict.remove(playlist);
296
}
297

298 299 300 301
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox private methods
////////////////////////////////////////////////////////////////////////////////

302 303
void PlaylistBox::readConfig()
{
304
    KConfigGroup config(KSharedConfig::openConfig(), "PlaylistBox");
305
    m_viewModeIndex = config.readEntry("ViewMode", 0);
306 307 308 309 310

    // TODO Restore ability to use Tree View once fixed.
    if(m_viewModeIndex == 2) {
        m_viewModeIndex = 0;
    }
311 312 313 314
}

void PlaylistBox::saveConfig()
{
315
    KConfigGroup config(KSharedConfig::openConfig(), "PlaylistBox");
316
    config.writeEntry("ViewMode", action<KSelectAction>("viewModeMenu")->currentItem());
317
    KSharedConfig::openConfig()->sync();
318 319
}

320
void PlaylistBox::remove()
321
{
322
    ItemList items = selectedBoxItems();
323

324
    if(items.isEmpty())
325
        return;
326

327
    QStringList files;
328
    QStringList names;
329

330
    foreach(Item *item, items) {
331
        if(item && item->playlist())
332
        {
333 334 335
           if (!item->playlist()->fileName().isEmpty() &&
               QFileInfo(item->playlist()->fileName()).exists())
           {
336
            files.append(item->playlist()->fileName());
337
           }
338

339 340
           names.append(item->playlist()->name());
        }
341 342
    }

343
    if(!files.isEmpty()) {
344
        int remove = KMessageBox::warningYesNoCancelList(
345
            this, i18n("Do you want to delete these files from the disk as well?"), files, QString(), KStandardGuiItem::del(), KGuiItem(i18n("Keep")));
346 347 348

        if(remove == KMessageBox::Yes) {
            QStringList couldNotDelete;
Laurent Montel's avatar
Laurent Montel committed
349
            for(QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
350 351 352 353 354 355 356 357 358
                if(!QFile::remove(*it))
                    couldNotDelete.append(*it);
            }

            if(!couldNotDelete.isEmpty())
                KMessageBox::errorList(this, i18n("Could not delete these files."), couldNotDelete);
        }
        else if(remove == KMessageBox::Cancel)
            return;
359
    }
360
    else if(items.count() > 1 || items.front()->playlist() != upcomingPlaylist()) {
361 362 363 364 365
        if(KMessageBox::warningContinueCancelList(this,
                                                  i18n("Are you sure you want to remove these "
                                                       "playlists from your collection?"),
                                                  names,
                                                  i18n("Remove Items?"),
Pino Toscano's avatar
Pino Toscano committed
366
                                                  KGuiItem(i18n("&Remove"), "user-trash")) == KMessageBox::Cancel)
367 368 369
        {
            return;
        }
370
    }
371

372
    PlaylistList removeQueue;
373

Laurent Montel's avatar
Laurent Montel committed
374
    for(ItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
375 376 377 378 379 380
        if(*it != Item::collectionItem() &&
           (*it)->playlist() &&
           (!(*it)->playlist()->readOnly()))
        {
            removeQueue.append((*it)->playlist());
        }
381
    }
382

383
    // FIXME removing items
384
    /*if(items.back()->nextSibling() && static_cast<Item *>(items.back()->nextSibling())->playlist())
385
        setSingleItem(items.back()->nextSibling());
386
    else {
387 388 389
        Item *i = static_cast<Item *>(items.front()->itemAbove());
        while(i && !i->playlist())
            i = static_cast<Item *>(i->itemAbove());
390

391 392
        if(!i)
            i = Item::collectionItem();
393

394
        setSingleItem(i);
395
    }*/
396

Laurent Montel's avatar
Laurent Montel committed
397
    for(PlaylistList::ConstIterator it = removeQueue.constBegin(); it != removeQueue.constEnd(); ++it) {
398 399 400 401 402 403
        if(*it != upcomingPlaylist())
            delete *it;
        else {
            action<KToggleAction>("showUpcoming")->setChecked(false);
            setUpcomingPlaylistEnabled(false);
        }
404
    }
405 406
}

407
void PlaylistBox::setDynamicListsFrozen(bool frozen)
408
{
409
    for(QList<ViewMode *>::Iterator it = m_viewModes.begin();
410 411
        it != m_viewModes.end();
        ++it)
412
    {
413
        (*it)->setDynamicListsFrozen(frozen);
414
    }
415 416
}

417 418
void PlaylistBox::slotSavePlaylists()
{
Michael Pyne's avatar
Michael Pyne committed
419
    qCDebug(JUK_LOG) << "Auto-saving playlists.\n";
420 421 422

    PlaylistList l;
    CollectionList *collection = CollectionList::instance();
423 424
    for(QTreeWidgetItemIterator it(topLevelItem(0)); *it; ++it) {
        Item *item = static_cast<Item *>(*it);
425 426
        if(item->playlist() && item->playlist() != collection)
            l.append(item->playlist());
427 428 429 430 431
    }

    Cache::savePlaylists(l);
}

432 433 434
void PlaylistBox::slotShowDropTarget()
{
    if(!m_dropItem) {
Michael Pyne's avatar
Michael Pyne committed
435
        qCCritical(JUK_LOG) << "Trying to show the playlist of a null item!\n";
436
        return;
437 438
    }

439
    raise(m_dropItem->playlist());
440 441
}

442 443
void PlaylistBox::slotAddItem(const QString &tag, unsigned column)
{
444 445
    for(QList<ViewMode *>::Iterator it = m_viewModes.begin(); it != m_viewModes.end(); ++it)
        (*it)->addItems(QStringList(tag), column);
446 447 448 449
}

void PlaylistBox::slotRemoveItem(const QString &tag, unsigned column)
{
450
    for(QList<ViewMode *>::Iterator it = m_viewModes.begin(); it != m_viewModes.end(); ++it)
451
        (*it)->removeItem(tag, column);
452 453
}

454
void PlaylistBox::mousePressEvent(QMouseEvent *e)
455
{
456
    if(e->button() == Qt::LeftButton)
457
        m_doingMultiSelect = true;
458
    QTreeWidget::mousePressEvent(e);
459 460
}

461
void PlaylistBox::mouseReleaseEvent(QMouseEvent *e)
462
{
463
    if(e->button() == Qt::LeftButton) {
464 465
        m_doingMultiSelect = false;
        slotPlaylistChanged();
466
    }
467
    QTreeWidget::mouseReleaseEvent(e);
468 469
}

470 471
void PlaylistBox::keyPressEvent(QKeyEvent *e)
{
472
    if((e->key() == Qt::Key_Up || e->key() == Qt::Key_Down) && e->modifiers() == Qt::ShiftModifier)
473
        m_doingMultiSelect = true;
474
    QTreeWidget::keyPressEvent(e);
475 476 477 478
}

void PlaylistBox::keyReleaseEvent(QKeyEvent *e)
{
479
    if(m_doingMultiSelect && e->key() == Qt::Key_Shift) {
480 481
        m_doingMultiSelect = false;
        slotPlaylistChanged();
482
    }
483
    QTreeWidget::keyReleaseEvent(e);
484 485
}

486
PlaylistBox::ItemList PlaylistBox::selectedBoxItems() const
487
{
488
    ItemList l;
489

490 491
    for(QTreeWidgetItemIterator it(const_cast<PlaylistBox *>(this),
                                 QTreeWidgetItemIterator::Selected); *it; ++it)
492
        l.append(static_cast<Item *>(*it));
493

494 495 496
    return l;
}

497
void PlaylistBox::setSingleItem(QTreeWidgetItem *item)
498
{
499 500 501
    setSelectionMode(QAbstractItemView::SingleSelection);
    setCurrentItem(item);
    setSelectionMode(QAbstractItemView::ExtendedSelection);
502 503
}

504 505 506 507
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox private slots
////////////////////////////////////////////////////////////////////////////////

508
void PlaylistBox::slotPlaylistChanged()
509
{
510 511
    // Don't update while the mouse is pressed down.

512
    if(m_doingMultiSelect)
513
        return;
514

515
    ItemList items = selectedBoxItems();
516 517
    m_hasSelection = !items.isEmpty();

518 519
    bool allowReload = false;

520
    PlaylistList playlists;
Laurent Montel's avatar
Laurent Montel committed
521
    for(ItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
522

523 524 525 526 527 528
        Playlist *p = (*it)->playlist();
        if(p) {
            if(p->canReload())
                allowReload = true;
            playlists.append(p);
        }
529 530
    }

531 532
    bool singlePlaylist = playlists.count() == 1;

533
    if(playlists.isEmpty() ||
534
       (singlePlaylist &&
535 536
        (playlists.front() == CollectionList::instance() ||
         playlists.front()->readOnly())))
537 538 539 540 541 542 543 544 545 546 547
    {
        action("file_save")->setEnabled(false);
        action("file_save_as")->setEnabled(false);
        action("renamePlaylist")->setEnabled(false);
        action("deleteItemPlaylist")->setEnabled(false);
    }
    else {
        action("file_save")->setEnabled(true);
        action("file_save_as")->setEnabled(true);
        action("renamePlaylist")->setEnabled(playlists.count() == 1);
        action("deleteItemPlaylist")->setEnabled(true);
548
    }
549 550
    action("reloadPlaylist")->setEnabled(allowReload);
    action("duplicatePlaylist")->setEnabled(!playlists.isEmpty());
551

552
    action("editSearch")->setEnabled(singlePlaylist &&
553
                                     playlists.front()->searchIsEditable());
554

555
    if(singlePlaylist) {
556
        PlaylistCollection::raise(playlists.front());
557

558 559 560 561
        if(playlists.front() == upcomingPlaylist())
            action("deleteItemPlaylist")->setText(i18n("Hid&e"));
        else
            action("deleteItemPlaylist")->setText(i18n("R&emove"));
562
    }
563
    else if(!playlists.isEmpty())
564
        createDynamicPlaylist(playlists);
565 566
}

567
void PlaylistBox::slotDoubleClicked(QTreeWidgetItem *item)
568
{
569 570 571
    if(!item)
        return;

572 573 574
    TrackSequenceManager *manager = TrackSequenceManager::instance();
    Item *playlistItem = static_cast<Item *>(item);

575
    manager->setCurrentPlaylist(playlistItem->playlist());
576 577 578 579 580

    manager->setCurrent(0); // Reset playback
    PlaylistItem *next = manager->nextItem(); // Allow manager to choose

    if(next) {
581
        emit startFilePlayback(next->file());
582 583 584 585
        playlistItem->playlist()->setPlaying(next);
    }
    else
        action("stop")->trigger();
586 587
}

588
void PlaylistBox::slotShowContextMenu(const QPoint &point)
589
{
590
    m_contextMenu->popup(mapToGlobal(point));
591 592
}

593 594 595 596 597
void PlaylistBox::slotPlaylistItemsDropped(Playlist *p)
{
    raise(p);
}

598
void PlaylistBox::slotSetViewMode(int index)
599
{
600
    if(index == m_viewModeIndex)
601
        return;
602 603 604

    viewMode()->setShown(false);
    m_viewModeIndex = index;
Laurent Montel's avatar
Laurent Montel committed
605
    viewMode()->setShown(true);
606 607
}

608
void PlaylistBox::setupItem(Item *item)
609
{
610 611
    m_playlistDict.insert(item->playlist(), item);
    viewMode()->queueRefresh();
612 613
}

614 615
void PlaylistBox::setupUpcomingPlaylist()
{
616
    KConfigGroup config(KSharedConfig::openConfig(), "Playlists");
617
    bool enable = config.readEntry("showUpcoming", false);
618 619 620 621 622

    setUpcomingPlaylistEnabled(enable);
    action<KToggleAction>("showUpcoming")->setChecked(enable);
}

Michael Pyne's avatar
Michael Pyne committed
623 624 625

void PlaylistBox::slotLoadCachedPlaylists()
{
Michael Pyne's avatar
Michael Pyne committed
626
    qCDebug(JUK_LOG) << "Loading cached playlists.";
627 628 629
    QTime stopwatch;
    stopwatch.start();

Michael Pyne's avatar
Michael Pyne committed
630
    Cache::loadPlaylists(this);
631

Michael Pyne's avatar
Michael Pyne committed
632
    qCDebug(JUK_LOG) << "Cached playlists loaded, took" << stopwatch.elapsed() << "ms";
633

634 635 636 637 638 639
    // Auto-save playlists after they change.
    m_savePlaylistTimer = new QTimer(this);
    m_savePlaylistTimer->setInterval(3000); // 3 seconds with no change? -> commit
    m_savePlaylistTimer->setSingleShot(true);
    connect(m_savePlaylistTimer, SIGNAL(timeout()), SLOT(slotSavePlaylists()));

Michael Pyne's avatar
Michael Pyne committed
640
    clearSelection();
641
    setCurrentItem(m_playlistDict[CollectionList::instance()]);
642 643 644

    QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
    QTimer::singleShot(0, object(), SLOT(slotScanFolders()));
Michael Pyne's avatar
Michael Pyne committed
645
}
646

647
////////////////////////////////////////////////////////////////////////////////
648
// PlaylistBox::Item protected methods
649 650
////////////////////////////////////////////////////////////////////////////////

651 652
PlaylistBox::Item *PlaylistBox::Item::m_collectionItem = 0;

653
PlaylistBox::Item::Item(PlaylistBox *listBox, const QString &icon, const QString &text, Playlist *l)
654
    : QObject(listBox), QTreeWidgetItem(listBox, QStringList(text)),
655
      PlaylistObserver(l),
656
      m_playlist(l), m_text(text), m_iconName(icon), m_sortedFirst(false)
657
{
658 659
    init();
}
660

661
PlaylistBox::Item::Item(Item *parent, const QString &icon, const QString &text, Playlist *l)
662
    : QObject(parent->listView()), QTreeWidgetItem(parent, QStringList(text)),
663
    PlaylistObserver(l),
664
    m_playlist(l), m_text(text), m_iconName(icon), m_sortedFirst(false)
665 666
{
    init();
667 668
}

669
PlaylistBox::Item::~Item()
670 671 672 673
{

}

674
int PlaylistBox::Item::compare(QTreeWidgetItem *i, int col, bool) const
675
{
676
    Item *otherItem = static_cast<Item *>(i);
677
    PlaylistBox *playlistBox = static_cast<PlaylistBox *>(treeWidget());
678 679

    if(m_playlist == playlistBox->upcomingPlaylist() && otherItem->m_playlist != CollectionList::instance())
680
        return -1;
681
    if(otherItem->m_playlist == playlistBox->upcomingPlaylist() && m_playlist != CollectionList::instance())
682
        return 1;
683 684

    if(m_sortedFirst && !otherItem->m_sortedFirst)
685
        return -1;
686
    else if(otherItem->m_sortedFirst && !m_sortedFirst)
687
        return 1;
688

Dirk Mueller's avatar
Dirk Mueller committed
689
    return text(col).toLower().localeAwareCompare(i->text(col).toLower());
690 691
}

692
    // FIXME paintcell
693
/*void PlaylistBox::Item::paintCell(QPainter *painter, const QColorGroup &colorGroup, int column, int width, int align)
694
{
695 696
    PlaylistBox *playlistBox = static_cast<PlaylistBox *>(listView());
    playlistBox->viewMode()->paintCell(this, painter, colorGroup, column, width, align);
697
}*/
698 699 700 701

void PlaylistBox::Item::setText(int column, const QString &text)
{
    m_text = text;
702
    QTreeWidgetItem::setText(column, text);
703 704
}

705 706 707 708 709
void PlaylistBox::Item::setup()
{
    listView()->viewMode()->setupItem(this);
}

710 711 712 713 714 715 716
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox::Item protected slots
////////////////////////////////////////////////////////////////////////////////

void PlaylistBox::Item::slotSetName(const QString &name)
{
    if(listView()) {
717 718
        setText(0, name);
        setSelected(true);
719

Kacper Kasper's avatar
Kacper Kasper committed
720 721
        treeWidget()->sortItems(0, Qt::AscendingOrder);
        treeWidget()->scrollToItem(treeWidget()->currentItem());
722
        //FIXME viewmode
Kacper Kasper's avatar
Kacper Kasper committed
723
        //listView()->viewMode()->queueRefresh();
724 725 726
    }
}

727
void PlaylistBox::Item::playingItemHasChanged()
728 729 730
{
}

731
void PlaylistBox::Item::playlistItemDataHasChanged()
732 733 734 735
{
    listView()->slotPlaylistDataChanged();
}

736 737 738 739 740 741
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox::Item private methods
////////////////////////////////////////////////////////////////////////////////

void PlaylistBox::Item::init()
{
742
    PlaylistBox *list = listView();
743 744 745 746

    list->setupItem(this);

    int iconSize = list->viewModeIndex() == 0 ? 32 : 16;
747
    setIcon(0, SmallIcon(m_iconName, iconSize));
748
    list->addNameToDict(m_text);
749

750
    if(m_playlist) {
Laurent Montel's avatar
Laurent Montel committed
751 752
        connect(m_playlist, SIGNAL(signalNameChanged(QString)),
                this, SLOT(slotSetName(QString)));
753 754
        connect(m_playlist, SIGNAL(signalEnableDirWatch(bool)),
                list->object(), SLOT(slotEnableDirWatch(bool)));
755
    }
756

757
    if(m_playlist == CollectionList::instance()) {
758 759 760
        m_sortedFirst = true;
        m_collectionItem = this;
        list->viewMode()->setupDynamicPlaylists();
761
    }
762

763
    if(m_playlist == list->historyPlaylist() || m_playlist == list->upcomingPlaylist())
764
        m_sortedFirst = true;
765 766
}

767
// vim: set et sw=4 tw=0 sta: