/* * Cantata * * Copyright (c) 2011-2014 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "synccollectionwidget.h" #include "widgets/treeview.h" #include "models/musiclibraryproxymodel.h" #include "models/musiclibraryitemartist.h" #include "models/musiclibraryitemalbum.h" #include "models/musiclibraryitemsong.h" #include "support/icon.h" #include "support/localize.h" #include "support/actioncollection.h" #include #include SyncCollectionWidget::SyncCollectionWidget(QWidget *parent, const QString &title, const QString &action) : QWidget(parent) , performedSearch(false) , searchTimer(0) { setupUi(this); titleLabel->setText(title); button->setText(action); button->setEnabled(false); model=new MusicLibraryModel(this, false, true); proxy=new MusicLibraryProxyModel(this); proxy->setSourceModel(model); tree->setModel(proxy); tree->setPageDefaults(); tree->setUseSimpleDelegate(); search->setText(QString()); search->setPlaceholderText(i18n("Search")); connect(proxy, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex))); connect(model, SIGNAL(checkedSongs(QSet)), this, SLOT(songsChecked(QSet))); connect(button, SIGNAL(clicked()), SLOT(copySongs())); connect(search, SIGNAL(returnPressed()), this, SLOT(delaySearchItems())); connect(search, SIGNAL(textChanged(const QString)), this, SLOT(delaySearchItems())); copyAction=new Action(action, this); connect(copyAction, SIGNAL(triggered()), SLOT(copySongs())); checkAction=new Action(i18n("Check Items"), this); connect(checkAction, SIGNAL(triggered()), SLOT(checkItems())); unCheckAction=new Action(i18n("Uncheck Items"), this); connect(unCheckAction, SIGNAL(triggered()), SLOT(unCheckItems())); tree->addAction(copyAction); QAction *sep=new QAction(this); sep->setSeparator(true); tree->addAction(sep); tree->addAction(checkAction); tree->addAction(unCheckAction); tree->setContextMenuPolicy(Qt::ActionsContextMenu); QAction *expand=ActionCollection::get()->action("expandall"); QAction *collapse=ActionCollection::get()->action("collapseall"); if (expand && collapse) { sep=new QAction(this); sep->setSeparator(true); tree->addAction(sep); tree->addAction(expand); tree->addAction(collapse); addAction(expand); addAction(collapse); connect(expand, SIGNAL(triggered()), this, SLOT(expandAll())); connect(collapse, SIGNAL(triggered()), this, SLOT(collapseAll())); } connect(tree, SIGNAL(itemsSelected(bool)), checkAction, SLOT(setEnabled(bool))); connect(tree, SIGNAL(itemsSelected(bool)), unCheckAction, SLOT(setEnabled(bool))); connect(tree, SIGNAL(itemActivated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &))); connect(tree, SIGNAL(clicked(const QModelIndex &)), this, SLOT(itemClicked(const QModelIndex &))); updateStats(); } SyncCollectionWidget::~SyncCollectionWidget() { } void SyncCollectionWidget::setIcon(const Icon &icon) { tree->setBackgroundImage(icon); } void SyncCollectionWidget::checkItems() { checkItems(true); } void SyncCollectionWidget::unCheckItems() { checkItems(false); } void SyncCollectionWidget::checkItems(bool c) { const QModelIndexList selected = tree->selectedIndexes(); if (0==selected.size()) { return; } foreach (const QModelIndex &idx, selected) { model->setData(proxy->mapToSource(idx), c, Qt::CheckStateRole); } } void SyncCollectionWidget::copySongs() { if (checkedSongs.isEmpty()) { return; } QList songs=checkedSongs.toList(); qSort(songs); emit copy(songs); } void SyncCollectionWidget::delaySearchItems() { if (search->text().trimmed().isEmpty()) { if (searchTimer) { searchTimer->stop(); } if (performedSearch) { tree->collapseToLevel(0); } searchItems(); performedSearch=false; } else { if (!searchTimer) { searchTimer=new QTimer(this); searchTimer->setSingleShot(true); connect(searchTimer, SIGNAL(timeout()), SLOT(searchItems())); } searchTimer->start(500); } } void SyncCollectionWidget::searchItems() { QString text=search->text().trimmed(); proxy->update(text); if (proxy->enabled() && !text.isEmpty()) { tree->expandAll(); } performedSearch=true; } void SyncCollectionWidget::expandAll() { QWidget *f=QApplication::focusWidget(); if (f && qobject_cast(f)) { static_cast(f)->expandAll(); } } void SyncCollectionWidget::collapseAll() { QWidget *f=QApplication::focusWidget(); if (f && qobject_cast(f)) { static_cast(f)->collapseAll(); } } void SyncCollectionWidget::itemClicked(const QModelIndex &index) { if (TreeView::getForceSingleClick() && !tree->checkBoxClicked(index)) { tree->setExpanded(index, !tree->isExpanded(index)); } } void SyncCollectionWidget::itemActivated(const QModelIndex &index) { if (!TreeView::getForceSingleClick()) { tree->setExpanded(index, !tree->isExpanded(index)); } } void SyncCollectionWidget::songsChecked(const QSet &songs) { checkedSongs=songs; button->setEnabled(!checkedSongs.isEmpty()); updateStats(); } void SyncCollectionWidget::dataChanged(const QModelIndex &tl, const QModelIndex &br) { QModelIndex firstIndex = proxy->mapToSource(tl); QModelIndex lastIndex = proxy->mapToSource(br); const MusicLibraryItem *item=static_cast(firstIndex.internalPointer()); switch (item->itemType()) { case MusicLibraryItem::Type_Artist: for (int i=firstIndex.row(); i<=lastIndex.row(); ++i) { QModelIndex index=model->index(i, 0, firstIndex.parent()); const MusicLibraryItemArtist *artist=static_cast(index.internalPointer()); foreach (const MusicLibraryItem *alItem, artist->childItems()) { foreach (const MusicLibraryItem *sItem, static_cast(alItem)->childItems()) { Song s=static_cast(sItem)->song(); if (Qt::Checked==item->checkState()) { checkedSongs.insert(s); } else { checkedSongs.remove(s); } } } } break; case MusicLibraryItem::Type_Album: for (int i=firstIndex.row(); i<=lastIndex.row(); ++i) { QModelIndex index=model->index(i, 0, firstIndex.parent()); const MusicLibraryItemAlbum *album=static_cast(index.internalPointer()); foreach (const MusicLibraryItem *sItem, album->childItems()) { Song s=static_cast(sItem)->song(); if (Qt::Checked==item->checkState()) { checkedSongs.insert(s); } else { checkedSongs.remove(s); } } } break; case MusicLibraryItem::Type_Song: for (int i=firstIndex.row(); i<=lastIndex.row(); ++i) { QModelIndex index=model->index(i, 0, firstIndex.parent()); Song s=static_cast(index.internalPointer())->song(); if (Qt::Checked==item->checkState()) { checkedSongs.insert(s); } else { checkedSongs.remove(s); } } default: break; } button->setEnabled(!checkedSongs.isEmpty()); updateStats(); } void SyncCollectionWidget::updateStats() { QSet artists; QSet albums; foreach (const Song &s, checkedSongs) { artists.insert(s.albumArtist()); albums.insert(s.albumArtist()+"--"+s.album); } if (checkedSongs.isEmpty()) { selection->setText(i18n("Nothing selected")); } else { selection->setText(i18n("Artists:%1, Albums:%2, Songs:%3", artists.count(), albums.count(), checkedSongs.count())); } copyAction->setEnabled(!checkedSongs.isEmpty()); }