File indexing completed on 2024-05-05 04:47:44
0001 /**************************************************************************************** 0002 * Copyright (c) 2017 Malte Veerman <malte.veerman@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #define DEBUG_PREFIX "AppletModel" 0018 0019 #include "AppletModel.h" 0020 0021 #include "AmarokContextPackageStructure.h" 0022 #include "AppletLoader.h" 0023 #include "core/support/Amarok.h" 0024 #include "core/support/Debug.h" 0025 0026 #include <QUrl> 0027 0028 #include <KPackage/Package> 0029 #include <KPackage/PackageLoader> 0030 #include <KPluginInfo> 0031 0032 #include <algorithm> 0033 0034 0035 using namespace Context; 0036 0037 0038 class Context::AppletPackage : public KPackage::Package 0039 { 0040 public: 0041 AppletPackage(const KPackage::Package &package) : KPackage::Package(package) {} 0042 0043 bool operator==(const AppletPackage &p) 0044 { 0045 return metadata() == p.metadata(); 0046 } 0047 }; 0048 0049 0050 AppletModel::AppletModel(AppletLoader *loader, QObject* parent) 0051 : QAbstractListModel(parent) 0052 , m_loader(loader) 0053 { 0054 newApplets(loader->applets()); 0055 connect(loader, &AppletLoader::finished, this, &AppletModel::newApplets); 0056 } 0057 0058 AppletModel::~AppletModel() 0059 { 0060 } 0061 0062 int AppletModel::rowCount(const QModelIndex& parent) const 0063 { 0064 Q_UNUSED(parent) 0065 0066 return m_packages.size(); 0067 } 0068 0069 void AppletModel::newApplets(const QList<KPluginMetaData>& applets) 0070 { 0071 DEBUG_BLOCK 0072 0073 beginResetModel(); 0074 0075 m_packages.clear(); 0076 0077 for (const auto &applet : applets) 0078 { 0079 auto loader = KPackage::PackageLoader::self(); 0080 auto structure = new AmarokContextPackageStructure; 0081 loader->addKnownPackageStructure(QStringLiteral("Amarok/Context"), structure); 0082 auto package = loader->loadPackage(QStringLiteral("Amarok/Context"), applet.pluginId()); 0083 0084 if (package.isValid()) 0085 { 0086 m_packages << package; 0087 } 0088 else 0089 error() << "Error loading package:" << applet.pluginId(); 0090 } 0091 0092 //Sort applets by name 0093 std::sort(m_packages.begin(), m_packages.end(), [] (const AppletPackage &p1, const AppletPackage &p2) { 0094 return p1.metadata().name() < p2.metadata().name(); 0095 }); 0096 0097 endResetModel(); 0098 } 0099 0100 QVariant AppletModel::data(const QModelIndex& index, int role) const 0101 { 0102 int row = index.row(); 0103 0104 if (row >= m_packages.size()) 0105 return QVariant(); 0106 0107 const auto &package = m_packages.at(row); 0108 0109 switch (role) 0110 { 0111 case Name: 0112 return package.metadata().name(); 0113 0114 case Id: 0115 return package.metadata().pluginId(); 0116 0117 case Icon: 0118 return package.fileUrl("icon"); 0119 0120 case Mainscript: 0121 return package.fileUrl("mainscript"); 0122 0123 case Collapsed: 0124 return Amarok::config(QStringLiteral("Context")).readEntry(package.metadata().pluginId() + "_collapsed", false); 0125 0126 case ContentHeight: 0127 return Amarok::config(QStringLiteral("Context")).readEntry(package.metadata().pluginId() + "_contentHeight", 300); 0128 } 0129 0130 return QVariant(); 0131 } 0132 0133 bool Context::AppletModel::setData(const QModelIndex& index, const QVariant& value, int role) 0134 { 0135 int row = index.row(); 0136 0137 if (row >= m_packages.size()) 0138 return false; 0139 0140 const auto &package = m_packages.at(row); 0141 0142 switch (role) 0143 { 0144 case Collapsed: 0145 { 0146 Amarok::config(QStringLiteral("Context")).writeEntry(package.metadata().pluginId() + "_collapsed", value.toBool()); 0147 Q_EMIT dataChanged(index, index, QVector<int>{role}); 0148 return true; 0149 } 0150 case ContentHeight: 0151 { 0152 Amarok::config(QStringLiteral("Context")).writeEntry(package.metadata().pluginId() + "_contentHeight", value.toReal()); 0153 Q_EMIT dataChanged(index, index, QVector<int>{role}); 0154 return true; 0155 } 0156 0157 default: 0158 warning() << (Role) role << "is read-only."; 0159 } 0160 0161 return false; 0162 } 0163 0164 QHash< int, QByteArray > AppletModel::roleNames() const 0165 { 0166 QHash<int, QByteArray> roles; 0167 roles.insert(Name, "name"); 0168 roles.insert(Id, "appletId"); 0169 roles.insert(Icon, "icon"); 0170 roles.insert(Mainscript, "mainscript"); 0171 roles.insert(Collapsed, "collapsed"); 0172 roles.insert(ContentHeight, "contentHeight"); 0173 0174 return roles; 0175 } 0176 0177 void AppletModel::setAppletCollapsed(const QString& id, bool collapsed) 0178 { 0179 DEBUG_BLOCK 0180 0181 debug() << "Set collapsed for applet:" << id << "to:" << collapsed; 0182 0183 auto package = findPackage(id); 0184 if (package.isValid()) 0185 { 0186 Amarok::config(QStringLiteral("Context")).writeEntry(id + "_collapsed", collapsed); 0187 int row = m_packages.indexOf(package); 0188 auto index = createIndex(row, 0); 0189 Q_EMIT dataChanged(index, index, QVector<int>{Collapsed}); 0190 } 0191 } 0192 0193 void Context::AppletModel::setAppletContentHeight(const QString& id, qreal height) 0194 { 0195 DEBUG_BLOCK 0196 0197 debug() << "Set content height for applet:" << id << "to:" << height; 0198 0199 auto package = findPackage(id); 0200 if (package.isValid()) 0201 { 0202 Amarok::config(QStringLiteral("Context")).writeEntry(id + "_contentHeight", height); 0203 int row = m_packages.indexOf(package); 0204 auto index = createIndex(row, 0); 0205 Q_EMIT dataChanged(index, index, QVector<int>{ContentHeight}); 0206 } 0207 } 0208 0209 QUrl Context::AppletModel::imageUrl(const QString& id, const QString& imageName) 0210 { 0211 auto package = findPackage(id); 0212 if (package.isValid()) 0213 return package.fileUrl("images", imageName); 0214 return QUrl(); 0215 } 0216 0217 AppletPackage AppletModel::findPackage(const QString& id) 0218 { 0219 for (const auto &package : m_packages) 0220 { 0221 auto metadata = package.metadata(); 0222 0223 if (metadata.pluginId() == id) 0224 return package; 0225 } 0226 0227 warning() << "Applet with id:" << id << "not found."; 0228 return AppletPackage(KPackage::Package()); 0229 } 0230 0231 AppletProxyModel::AppletProxyModel(AppletModel* appletModel, QObject *parent) 0232 : QSortFilterProxyModel(parent) 0233 , m_appletModel(appletModel) 0234 { 0235 setSourceModel(appletModel); 0236 setDynamicSortFilter(true); 0237 sort(0); 0238 0239 connect(m_appletModel->loader(), &AppletLoader::finished, this, &AppletProxyModel::enabledAppletsChanged); 0240 } 0241 0242 AppletProxyModel::~AppletProxyModel() 0243 { 0244 } 0245 0246 QStringList AppletProxyModel::enabledApplets() const 0247 { 0248 QStringList list; 0249 for (const auto &applet : m_appletModel->loader()->enabledApplets()) 0250 { 0251 list << applet.pluginId(); 0252 } 0253 0254 std::sort(list.begin(), list.end(), 0255 [] (const QString &a, const QString &b) { 0256 QStringList ae = Amarok::config(QStringLiteral("Context")).readEntry("enabledApplets", QStringList()); 0257 return ae.indexOf(a) < ae.indexOf(b); 0258 } 0259 ); 0260 0261 return list; 0262 } 0263 0264 void AppletProxyModel::setAppletEnabled(const QString& id, bool enabled, int place) 0265 { 0266 DEBUG_BLOCK 0267 0268 debug() << "Set enabled for applet:" << id << "to:" << enabled; 0269 0270 if (enabled == appletEnabled(id)) 0271 return; 0272 0273 QStringList ea = enabledApplets(); 0274 0275 if (enabled) 0276 { 0277 if (place <= -1) 0278 place = ea.size(); 0279 0280 debug() << "Applet's new place is" << place; 0281 ea.insert(place, id); 0282 } 0283 else 0284 { 0285 ea.removeAll(id); 0286 } 0287 Amarok::config(QStringLiteral("Context")).writeEntry("enabledApplets", ea); 0288 0289 debug() << "New enabled applets:" << ea; 0290 0291 invalidateFilter(); 0292 0293 Q_EMIT enabledAppletsChanged(); 0294 } 0295 0296 void AppletProxyModel::setAppletPlace(const QString& id, int place) 0297 { 0298 DEBUG_BLOCK 0299 0300 debug() << "Set place for applet:" << id << "to:" << place; 0301 0302 int currentPlace = appletPlace(id); 0303 debug() << "Current place is" << currentPlace; 0304 0305 if (currentPlace == place) 0306 return; 0307 0308 if (place <= -1) 0309 { 0310 setAppletEnabled(id, false); 0311 return; 0312 } 0313 0314 if (currentPlace <= -1) 0315 setAppletEnabled(id, true, place); 0316 0317 QStringList ea = enabledApplets(); 0318 0319 place = qMin(place, ea.size() - 1); 0320 bool forward = place > currentPlace; 0321 0322 beginMoveRows(QModelIndex(), currentPlace, currentPlace, QModelIndex(), forward ? place + 1 : place); 0323 ea.move(currentPlace, place); 0324 Amarok::config(QStringLiteral("Context")).writeEntry("enabledApplets", ea); 0325 endMoveRows(); 0326 0327 debug() << "New enabled applets:" << ea; 0328 } 0329 0330 int AppletProxyModel::appletPlace(const QString& id) const 0331 { 0332 return enabledApplets().indexOf(id); 0333 } 0334 0335 bool AppletProxyModel::appletEnabled(const QString& id) const 0336 { 0337 return enabledApplets().contains(id); 0338 } 0339 0340 void Context::AppletProxyModel::clear() 0341 { 0342 for( const auto &applet : enabledApplets() ) 0343 { 0344 setAppletEnabled( applet, false ); 0345 } 0346 } 0347 0348 bool AppletProxyModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const 0349 { 0350 int placeLeft = appletPlace(source_left.data(AppletModel::Id).toString()); 0351 int placeRight = appletPlace(source_right.data(AppletModel::Id).toString()); 0352 0353 return placeLeft < placeRight; 0354 } 0355 0356 bool AppletProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const 0357 { 0358 QModelIndex index = sourceModel()->index(source_row, 0, source_parent); 0359 return appletEnabled(index.data(AppletModel::Id).toString()); 0360 } 0361 0362