File indexing completed on 2023-05-30 11:30:45
0001 /** 0002 * Copyright (C) 2005 Michael Pyne <mpyne@kde.org> 0003 * Copyright (C) 2014 Arnold Dumas <contact@arnolddumas.fr> 0004 * 0005 * This program is free software; you can redistribute it and/or modify it under 0006 * the terms of the GNU General Public License as published by the Free Software 0007 * Foundation; either version 2 of the License, or (at your option) any later 0008 * version. 0009 * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU General Public License along with 0015 * this program. If not, see <http://www.gnu.org/licenses/>. 0016 */ 0017 0018 #include "coverdialog.h" 0019 0020 #include <KLocalizedString> 0021 #include <kiconloader.h> 0022 0023 #include <QTimer> 0024 #include <QMenu> 0025 0026 #include "covericonview.h" 0027 #include "covermanager.h" 0028 #include "collectionlist.h" 0029 #include "juk_debug.h" 0030 0031 using CoverUtility::CoverIconViewItem; 0032 0033 class AllArtistsListViewItem : public QListWidgetItem 0034 { 0035 public: 0036 AllArtistsListViewItem(QListWidget *parent) : 0037 QListWidgetItem(i18n("<All Artists>"), parent) 0038 { 0039 } 0040 0041 bool operator< (const QListWidgetItem& other) const override 0042 { 0043 Q_UNUSED(other); 0044 return true; // Always be at the top. 0045 } 0046 }; 0047 0048 class CaseInsensitiveItem : public QListWidgetItem 0049 { 0050 public: 0051 CaseInsensitiveItem(QListWidget *parent, const QString &text) : 0052 QListWidgetItem(text, parent) 0053 { 0054 } 0055 0056 bool operator< (const QListWidgetItem& other) const override 0057 { 0058 return text().toLower().localeAwareCompare(other.text().toLower()); 0059 } 0060 }; 0061 0062 CoverDialog::CoverDialog(QWidget *parent) : 0063 QWidget(parent, Qt::Dialog) 0064 { 0065 setupUi(this); 0066 0067 setObjectName(QLatin1String("juk_cover_dialog")); 0068 0069 m_searchLine->setClearButtonEnabled(true); 0070 0071 connect(m_artists, SIGNAL(itemClicked(QListWidgetItem*)), 0072 this, SLOT(slotArtistClicked(QListWidgetItem*))); 0073 0074 connect(m_covers, SIGNAL(customContextMenuRequested(QPoint)), 0075 this, SLOT(slotContextRequested(QPoint))); 0076 0077 connect(m_searchLine, SIGNAL(textChanged(QString)), 0078 this, SLOT(slotSearchPatternChanged(QString))); 0079 } 0080 0081 CoverDialog::~CoverDialog() 0082 { 0083 } 0084 0085 void CoverDialog::show() 0086 { 0087 m_artists->clear(); 0088 m_covers->clear(); 0089 0090 QStringList artists = CollectionList::instance()->uniqueSet(CollectionList::Artists); 0091 0092 new AllArtistsListViewItem(m_artists); 0093 for(QStringList::ConstIterator it = artists.constBegin(); it != artists.constEnd(); ++it) 0094 new CaseInsensitiveItem(m_artists, *it); 0095 0096 QTimer::singleShot(0, this, SLOT(loadCovers())); 0097 QWidget::show(); 0098 } 0099 0100 // TODO: Make this concurrent on a non-GUI thread 0101 void CoverDialog::loadCovers() 0102 { 0103 auto it = CoverManager::begin(); 0104 const auto &end = CoverManager::end(); 0105 0106 for(; it != end; ++it) { 0107 (void) new CoverIconViewItem(it->first, m_covers); 0108 } 0109 } 0110 0111 // TODO: Add a way to show cover art for tracks with no artist. 0112 void CoverDialog::slotArtistClicked(QListWidgetItem *item) 0113 { 0114 m_covers->clear(); 0115 if (!item) { 0116 return; 0117 } 0118 if(dynamic_cast<AllArtistsListViewItem *>(item)) { 0119 // All artists. 0120 loadCovers(); 0121 } 0122 else { 0123 QString artist = item->text().toLower(); 0124 0125 CoverDataMapIterator it, end; 0126 0127 it = CoverManager::begin(); 0128 end = CoverManager::end(); 0129 0130 for(; it != end; ++it) { 0131 if(it->second.artist == artist) 0132 (void) new CoverIconViewItem(it->first, m_covers); 0133 } 0134 } 0135 } 0136 0137 void CoverDialog::slotContextRequested(const QPoint &pt) 0138 { 0139 static QMenu *menu = nullptr; 0140 0141 QListWidgetItem* item = m_covers->currentItem(); 0142 0143 if(!item) 0144 return; 0145 0146 if(!menu) { 0147 menu = new QMenu(this); 0148 menu->addAction(i18n("Remove Cover"), this, SLOT(removeSelectedCover())); 0149 } 0150 0151 QPoint globalPt = m_covers->mapToGlobal(pt); 0152 menu->popup(globalPt); 0153 } 0154 0155 void CoverDialog::slotSearchPatternChanged(const QString& pattern) 0156 { 0157 m_covers->clear(); 0158 0159 QListWidgetItem* item = m_artists->currentItem(); 0160 0161 // If the expression is cleared, then use slotArtistClicked. 0162 if (pattern.isEmpty()) { 0163 slotArtistClicked(item); 0164 } 0165 0166 else { 0167 QRegExp filter(pattern, Qt::CaseInsensitive, QRegExp::Wildcard); 0168 QString artist = item->text().toLower(); 0169 0170 CoverDataMapIterator it = CoverManager::begin(); 0171 const CoverDataMapIterator end = CoverManager::end(); 0172 0173 // Here, only show cover that match the search pattern. 0174 if (dynamic_cast<AllArtistsListViewItem *>(item)) { 0175 for(; it != end; ++it) { 0176 if (filter.indexIn(it->second.artist) != -1) { 0177 (void) new CoverIconViewItem(it->first, m_covers); 0178 } 0179 } 0180 } 0181 // Here, only show the covers that match the search pattern and 0182 // that have the same artist as the currently selected one. 0183 else { 0184 for(; it != end; ++it) { 0185 if (it->second.artist == artist 0186 && ((filter.indexIn(it->second.artist) != -1) 0187 || (filter.indexIn(it->second.album) != -1))) 0188 { 0189 (void) new CoverIconViewItem(it->first, m_covers); 0190 } 0191 } 0192 } 0193 } 0194 } 0195 0196 void CoverDialog::removeSelectedCover() 0197 { 0198 CoverIconViewItem *coverItem = m_covers->currentItem(); 0199 0200 if(!coverItem || !coverItem->isSelected()) { 0201 qCWarning(JUK_LOG) << "No item selected for removeSelectedCover.\n"; 0202 return; 0203 } 0204 0205 if(!CoverManager::removeCover(coverItem->id())) 0206 qCCritical(JUK_LOG) << "Unable to remove selected cover: " << coverItem->id(); 0207 else 0208 delete coverItem; 0209 } 0210 0211 // vim: set et sw=4 tw=0 sta: