playlistbox.cpp 22.7 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 <kmessagebox.h>
20
#include <kactioncollection.h>
Laurent Montel's avatar
Poirt  
Laurent Montel committed
21 22
#include <ktoggleaction.h>
#include <kselectaction.h>
23
#include <kconfiggroup.h>
Michael Pyne's avatar
Michael Pyne committed
24
#include <KSharedConfig>
25

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

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

using namespace ActionCollection;
60 61 62 63 64

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

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

80 81
    setColumnCount(2); // Use fake column for sorting
    setColumnHidden(1, true);
82
    setSortingEnabled(true);
83
    sortByColumn(1, Qt::AscendingOrder);
84

85
    header()->blockSignals(true);
86
    header()->hide();
87
    header()->blockSignals(false);
88

89 90
    viewport()->setAcceptDrops(true);
    setDropIndicatorShown(true);
91
    setSelectionMode(QAbstractItemView::ExtendedSelection);
Laurent Montel's avatar
Laurent Montel committed
92

Michael Pyne's avatar
Michael Pyne committed
93
    m_contextMenu = new QMenu(this);
94

95 96 97 98 99 100 101 102
    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
103

104
    m_contextMenu->addSeparator();
105

106
    // add the view modes stuff
Laurent Montel's avatar
Laurent Montel committed
107

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

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

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

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

127 128
    CollectionList::initialize(this);

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

132 133 134
    TrackSequenceManager::instance()->setCurrentPlaylist(CollectionList::instance());
    raise(CollectionList::instance());

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

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

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

144 145
    connect(this, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(slotShowContextMenu(QPoint)));
146

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

151
    setupUpcomingPlaylist();
152

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

160
    m_savePlaylistTimer = 0;
161

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

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

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

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

185 186
    Cache::savePlaylists(l);
    saveConfig();
187 188
}

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

194
    Item *i = m_playlistDict.value(playlist, 0);
195

196
    if(i) {
197
        clearSelection();
198
        setCurrentItem(i);
199

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

206
    slotPlaylistChanged();
207 208
}

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

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

217
    if(name.isNull())
218
        return;
219

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

224 225 226 227 228 229
void PlaylistBox::scanFolders()
{
    PlaylistCollection::scanFolders();
    emit startupComplete();
}

230 231 232 233
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox public slots
////////////////////////////////////////////////////////////////////////////////

234 235
void PlaylistBox::paste()
{
236
    // TODO: Reimplement
237 238
}

239 240 241 242
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox protected methods
////////////////////////////////////////////////////////////////////////////////

243 244
void PlaylistBox::slotFreezePlaylists()
{
245
    setDynamicListsFrozen(true);
246 247 248 249
}

void PlaylistBox::slotUnfreezePlaylists()
{
250
    setDynamicListsFrozen(false);
251 252
}

253 254
void PlaylistBox::slotPlaylistDataChanged()
{
255 256
    if(m_savePlaylistTimer)
        m_savePlaylistTimer->start(); // Restarts the timer if it's already running.
257 258
}

259 260 261 262 263
void PlaylistBox::slotSetHistoryPlaylistEnabled(bool enable)
{
    setHistoryPlaylistEnabled(enable);
}

264 265
void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName)
{
266
    setupPlaylist(playlist, iconName, nullptr);
267 268 269 270
}

void PlaylistBox::setupPlaylist(Playlist *playlist, const QString &iconName, Item *parentItem)
{
271 272 273 274
    connect(playlist, &Playlist::signalPlaylistItemsDropped,
            this,     &PlaylistBox::slotPlaylistItemsDropped);
    connect(playlist, &Playlist::signalMoveFocusAway,
            this,     &PlaylistBox::signalMoveFocusAway);
275

276
    PlaylistCollection::setupPlaylist(playlist, iconName);
277 278

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

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

292 293
    removeFileFromDict(playlist->fileName());
    m_playlistDict.remove(playlist);
294
}
295

296 297 298 299
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox private methods
////////////////////////////////////////////////////////////////////////////////

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

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

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

318
void PlaylistBox::remove()
319
{
320
    ItemList items = selectedBoxItems();
321

322
    if(items.isEmpty())
323
        return;
324

325
    QStringList files;
326
    QStringList names;
327

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

337 338
           names.append(item->playlist()->name());
        }
339 340
    }

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

        if(remove == KMessageBox::Yes) {
            QStringList couldNotDelete;
Laurent Montel's avatar
Laurent Montel committed
347
            for(QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
348 349 350 351 352 353 354 355 356
                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;
357
    }
358
    else if(items.count() > 1 || items.front()->playlist() != upcomingPlaylist()) {
359 360 361 362 363
        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
364
                                                  KGuiItem(i18n("&Remove"), "user-trash")) == KMessageBox::Cancel)
365 366 367
        {
            return;
        }
368
    }
369

370
    PlaylistList removeQueue;
371

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

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

389 390
        if(!i)
            i = Item::collectionItem();
391

392
        setSingleItem(i);
393
    }*/
394

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

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

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

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

    Cache::savePlaylists(l);
}

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

