diff --git a/containments/homescreen/applicationlistmodel.cpp b/containments/homescreen/applicationlistmodel.cpp index b4b844c3..da6dcbd5 100644 --- a/containments/homescreen/applicationlistmodel.cpp +++ b/containments/homescreen/applicationlistmodel.cpp @@ -39,13 +39,9 @@ ApplicationListModel::ApplicationListModel(HomeScreen *parent) - : QAbstractListModel(parent), + : QSortFilterProxyModel(parent), m_homeScreen(parent) { - //can't use the new syntax as this signal is overloaded - connect(KSycoca::self(), SIGNAL(databaseChanged(const QStringList &)), - this, SLOT(sycocaDbChanged(const QStringList &))); - loadSettings(); } @@ -64,128 +60,23 @@ void ApplicationListModel::loadSettings() m_appPositions[app] = i; ++i; } - - loadApplications(); } QHash ApplicationListModel::roleNames() const { QHash roleNames; - roleNames[ApplicationNameRole] = "ApplicationNameRole"; - roleNames[ApplicationIconRole] = "ApplicationIconRole"; - roleNames[ApplicationStorageIdRole] = "ApplicationStorageIdRole"; - roleNames[ApplicationEntryPathRole] = "ApplicationEntryPathRole"; - roleNames[ApplicationOriginalRowRole] = "ApplicationOriginalRowRole"; - roleNames[ApplicationStartupNotifyRole] = "ApplicationStartupNotifyRole"; + if (sourceModel()) { + roleNames = sourceModel()->roleNames(); + } + + roleNames[SortKeyRole] = "SortKeyRole"; roleNames[ApplicationLocationRole] = "ApplicationLocationRole"; + const_cast(this)->m_urlRole = roleNames.key("url"); + return roleNames; } -void ApplicationListModel::sycocaDbChanged(const QStringList &changes) -{ - if (!changes.contains("apps") && !changes.contains("xdgdata-apps")) { - return; - } - - m_applicationList.clear(); - - loadApplications(); -} - -bool appNameLessThan(const ApplicationData &a1, const ApplicationData &a2) -{ - return a1.name.toLower() < a2.name.toLower(); -} - -void ApplicationListModel::loadApplications() -{ - auto cfg = KSharedConfig::openConfig("applications-blacklistrc"); - auto blgroup = KConfigGroup(cfg, QStringLiteral("Applications")); - - // This is only temporary to get a clue what those apps' desktop files are called - // I'll remove it once I've done a blacklist - QStringList bl; - - QStringList blacklist = blgroup.readEntry("blacklist", QStringList()); - - - beginResetModel(); - - m_applicationList.clear(); - - KServiceGroup::Ptr group = KServiceGroup::root(); - if (!group || !group->isValid()) return; - KServiceGroup::List subGroupList = group->entries(true); - - QMap orderedList; - QList unorderedList; - - // Iterate over all entries in the group - while (!subGroupList.isEmpty()) { - KSycocaEntry::Ptr groupEntry = subGroupList.first(); - subGroupList.pop_front(); - - if (groupEntry->isType(KST_KServiceGroup)) { - KServiceGroup::Ptr serviceGroup(static_cast(groupEntry.data())); - - if (!serviceGroup->noDisplay()) { - KServiceGroup::List entryGroupList = serviceGroup->entries(true); - - for(KServiceGroup::List::ConstIterator it = entryGroupList.constBegin(); it != entryGroupList.constEnd(); it++) { - KSycocaEntry::Ptr entry = (*it); - - if (entry->isType(KST_KServiceGroup)) { - KServiceGroup::Ptr serviceGroup(static_cast(entry.data())); - subGroupList << serviceGroup; - - } else if (entry->property("Exec").isValid()) { - KService::Ptr service(static_cast(entry.data())); - - if (service->isApplication() && - !blacklist.contains(service->desktopEntryName()) && - service->showOnCurrentPlatform() && - !service->property("Terminal", QVariant::Bool).toBool()) { - - bl << service->desktopEntryName(); - - ApplicationData data; - data.name = service->name(); - data.icon = service->icon(); - data.storageId = service->storageId(); - data.entryPath = service->exec(); - data.startupNotify = service->property("StartupNotify").toBool(); - - if (m_favorites.contains(data.storageId)) { - data.location = Favorites; - } else if (m_desktopItems.contains(data.storageId)) { - data.location = Desktop; - } - - auto it = m_appPositions.constFind(service->storageId()); - if (it != m_appPositions.constEnd()) { - orderedList[*it] = data; - } else { - unorderedList << data; - } - } - } - } - } - } - } - - blgroup.writeEntry("allapps", bl); - blgroup.writeEntry("blacklist", blacklist); - cfg->sync(); - - std::sort(unorderedList.begin(), unorderedList.end(), appNameLessThan); - m_applicationList << orderedList.values(); - m_applicationList << unorderedList; - - endResetModel(); - emit countChanged(); -} QVariant ApplicationListModel::data(const QModelIndex &index, int role) const { @@ -194,127 +85,117 @@ QVariant ApplicationListModel::data(const QModelIndex &index, int role) const } switch (role) { - case Qt::DisplayRole: - case ApplicationNameRole: - return m_applicationList.at(index.row()).name; - case ApplicationIconRole: - return m_applicationList.at(index.row()).icon; - case ApplicationStorageIdRole: - return m_applicationList.at(index.row()).storageId; - case ApplicationEntryPathRole: - return m_applicationList.at(index.row()).entryPath; - case ApplicationOriginalRowRole: - return index.row(); - case ApplicationStartupNotifyRole: - return m_applicationList.at(index.row()).startupNotify; - case ApplicationLocationRole: - return m_applicationList.at(index.row()).location; + case SortKeyRole: { + const QString url = QSortFilterProxyModel::data(index, m_urlRole).toString(); + if (m_appOrder.contains(url)) { + return QString::number(m_appOrder.indexOf(url)) + QStringLiteral("_") + QSortFilterProxyModel::data(index, Qt::DisplayRole).toString(); + } else { + return QStringLiteral("z_") + QSortFilterProxyModel::data(index, Qt::DisplayRole).toString(); + } + } + + case ApplicationLocationRole: { + const QString url = QSortFilterProxyModel::data(index, m_urlRole).toString(); + if (m_favorites.contains(url)) { + return Favorites; + } else if (m_desktopItems.contains(url)) { + return Desktop; + } else { + return Grid; + } + } default: - return QVariant(); + return QSortFilterProxyModel::data(index, role); } } +//TODO: remove? Qt::ItemFlags ApplicationListModel::flags(const QModelIndex &index) const { if (!index.isValid()) return nullptr; - return Qt::ItemIsDragEnabled|QAbstractItemModel::flags(index); + return Qt::ItemIsDragEnabled|QSortFilterProxyModel::flags(index); } -int ApplicationListModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - return 0; - } - - return m_applicationList.count(); -} - -void ApplicationListModel::moveRow(const QModelIndex& /* sourceParent */, int sourceRow, const QModelIndex& /* destinationParent */, int destinationChild) -{ - moveItem(sourceRow, destinationChild); -} void ApplicationListModel::setLocation(int row, LauncherLocation location) { - if (row < 0 || row >= m_applicationList.length()) { + if (row < 0 || row >= rowCount()) { return; } - ApplicationData &data = m_applicationList[row]; - if (data.location == location) { + const QString url = data(index(row, 0), m_urlRole).toString(); + + if (url.isEmpty()) { return; } - if (location == Favorites) {qWarning()<<"favoriting"<= m_maxFavoriteCount || m_favorites.count() >= m_maxFavoriteCount) { return; } - m_favorites.insert(row, data.storageId); + m_favorites.insert(row, url); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); // Out of favorites - } else if (data.location == Favorites) { - m_favorites.removeAll(data.storageId); + } else if (m_favorites.contains(url)) { + m_favorites.removeAll(url); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); } // In Desktop - if (location == Desktop) { - m_desktopItems.insert(data.storageId); + if (location == Desktop && m_desktopItems.contains(url)) { + m_desktopItems.insert(url); m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList()); // Out of Desktop - } else if (data.location == Desktop) { - m_desktopItems.remove(data.storageId); + } else if (m_desktopItems.contains(url)) { + m_desktopItems.remove(url); m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList()); } - data.location = location; emit m_homeScreen->configNeedsSaving(); emit dataChanged(index(row, 0), index(row, 0)); } void ApplicationListModel::moveItem(int row, int destination) { - if (row < 0 || destination < 0 || row >= m_applicationList.length() || - destination >= m_applicationList.length() || row == destination) { + if (row < 0 || destination < 0 || row >= rowCount() || + destination >= rowCount() || row == destination) { return; } if (destination > row) { ++destination; } - beginMoveRows(QModelIndex(), row, row, QModelIndex(), destination); - if (destination > row) { - ApplicationData data = m_applicationList.at(row); - m_applicationList.insert(destination, data); - m_applicationList.takeAt(row); + const QString url = data(index(row, 0), m_urlRole).toString(); - } else { - ApplicationData data = m_applicationList.takeAt(row); - m_applicationList.insert(destination, data); + if (url.isEmpty()) { + return; } + if (m_appOrder.length() < qMax(row, destination)) { + for (int i = m_appOrder.length(); i <= qMax(row, destination); ++i) { + m_appOrder << data(index(i, 0), m_urlRole).toString(); + } + } + if (destination > row) { + m_appOrder.insert(destination, url); + m_appOrder.takeAt(row); - m_appOrder.clear(); - m_appPositions.clear(); - int i = 0; - for (auto app : m_applicationList) { - m_appOrder << app.storageId; - m_appPositions[app.storageId] = i; - ++i; + } else { + m_appOrder.takeAt(row); + m_appOrder.insert(destination, url); } m_homeScreen->config().writeEntry("AppOrder", m_appOrder); - - endMoveRows(); } void ApplicationListModel::runApplication(const QString &storageId) @@ -344,7 +225,7 @@ void ApplicationListModel::setMaxFavoriteCount(int count) m_favorites.pop_back(); } emit favoriteCountChanged(); - +/*TODO int i = 0; for (auto &app : m_applicationList) { if (i >= count && app.location == Favorites) { @@ -352,7 +233,7 @@ void ApplicationListModel::setMaxFavoriteCount(int count) emit dataChanged(index(i, 0), index(i, 0)); } ++i; - } + }*/ } m_maxFavoriteCount = count; diff --git a/containments/homescreen/applicationlistmodel.h b/containments/homescreen/applicationlistmodel.h index 571aaa41..d12a7b35 100644 --- a/containments/homescreen/applicationlistmodel.h +++ b/containments/homescreen/applicationlistmodel.h @@ -22,7 +22,7 @@ // Qt #include -#include +#include #include #include "homescreen.h" @@ -31,16 +31,7 @@ class QString; class ApplicationListModel; -struct ApplicationData { - QString name; - QString icon; - QString storageId; - QString entryPath; - int location = 0; //FIXME - bool startupNotify = true; -}; - -class ApplicationListModel : public QAbstractListModel { +class ApplicationListModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countChanged) @@ -56,12 +47,7 @@ public: Q_ENUM(LauncherLocation) enum Roles { - ApplicationNameRole = Qt::UserRole + 1, - ApplicationIconRole, - ApplicationStorageIdRole, - ApplicationEntryPathRole, - ApplicationOriginalRowRole, - ApplicationStartupNotifyRole, + SortKeyRole = Qt::UserRole + 100, ApplicationLocationRole }; @@ -70,11 +56,7 @@ public: void loadSettings(); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - - void moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild); - - int count() const { return m_applicationList.count(); } + int count() const { return rowCount(); } int favoriteCount() const { return m_favorites.count();} int maxFavoriteCount() const; @@ -92,10 +74,7 @@ public: Q_INVOKABLE void runApplication(const QString &storageId); - Q_INVOKABLE void loadApplications(); - public Q_SLOTS: - void sycocaDbChanged(const QStringList &change); Q_SIGNALS: void countChanged(); @@ -103,10 +82,9 @@ Q_SIGNALS: void maxFavoriteCountChanged(); private: - QList m_applicationList; - HomeScreen *m_homeScreen = nullptr; int m_maxFavoriteCount = 0; + int m_urlRole = 0; QStringList m_appOrder; QStringList m_favorites; QSet m_desktopItems; diff --git a/containments/homescreen/package/contents/ui/launcher/Delegate.qml b/containments/homescreen/package/contents/ui/launcher/Delegate.qml index 858253c5..243fb930 100644 --- a/containments/homescreen/package/contents/ui/launcher/Delegate.qml +++ b/containments/homescreen/package/contents/ui/launcher/Delegate.qml @@ -47,7 +47,7 @@ ContainmentLayoutManager.ItemContainer { opacity: dragActive ? 0.4 : 1 - key: model.ApplicationStorageIdRole + key: model.url property real dragCenterX property real dragCenterY @@ -93,8 +93,8 @@ ContainmentLayoutManager.ItemContainer { onClicked: { clickFedbackAnimation.target = delegate; clickFedbackAnimation.running = true; - feedbackWindow.title = modelData.ApplicationNameRole; - feedbackWindow.icon = modelData.ApplicationIconRole; + feedbackWindow.title = model.display; + feedbackWindow.icon = model.decoration; feedbackWindow.state = "open"; plasmoid.nativeInterface.applicationListModel.runApplication(modelData.ApplicationStorageIdRole); @@ -112,7 +112,7 @@ ContainmentLayoutManager.ItemContainer { Layout.minimumHeight: parent.height - root.reservedSpaceForLabel Layout.preferredHeight: Layout.minimumHeight - source: modelData ? modelData.ApplicationIconRole : "" + source: model.decoration Behavior on scale { NumberAnimation { duration: units.longDuration @@ -133,7 +133,7 @@ ContainmentLayoutManager.ItemContainer { maximumLineCount: 2 elide: Text.ElideRight - text: model.ApplicationNameRole + text: model.display font.pixelSize: theme.defaultFont.pixelSize color: model.ApplicationLocationRole == ApplicationListModel.Desktop ? "white" : theme.textColor diff --git a/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml b/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml index 2017d0cd..2e908235 100644 --- a/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml +++ b/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml @@ -29,6 +29,8 @@ import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutM import org.kde.phone.homescreen 1.0 +import org.kde.plasma.private.kicker 0.1 as Kicker + LauncherContainer { id: root @@ -39,6 +41,28 @@ LauncherContainer { frame.width: width + Kicker.RootModel { + id: kickerRootModel + appNameFormat: 0 + + autoPopulate: false + flat: true + sorted: true + showSeparators: false + appletInterface: plasmoid + paginate: false + showAllApps: true + showTopLevelItems: false + showRecentApps: false + showRecentDocs: false + showRecentContacts: false + recentOrdering: 0 + Component.onCompleted: { + kickerRootModel.refresh(); + plasmoid.nativeInterface.applicationListModel.sourceModel = kickerRootModel.modelForRow(0); + } + } + Repeater { model: plasmoid.nativeInterface.applicationListModel delegate: Delegate {