diff --git a/applets/kicker/package/contents/ui/main.qml b/applets/kicker/package/contents/ui/main.qml index 766656dde..77449b858 100644 --- a/applets/kicker/package/contents/ui/main.qml +++ b/applets/kicker/package/contents/ui/main.qml @@ -1,263 +1,266 @@ /*************************************************************************** * Copyright (C) 2014-2015 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 import QtQuick.Layouts 1.1 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.private.kicker 0.1 as Kicker Item { id: kicker anchors.fill: parent signal reset property bool isDash: (plasmoid.pluginName == "org.kde.plasma.kickerdash") Plasmoid.switchWidth: isDash || !Plasmoid.fullRepresentationItem ? 0 : Plasmoid.fullRepresentationItem.Layout.minimumWidth Plasmoid.switchHeight: isDash || !Plasmoid.fullRepresentationItem ? 0 : Plasmoid.fullRepresentationItem.Layout.minimumHeight // this is a bit of a hack to prevent Plasma from spawning a dialog on its own when we're Dash Plasmoid.preferredRepresentation: isDash ? Plasmoid.fullRepresentation : null Plasmoid.compactRepresentation: isDash ? null : compactRepresentation Plasmoid.fullRepresentation: isDash ? compactRepresentation : menuRepresentation property QtObject itemListDialogComponent: Qt.createComponent("ItemListDialog.qml"); property Item dragSource: null property QtObject globalFavorites: rootModel.favoritesModel property QtObject systemFavorites: rootModel.systemFavoritesModel onSystemFavoritesChanged: { systemFavorites.favorites = plasmoid.configuration.favoriteSystemActions; } function action_menuedit() { processRunner.runMenuEditor(); } function updateSvgMetrics() { lineSvg.horLineHeight = lineSvg.elementSize("horizontal-line").height; lineSvg.vertLineWidth = lineSvg.elementSize("vertical-line").width; } Component { id: compactRepresentation CompactRepresentation {} } Component { id: menuRepresentation MenuRepresentation {} } Kicker.RootModel { id: rootModel + autoPopulate: false + appNameFormat: plasmoid.configuration.appNameFormat flat: isDash ? true : plasmoid.configuration.limitDepth sorted: plasmoid.configuration.alphaSort showSeparators: !isDash appletInterface: plasmoid showAllApps: isDash showRecentApps: plasmoid.configuration.showRecentApps showRecentDocs: plasmoid.configuration.showRecentDocs showRecentContacts: plasmoid.configuration.showRecentContacts onShowRecentAppsChanged: { plasmoid.configuration.showRecentApps = showRecentApps; } onShowRecentDocsChanged: { plasmoid.configuration.showRecentDocs = showRecentDocs; } onShowRecentContactsChanged: { plasmoid.configuration.showRecentContacts = showRecentContacts; } Component.onCompleted: { favoritesModel.favorites = plasmoid.configuration.favoriteApps; + rootModel.refresh(); } } Connections { target: globalFavorites onFavoritesChanged: { plasmoid.configuration.favoriteApps = target.favorites; } } Connections { target: systemFavorites onFavoritesChanged: { plasmoid.configuration.favoriteSystemActions = target.favorites; } } Connections { target: plasmoid.configuration onFavoriteAppsChanged: { globalFavorites.favorites = plasmoid.configuration.favoriteApps; } onFavoriteSystemActionsChanged: { systemFavorites.favorites = plasmoid.configuration.favoriteSystemActions; } } Kicker.RunnerModel { id: runnerModel appletInterface: plasmoid favoritesModel: globalFavorites runners: { var runners = new Array("services"); if (isDash) { runners = runners.concat(new Array("desktopsessions", "PowerDevil")); } if (plasmoid.configuration.useExtraRunners) { runners = runners.concat(plasmoid.configuration.extraRunners); } return runners; } deleteWhenEmpty: isDash } Kicker.DragHelper { id: dragHelper dragIconSize: units.iconSizes.medium } Kicker.ProcessRunner { id: processRunner; } Kicker.WindowSystem { id: windowSystem; } PlasmaCore.FrameSvgItem { id : highlightItemSvg visible: false imagePath: "widgets/viewitem" prefix: "hover" } PlasmaCore.FrameSvgItem { id : listItemSvg visible: false imagePath: "widgets/listitem" prefix: "normal" } PlasmaCore.Svg { id: arrows imagePath: "widgets/arrows" size: "16x16" } PlasmaCore.Svg { id: lineSvg imagePath: "widgets/line" property int horLineHeight property int vertLineWidth } PlasmaComponents.Label { id: toolTipDelegate width: contentWidth height: contentHeight property Item toolTip text: (toolTip != null) ? toolTip.text : "" } Timer { id: justOpenedTimer repeat: false interval: 600 } Connections { target: plasmoid onExpandedChanged: { if (expanded) { windowSystem.monitorWindowVisibility(plasmoid.fullRepresentationItem); justOpenedTimer.start(); } else { kicker.reset(); } } } function resetDragSource() { dragSource = null; } function enableHideOnWindowDeactivate() { plasmoid.hideOnWindowDeactivate = true; } Component.onCompleted: { if (plasmoid.hasOwnProperty("activationTogglesExpanded")) { plasmoid.activationTogglesExpanded = !isDash } windowSystem.focusOut.connect(enableHideOnWindowDeactivate); plasmoid.hideOnWindowDeactivate = true; if (plasmoid.immutability !== PlasmaCore.Types.SystemImmutable) { plasmoid.setAction("menuedit", i18n("Edit Applications...")); } updateSvgMetrics(); theme.themeChanged.connect(updateSvgMetrics); rootModel.refreshed.connect(reset); dragHelper.dropped.connect(resetDragSource); } } diff --git a/applets/kicker/plugin/rootmodel.cpp b/applets/kicker/plugin/rootmodel.cpp index 6069ef8d2..0db61ec56 100644 --- a/applets/kicker/plugin/rootmodel.cpp +++ b/applets/kicker/plugin/rootmodel.cpp @@ -1,407 +1,423 @@ /*************************************************************************** * Copyright (C) 2014-2015 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "rootmodel.h" #include "actionlist.h" #include "favoritesmodel.h" #include "recentcontactsmodel.h" #include "recentusagemodel.h" #include "systemmodel.h" #include #include GroupEntry::GroupEntry(AppsModel *parentModel, const QString &name, const QString &iconName, AbstractModel *childModel) : AbstractGroupEntry(parentModel) , m_name(name) , m_iconName(iconName) , m_childModel(childModel) { QObject::connect(parentModel, &RootModel::cleared, childModel, &AbstractModel::deleteLater); QObject::connect(childModel, &AbstractModel::countChanged, [parentModel, this] { if (parentModel) { parentModel->entryChanged(this); } } ); } QString GroupEntry::name() const { return m_name; } QIcon GroupEntry::icon() const { return QIcon::fromTheme(m_iconName, QIcon::fromTheme("unknown")); } bool GroupEntry::hasChildren() const { return m_childModel && m_childModel->count() > 0; } AbstractModel *GroupEntry::childModel() const { return m_childModel; } RootModel::RootModel(QObject *parent) : AppsModel(QString(), parent) , m_complete(false) , m_favorites(new FavoritesModel(this)) , m_systemModel(nullptr) +, m_autoPopulate(true) , m_showAllApps(false) , m_showRecentApps(true) , m_showRecentDocs(true) , m_showRecentContacts(false) , m_showPowerSession(true) , m_recentAppsModel(0) , m_recentDocsModel(0) , m_recentContactsModel(0) { } RootModel::~RootModel() { } QVariant RootModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || index.row() >= m_entryList.count()) { return QVariant(); } if (role == Kicker::HasActionListRole || role == Kicker::ActionListRole) { const AbstractEntry *entry = m_entryList.at(index.row()); if (entry->type() == AbstractEntry::GroupType) { const GroupEntry *group = static_cast(entry); AbstractModel *model = group->childModel(); if (model == m_recentAppsModel || model == m_recentDocsModel || model == m_recentContactsModel) { if (role == Kicker::HasActionListRole) { return true; } else if (role == Kicker::ActionListRole) { QVariantList actionList; actionList << model->actions(); actionList << Kicker::createSeparatorActionItem(); actionList << Kicker::createActionItem(i18n("Hide %1", group->name()), "hideCategory"); return actionList; } } } } return AppsModel::data(index, role); } bool RootModel::trigger(int row, const QString& actionId, const QVariant& argument) { const AbstractEntry *entry = m_entryList.at(row); if (entry->type() == AbstractEntry::GroupType) { if (actionId == "hideCategory") { AbstractModel *model = entry->childModel(); if (model == m_recentAppsModel) { setShowRecentApps(false); return true; } else if (model == m_recentDocsModel) { setShowRecentDocs(false); return true; } else if (model == m_recentContactsModel) { setShowRecentContacts(false); return true; } } else if (entry->childModel()->hasActions()) { return entry->childModel()->trigger(-1, actionId, QVariant()); } } return AppsModel::trigger(row, actionId, argument); } +bool RootModel::autoPopulate() const +{ + return m_autoPopulate; +} + +void RootModel::setAutoPopulate(bool populate) +{ + if (m_autoPopulate != populate) { + m_autoPopulate = populate; + + emit autoPopulateChanged(); + } +} bool RootModel::showAllApps() const { return m_showAllApps; } void RootModel::setShowAllApps(bool show) { if (m_showAllApps != show) { m_showAllApps = show; refresh(); emit showAllAppsChanged(); } } bool RootModel::showRecentApps() const { return m_showRecentApps; } void RootModel::setShowRecentApps(bool show) { if (show != m_showRecentApps) { m_showRecentApps = show; refresh(); emit showRecentAppsChanged(); } } bool RootModel::showRecentDocs() const { return m_showRecentDocs; } void RootModel::setShowRecentDocs(bool show) { if (show != m_showRecentDocs) { m_showRecentDocs = show; refresh(); emit showRecentDocsChanged(); } } bool RootModel::showRecentContacts() const { return m_showRecentContacts; } void RootModel::setShowRecentContacts(bool show) { if (show != m_showRecentContacts) { m_showRecentContacts = show; refresh(); emit showRecentContactsChanged(); } } bool RootModel::showPowerSession() const { return m_showPowerSession; } void RootModel::setShowPowerSession(bool show) { if (show != m_showPowerSession) { m_showPowerSession = show; refresh(); emit showPowerSessionChanged(); } } AbstractModel* RootModel::favoritesModel() { return m_favorites; } AbstractModel* RootModel::systemFavoritesModel() { if (m_systemModel) { return m_systemModel->favoritesModel(); } return nullptr; } void RootModel::classBegin() { } void RootModel::componentComplete() { m_complete = true; - refresh(); + if (m_autoPopulate) { + refresh(); + } } void RootModel::refresh() { if (!m_complete) { return; } beginResetModel(); AppsModel::refreshInternal(); AppsModel *allModel = nullptr; m_recentAppsModel = nullptr; m_recentDocsModel = nullptr; m_recentContactsModel = nullptr; if (m_showAllApps) { QList groups; if (m_paginate) { QHash appsHash; QList apps; foreach (const AbstractEntry *groupEntry, m_entryList) { AbstractModel *model = groupEntry->childModel(); for (int i = 0; i < model->count(); ++i) { GroupEntry *subGroupEntry = static_cast(model->index(i, 0).internalPointer()); AbstractModel *subModel = subGroupEntry->childModel(); for (int j = 0; j < subModel->count(); ++j) { AppEntry *appEntry = static_cast(subModel->index(i, 0).internalPointer()); if (appEntry->name().isEmpty()) { continue; } appsHash.insert(appEntry->service()->menuId(), appEntry); } } } apps = appsHash.values(); QCollator c; std::sort(apps.begin(), apps.end(), [&c](AbstractEntry* a, AbstractEntry* b) { if (a->type() != b->type()) { return a->type() > b->type(); } else { return c.compare(a->name(), b->name()) < 0; } }); int at = 0; QList page; page.reserve(24); foreach(AppEntry *app, apps) { page.append(app); if (at == (m_pageSize - 1)) { at = 0; AppsModel *model = new AppsModel(page, false, this); groups.append(new GroupEntry(this, QString(), QString(), model)); page.clear(); } else { ++at; } } if (!page.isEmpty()) { AppsModel *model = new AppsModel(page, false, this); groups.append(new GroupEntry(this, QString(), QString(), model)); } groups.prepend(new GroupEntry(this, QString(), QString(), m_favorites)); } else { QHash> m_categoryHash; foreach (const AbstractEntry *groupEntry, m_entryList) { AbstractModel *model = groupEntry->childModel(); for (int i = 0; i < model->count(); ++i) { AbstractEntry *appEntry = static_cast(model->index(i, 0).internalPointer()); if (appEntry->name().isEmpty()) { continue; } const QChar &first = appEntry->name().at(0).toUpper(); m_categoryHash[first.isDigit() ? QStringLiteral("0-9") : first].append(appEntry); } } QHashIterator> i(m_categoryHash); while (i.hasNext()) { i.next(); AppsModel *model = new AppsModel(i.value(), false, this); model->setDescription(i.key()); groups.append(new GroupEntry(this, i.key(), QString(), model)); } } allModel = new AppsModel(groups, true, this); allModel->setDescription(QStringLiteral("KICKER_ALL_MODEL")); // Intentionally no i18n. } int separatorPosition = 0; if (allModel) { m_entryList.prepend(new GroupEntry(this, i18n("All Applications"), QString(), allModel)); ++separatorPosition; } if (m_showRecentContacts) { m_recentContactsModel = new RecentContactsModel(this); m_entryList.prepend(new GroupEntry(this, i18n("Recent Contacts"), QString(), m_recentContactsModel)); ++separatorPosition; } if (m_showRecentDocs) { m_recentDocsModel = new RecentUsageModel(this, RecentUsageModel::OnlyDocs); m_entryList.prepend(new GroupEntry(this, i18n("Recent Documents"), QString(), m_recentDocsModel)); ++separatorPosition; } if (m_showRecentApps) { m_recentAppsModel = new RecentUsageModel(this, RecentUsageModel::OnlyApps); m_entryList.prepend(new GroupEntry(this, i18n("Recent Applications"), QString(), m_recentAppsModel)); ++separatorPosition; } if (m_showSeparators && separatorPosition > 0) { m_entryList.insert(separatorPosition, new SeparatorEntry(this)); ++m_separatorCount; } m_systemModel = new SystemModel(this); if (m_showPowerSession) { m_entryList << new GroupEntry(this, i18n("Power / Session"), QString(), m_systemModel); } endResetModel(); m_favorites->refresh(); emit systemFavoritesModelChanged(); emit countChanged(); emit separatorCountChanged(); emit refreshed(); } diff --git a/applets/kicker/plugin/rootmodel.h b/applets/kicker/plugin/rootmodel.h index 9be2b3ead..0cedafa82 100644 --- a/applets/kicker/plugin/rootmodel.h +++ b/applets/kicker/plugin/rootmodel.h @@ -1,123 +1,131 @@ /*************************************************************************** * Copyright (C) 2014-2015 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #ifndef ROOTMODEL_H #define ROOTMODEL_H #include "appsmodel.h" #include class FavoritesModel; class RecentContactsModel; class RecentUsageModel; class SystemModel; class RootModel; class GroupEntry : public AbstractGroupEntry { public: GroupEntry(AppsModel *parentModel, const QString &name, const QString &iconName, AbstractModel *childModel); QIcon icon() const; QString name() const; bool hasChildren() const; AbstractModel *childModel() const; private: QString m_name; QString m_iconName; QPointer m_childModel; }; class RootModel : public AppsModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(bool autoPopulate READ autoPopulate WRITE setAutoPopulate NOTIFY autoPopulateChanged) + Q_PROPERTY(QObject* systemFavoritesModel READ systemFavoritesModel NOTIFY systemFavoritesModelChanged) Q_PROPERTY(bool showAllApps READ showAllApps WRITE setShowAllApps NOTIFY showAllAppsChanged) Q_PROPERTY(bool showRecentApps READ showRecentApps WRITE setShowRecentApps NOTIFY showRecentAppsChanged) Q_PROPERTY(bool showRecentDocs READ showRecentDocs WRITE setShowRecentDocs NOTIFY showRecentDocsChanged) Q_PROPERTY(bool showRecentContacts READ showRecentContacts WRITE setShowRecentContacts NOTIFY showRecentContactsChanged) Q_PROPERTY(bool showPowerSession READ showPowerSession WRITE setShowPowerSession NOTIFY showPowerSessionChanged) public: explicit RootModel(QObject *parent = 0); ~RootModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; Q_INVOKABLE virtual bool trigger(int row, const QString &actionId, const QVariant &argument); + bool autoPopulate() const; + void setAutoPopulate(bool populate); + bool showAllApps() const; void setShowAllApps(bool show); bool showRecentApps() const; void setShowRecentApps(bool show); bool showRecentDocs() const; void setShowRecentDocs(bool show); bool showRecentContacts() const; void setShowRecentContacts(bool show); bool showPowerSession() const; void setShowPowerSession(bool show); AbstractModel* favoritesModel(); AbstractModel* systemFavoritesModel(); void classBegin() override; void componentComplete() override; Q_SIGNALS: void refreshed() const; void systemFavoritesModelChanged() const; + void autoPopulateChanged() const; void showAllAppsChanged() const; void showRecentAppsChanged() const; void showRecentDocsChanged() const; void showRecentContactsChanged() const; void showPowerSessionChanged() const; void recentAppsModelChanged() const; protected Q_SLOTS: void refresh(); private: bool m_complete; FavoritesModel *m_favorites; SystemModel *m_systemModel; + bool m_autoPopulate; + bool m_showAllApps; bool m_showRecentApps; bool m_showRecentDocs; bool m_showRecentContacts; bool m_showPowerSession; RecentUsageModel *m_recentAppsModel; RecentUsageModel *m_recentDocsModel; RecentContactsModel *m_recentContactsModel; }; #endif