437
    raise(m_dropItem->playlist());
438 439
}

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

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

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

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

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

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

484
PlaylistBox::ItemList PlaylistBox::selectedBoxItems() const
485
{
486
    ItemList l;
487

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

492 493 494
    return l;
}

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

502 503 504 505
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox private slots
////////////////////////////////////////////////////////////////////////////////

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

510
    if(m_doingMultiSelect)
511
        return;
512

513
    ItemList items = selectedBoxItems();
514 515
    m_hasSelection = !items.isEmpty();

516 517
    bool allowReload = false;

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

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

529 530
    bool singlePlaylist = playlists.count() == 1;

531
    if(playlists.isEmpty() ||
532
       (singlePlaylist &&
533 534
        (playlists.front() == CollectionList::instance() ||
         playlists.front()->readOnly())))
535 536 537 538 539 540 541 542 543 544 545
    {
        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);
546
    }
547 548
    action("reloadPlaylist")->setEnabled(allowReload);
    action("duplicatePlaylist")->setEnabled(!playlists.isEmpty());
549

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

553
    if(singlePlaylist) {
554
        PlaylistCollection::raise(playlists.front());
555

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

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

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

573
    manager->setCurrentPlaylist(playlistItem->playlist());
574 575 576 577 578

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

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

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

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

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

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

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

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

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

Michael Pyne's avatar
Michael Pyne committed
621 622 623

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

Michael Pyne's avatar
Michael Pyne committed
628
    Cache::loadPlaylists(this);
629

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

632 633 634 635 636 637
    // 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
638
    clearSelection();
639
    setCurrentItem(m_playlistDict[CollectionList::instance()]);
640 641 642

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

645
////////////////////////////////////////////////////////////////////////////////
646
// PlaylistBox::Item protected methods
647 648
////////////////////////////////////////////////////////////////////////////////

649 650
PlaylistBox::Item *PlaylistBox::Item::m_collectionItem = 0;

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

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

667
PlaylistBox::Item::~Item()
668 669 670 671
{

}

672
// FIXME paintcell
673
/*void PlaylistBox::Item::paintCell(QPainter *painter, const QColorGroup &colorGroup, int column, int width, int align)
674
{
675 676
    PlaylistBox *playlistBox = static_cast<PlaylistBox *>(listView());
    playlistBox->viewMode()->paintCell(this, painter, colorGroup, column, width, align);
677
}*/
678

679 680 681 682 683
void PlaylistBox::Item::setup()
{
    listView()->viewMode()->setupItem(this);
}

684 685 686 687 688 689
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox::Item protected slots
////////////////////////////////////////////////////////////////////////////////

void PlaylistBox::Item::slotSetName(const QString &name)
{
690 691 692
    setText(0, name); // Display name
    setText(1, sortTextFor(name));
    setSelected(true);
693

694 695 696
    treeWidget()->scrollToItem(this);
    //FIXME viewmode
    //listView()->viewMode()->queueRefresh();
697 698
}

699
void PlaylistBox::Item::playingItemHasChanged()
700 701 702
{
}

703
void PlaylistBox::Item::playlistItemDataHasChanged()
704
{
705 706 707 708
    // This avoids spuriously re-saving all playlists just because play queue
    // changes.
    if(m_playlist != listView()->upcomingPlaylist())
        listView()->slotPlaylistDataChanged();
709 710
}

711 712 713 714 715 716
////////////////////////////////////////////////////////////////////////////////
// PlaylistBox::Item private methods
////////////////////////////////////////////////////////////////////////////////

void PlaylistBox::Item::init()
{
717
    PlaylistBox *list = listView();
718 719 720

    list->setupItem(this);

721
    const QString itemText(text());
722
    setIcon(0, QIcon::fromTheme(m_iconName));
723
    list->addNameToDict(itemText);
724

725
    if(m_playlist) {
Laurent Montel's avatar
Laurent Montel committed
726 727
        connect(m_playlist, SIGNAL(signalNameChanged(QString)),
                this, SLOT(slotSetName(QString)));
728 729
        connect(m_playlist, SIGNAL(signalEnableDirWatch(bool)),
                list->object(), SLOT(slotEnableDirWatch(bool)));
730
    }
731

732
    if(m_playlist == CollectionList::instance()) {
733 734 735
        m_sortedFirst = true;
        m_collectionItem = this;
        list->viewMode()->setupDynamicPlaylists();
736
    }
737

738
    if(m_playlist == list->historyPlaylist() || m_playlist == list->upcomingPlaylist())
739
        m_sortedFirst = true;
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755

    setText(1, sortTextFor(itemText));
}

QString PlaylistBox::Item::sortTextFor(const QString &name) const
{
    // Collection List goes before everything, then
    // playlists that 'sort first', then remainder of
    // playlists.
    const auto prefix
        = (playlist() == CollectionList::instance())
            ? QStringLiteral("0")
            : m_sortedFirst
                ? QStringLiteral("1")
                : QStringLiteral("2");
    return prefix + name;
756 757
}

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