diff --git a/appentry.cpp b/appentry.cpp index 19231796d..5efdb0d00 100644 --- a/appentry.cpp +++ b/appentry.cpp @@ -1,337 +1,338 @@ /*************************************************************************** * Copyright (C) 201 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 #include "appentry.h" #include "actionlist.h" #include "appsmodel.h" #include "containmentinterface.h" #include "menuentryeditor.h" #ifdef PackageKitQt5_FOUND #include "findpackagenamejob.h" #endif #include #include #include #include #if HAVE_X11 #include #endif #include #include #include #include #include #include #include #include #include #include #include MenuEntryEditor *AppEntry::m_menuEntryEditor = nullptr; AppEntry::AppEntry(AbstractModel *owner, KService::Ptr service, NameFormat nameFormat) : AbstractEntry(owner) , m_service(service) { if (m_service) { init(nameFormat); } } AppEntry::AppEntry(AbstractModel *owner, const QString &id) : AbstractEntry(owner) { const QUrl url(id); if (url.scheme() == QStringLiteral("preferred")) { m_service = defaultAppByName(url.host()); m_id = id; } else { m_service = KService::serviceByStorageId(id); } if (m_service) { init((NameFormat)owner->rootModel()->property("appNameFormat").toInt()); } } void AppEntry::init(NameFormat nameFormat) { m_name = nameFromService(m_service, nameFormat); if (nameFormat == GenericNameOnly) { m_description = nameFromService(m_service, NameOnly); } else { m_description = nameFromService(m_service, GenericNameOnly); } if (!m_menuEntryEditor) { m_menuEntryEditor = new MenuEntryEditor(); } } bool AppEntry::isValid() const { return m_service; } QIcon AppEntry::icon() const { if (m_icon.isNull()) { m_icon = QIcon::fromTheme(m_service->icon(), QIcon::fromTheme("unknown")); } return m_icon; } QString AppEntry::name() const { return m_name; } QString AppEntry::description() const { return m_description; } KService::Ptr AppEntry::service() const { return m_service; } QString AppEntry::id() const { if (!m_id.isEmpty()) { return m_id; } return m_service->storageId(); } QUrl AppEntry::url() const { return QUrl::fromLocalFile(m_service->entryPath()); } bool AppEntry::hasActions() const { return true; } QVariantList AppEntry::actions() const { QVariantList actionList; actionList << Kicker::jumpListActions(m_service); if (!actionList.isEmpty()) { actionList << Kicker::createSeparatorActionItem(); } QObject *appletInterface = m_owner->rootModel()->property("appletInterface").value(); const bool systemImmutable = appletInterface->property("immutability").toInt() == Plasma::Types::SystemImmutable; const QVariantList &addLauncherActions = Kicker::createAddLauncherActionList(appletInterface, m_service); if (!systemImmutable && !addLauncherActions.isEmpty()) { actionList << addLauncherActions << Kicker::createSeparatorActionItem(); } const QVariantList &recentDocuments = Kicker::recentDocumentActions(m_service); if (!recentDocuments.isEmpty()) { actionList << recentDocuments << Kicker::createSeparatorActionItem(); } // Don't allow adding launchers, editing, hiding, or uninstalling applications // when system is immutable. if (systemImmutable) { return actionList; } if (m_menuEntryEditor->canEdit(m_service->entryPath())) { actionList << Kicker::createSeparatorActionItem(); QVariantMap editAction = Kicker::createActionItem(i18n("Edit Application..."), "editApplication"); editAction["icon"] = "kmenuedit"; // TODO: Using the KMenuEdit icon might be misleading. actionList << editAction; } #ifdef PackageKitQt5_FOUND /*QStringList files(m_service->entryPath()); if (m_service->isApplication()) { files += QStandardPaths::findExecutable(KShell::splitArgs(m_service->exec()).first()); } FindPackageJob* job = new FindPackageJob(files); // TODO: Would be great to make this async. if (job->exec() && !job->packageNames().isEmpty()) { QString packageName = job->packageNames().first(); QVariantMap removeAction = Kicker::createActionItem(i18n("Remove '%1'...", packageName), "removeApplication", packageName); removeAction["icon"] = "applications-other"; actionList << removeAction; }*/ #endif QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains("hiddenApplications") && qobject_cast(m_owner)) { const QStringList &hiddenApps = appletConfig->value("hiddenApplications").toStringList(); if (!hiddenApps.contains(m_service->menuId())) { actionList << Kicker::createActionItem(i18n("Hide Application"), "hideApplication"); } } return actionList; } bool AppEntry::run(const QString& actionId, const QVariant &argument) { if (!m_service->isValid()) { return false; } if (actionId.isEmpty()) { quint32 timeStamp = 0; #if HAVE_X11 if (QX11Info::isPlatformX11()) { timeStamp = QX11Info::appUserTime(); } #endif // TODO Once we depend on KDE Frameworks 5.24 and D1902 is merged, use KRun::runApplication instead KRun::runService(*m_service, {}, nullptr, true, {}, KStartupInfo::createNewStartupIdForTimestamp(timeStamp)); KActivities::ResourceInstance::notifyAccessed(QUrl("applications:" + m_service->storageId()), "org.kde.plasma.kicker"); return true; } QObject *appletInterface = m_owner->rootModel()->property("appletInterface").value(); if (Kicker::handleAddLauncherAction(actionId, appletInterface, m_service)) { return true; } else if (actionId == "editApplication" && m_menuEntryEditor->canEdit(m_service->entryPath())) { m_menuEntryEditor->edit(m_service->entryPath(), m_service->menuId()); return true; } else if (actionId == "removeApplication") { QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains("removeApplicationCommand")) { const QStringList &removeAppCmd = KShell::splitArgs(appletConfig->value("removeApplicationCommand").toString()); if (!removeAppCmd.isEmpty()) { return QProcess::startDetached(removeAppCmd.first(), removeAppCmd.mid(1) << argument.toString()); } } } else if (actionId == "_kicker_jumpListAction") { return KRun::run(argument.toString(), {}, nullptr, m_service->name(), m_service->icon()); } return Kicker::handleRecentDocumentAction(m_service, actionId, argument); } QString AppEntry::nameFromService(const KService::Ptr service, NameFormat nameFormat) { const QString &name = service->name(); QString genericName = service->genericName(); if (genericName.isEmpty()) { genericName = service->comment(); } if (nameFormat == NameOnly || genericName.isEmpty() || name == genericName) { return name; } else if (nameFormat == GenericNameOnly) { return genericName; } else if (nameFormat == NameAndGenericName) { return i18nc("App name (Generic name)", "%1 (%2)", name, genericName); } else { return i18nc("Generic name (App name)", "%1 (%2)", genericName, name); } } KService::Ptr AppEntry::defaultAppByName(const QString& name) { if (name == QLatin1String("browser")) { KConfigGroup config(KSharedConfig::openConfig(), "General"); QString browser = config.readPathEntry("BrowserApplication", QString()); if (browser.isEmpty()) { return KMimeTypeTrader::self()->preferredService(QLatin1String("text/html")); } else if (browser.startsWith('!')) { browser = browser.mid(1); } return KService::serviceByStorageId(browser); } return KService::Ptr(); } AppGroupEntry::AppGroupEntry(AppsModel *parentModel, KServiceGroup::Ptr group, - bool flat, bool sorted, bool separators, int appNameFormat) : AbstractGroupEntry(parentModel), + bool paginate, int pageSize, bool flat, bool sorted, bool separators, int appNameFormat) : AbstractGroupEntry(parentModel), m_group(group) { - AppsModel* model = new AppsModel(group->entryPath(), flat, sorted, separators, parentModel); + AppsModel* model = new AppsModel(group->entryPath(), paginate, pageSize, flat, + sorted, separators, parentModel); model->setAppNameFormat(appNameFormat); m_childModel = model; QObject::connect(parentModel, &AppsModel::cleared, model, &AppsModel::deleteLater); QObject::connect(model, &AppsModel::countChanged, [parentModel, this] { if (parentModel) { parentModel->entryChanged(this); } } ); QObject::connect(model, &AppsModel::hiddenEntriesChanged, [parentModel, this] { if (parentModel) { parentModel->entryChanged(this); } } ); } QIcon AppGroupEntry::icon() const { if (m_icon.isNull()) { m_icon = QIcon::fromTheme(m_group->icon(), QIcon::fromTheme("unknown")); } return m_icon; } QString AppGroupEntry::name() const { return m_group->caption(); } bool AppGroupEntry::hasChildren() const { return m_childModel && m_childModel->count() > 0; } AbstractModel *AppGroupEntry::childModel() const { return m_childModel; } diff --git a/appentry.h b/appentry.h index 98841a68a..4ee770669 100644 --- a/appentry.h +++ b/appentry.h @@ -1,93 +1,93 @@ /*************************************************************************** * Copyright (C) 201 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 APPENTRY_H #define APPENTRY_H #include "abstractentry.h" #include #include class AppsModel; class MenuEntryEditor; class AppEntry : public AbstractEntry { public: enum NameFormat { NameOnly = 0, GenericNameOnly, NameAndGenericName, GenericNameAndName }; explicit AppEntry(AbstractModel *owner, KService::Ptr service, NameFormat nameFormat); explicit AppEntry(AbstractModel *owner, const QString &id); EntryType type() const { return RunnableType; } bool isValid() const; QIcon icon() const; QString name() const; QString description() const; KService::Ptr service() const; QString id() const; QUrl url() const; bool hasActions() const; QVariantList actions() const; bool run(const QString& actionId = QString(), const QVariant &argument = QVariant()); static QString nameFromService(const KService::Ptr service, NameFormat nameFormat); static KService::Ptr defaultAppByName(const QString &name); private: void init(NameFormat nameFormat); QString m_id; QString m_name; QString m_description; mutable QIcon m_icon; KService::Ptr m_service; static MenuEntryEditor *m_menuEntryEditor; }; class AppGroupEntry : public AbstractGroupEntry { public: AppGroupEntry(AppsModel *parentModel, KServiceGroup::Ptr group, - bool flat, bool sorted, bool separators, int appNameFormat); + bool paginate, int pageSize, bool flat, bool sorted, bool separators, int appNameFormat); QIcon icon() const; QString name() const; bool hasChildren() const; AbstractModel *childModel() const; private: KServiceGroup::Ptr m_group; mutable QIcon m_icon; QPointer m_childModel; }; #endif diff --git a/appsmodel.cpp b/appsmodel.cpp index bab0a8baf..784993629 100644 --- a/appsmodel.cpp +++ b/appsmodel.cpp @@ -1,570 +1,637 @@ /*************************************************************************** * Copyright (C) 2012 Aurélien Gâteau * * Copyright (C) 2013-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 "appsmodel.h" #include "actionlist.h" +#include "rootmodel.h" #include #include #include #include #include #include -AppsModel::AppsModel(const QString &entryPath, bool flat, bool sorted, bool separators, QObject *parent) +AppsModel::AppsModel(const QString &entryPath, bool paginate, int pageSize, bool flat, + bool sorted, bool separators, QObject *parent) : AbstractModel(parent) +, m_paginate(paginate) +, m_pageSize(pageSize) , m_deleteEntriesOnDestruction(true) , m_separatorCount(0) , m_showSeparators(separators) , m_appletInterface(nullptr) , m_description(i18n("Applications")) , m_entryPath(entryPath) , m_staticEntryList(false) , m_changeTimer(0) , m_flat(flat) , m_sorted(sorted) , m_appNameFormat(AppEntry::NameOnly) { if (!m_entryPath.isEmpty()) { refresh(); } } AppsModel::AppsModel(const QList entryList, bool deleteEntriesOnDestruction, QObject *parent) : AbstractModel(parent) +, m_paginate(false) +, m_pageSize(24) , m_deleteEntriesOnDestruction(deleteEntriesOnDestruction) , m_separatorCount(0) , m_showSeparators(false) , m_appletInterface(nullptr) , m_description(i18n("Applications")) , m_entryPath(QString()) , m_staticEntryList(true) , m_changeTimer(0) , m_flat(true) , m_sorted(true) , m_appNameFormat(AppEntry::NameOnly) { foreach(AbstractEntry *suggestedEntry, entryList) { bool found = false; foreach (const AbstractEntry *entry, m_entryList) { if (entry->type() == AbstractEntry::RunnableType && static_cast(entry)->service()->storageId() == static_cast(suggestedEntry)->service()->storageId()) { found = true; } } if (!found) { m_entryList << suggestedEntry; } } sortEntries(); } AppsModel::~AppsModel() { if (m_deleteEntriesOnDestruction) { qDeleteAll(m_entryList); } } QString AppsModel::description() const { return m_description; } void AppsModel::setDescription(const QString &text) { if (m_description != text) { m_description = text; emit descriptionChanged(); } } QVariant AppsModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_entryList.count()) { return QVariant(); } const AbstractEntry *entry = m_entryList.at(index.row()); if (role == Qt::DisplayRole) { return entry->name(); } else if (role == Qt::DecorationRole) { return entry->icon(); } else if (role == Kicker::DescriptionRole) { return entry->description(); } else if (role == Kicker::FavoriteIdRole && entry->type() == AbstractEntry::RunnableType) { return entry->id(); } else if (role == Kicker::UrlRole && entry->type() == AbstractEntry::RunnableType) { return entry->url(); } else if (role == Kicker::IsParentRole) { return (entry->type() == AbstractEntry::GroupType); } else if (role == Kicker::IsSeparatorRole) { return (entry->type() == AbstractEntry::SeparatorType); } else if (role == Kicker::HasChildrenRole) { return entry->hasChildren(); } else if (role == Kicker::HasActionListRole) { const AppsModel *appsModel = qobject_cast(entry->childModel()); return entry->hasActions() || (appsModel && !appsModel->hiddenEntries().isEmpty()); } else if (role == Kicker::ActionListRole) { QVariantList actionList = entry->actions(); if (!m_hiddenEntries.isEmpty()) { actionList << Kicker::createSeparatorActionItem(); actionList << Kicker::createActionItem(i18n("Unhide Applications in this Submenu"), "unhideSiblingApplications"); } const AppsModel *appsModel = qobject_cast(entry->childModel()); if (appsModel && !appsModel->hiddenEntries().isEmpty()) { actionList << Kicker::createActionItem(i18n("Unhide Applications in '%1'", entry->name()), "unhideChildApplications"); } return actionList; } return QVariant(); } QModelIndex AppsModel::index(int row, int column, const QModelIndex &parent) const { return hasIndex(row, column, parent) ? createIndex(row, column, m_entryList.at(row)) : QModelIndex(); } int AppsModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_entryList.count(); } bool AppsModel::trigger(int row, const QString &actionId, const QVariant &argument) { if (row < 0 || row >= m_entryList.count()) { return false; } AbstractEntry *entry = m_entryList.at(row); if (actionId == "hideApplication" && entry->type() == AbstractEntry::RunnableType) { QObject *appletInterface = rootModel()->property("appletInterface").value(); QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains("hiddenApplications")) { QStringList hiddenApps = appletConfig->value("hiddenApplications").toStringList(); KService::Ptr service = static_cast(entry)->service(); if (!hiddenApps.contains(service->menuId())) { hiddenApps << service->menuId(); appletConfig->insert("hiddenApplications", hiddenApps); QMetaObject::invokeMethod(appletConfig, "valueChanged", Qt::DirectConnection, Q_ARG(QString, "hiddenApplications"), Q_ARG(QVariant, hiddenApps)); refresh(); emit hiddenEntriesChanged(); } } return false; } else if (actionId == "unhideSiblingApplications") { QObject *appletInterface = rootModel()->property("appletInterface").value(); QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains("hiddenApplications")) { QStringList hiddenApps = appletConfig->value("hiddenApplications").toStringList(); foreach(const QString& app, m_hiddenEntries) { hiddenApps.removeOne(app); } appletConfig->insert("hiddenApplications", hiddenApps); QMetaObject::invokeMethod(appletConfig, "valueChanged", Qt::DirectConnection, Q_ARG(QString, "hiddenApplications"), Q_ARG(QVariant, hiddenApps)); m_hiddenEntries.clear(); refresh(); emit hiddenEntriesChanged(); } return false; } else if (actionId == "unhideChildApplications") { QObject *appletInterface = rootModel()->property("appletInterface").value(); QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (entry->type() == AbstractEntry::GroupType && appletConfig && appletConfig->contains("hiddenApplications")) { const AppsModel *appsModel = qobject_cast(entry->childModel()); if (!appsModel) { return false; } QStringList hiddenApps = appletConfig->value("hiddenApplications").toStringList(); foreach(const QString& app, appsModel->hiddenEntries()) { hiddenApps.removeOne(app); } appletConfig->insert("hiddenApplications", hiddenApps); QMetaObject::invokeMethod(appletConfig, "valueChanged", Qt::DirectConnection, Q_ARG(QString, "hiddenApplications"), Q_ARG(QVariant, hiddenApps)); refresh(); emit hiddenEntriesChanged(); } return false; } return entry->run(actionId, argument); } AbstractModel *AppsModel::modelForRow(int row) { if (row < 0 || row >= m_entryList.count()) { return 0; } return m_entryList.at(row)->childModel(); } int AppsModel::rowForModel(AbstractModel *model) { for (int i = 0; i < m_entryList.count(); ++i) { if (m_entryList.at(i)->childModel() == model) { return i; } } return -1; } int AppsModel::separatorCount() const { return m_separatorCount; } +bool AppsModel::paginate() const +{ + return m_paginate; +} + +void AppsModel::setPaginate(bool paginate) +{ + if (m_paginate != paginate) { + m_paginate = paginate; + + refresh(); + + emit paginateChanged(); + } +} + +int AppsModel::pageSize() const +{ + return m_pageSize; +} + +void AppsModel::setPageSize(int size) +{ + if (m_pageSize != size) { + m_pageSize = size; + + refresh(); + + emit pageSizeChanged(); + } +} + bool AppsModel::flat() const { return m_flat; } void AppsModel::setFlat(bool flat) { if (m_flat != flat) { m_flat = flat; refresh(); emit flatChanged(); } } bool AppsModel::sorted() const { return m_sorted; } void AppsModel::setSorted(bool sorted) { if (m_sorted != sorted) { m_sorted = sorted; refresh(); emit sortedChanged(); } } bool AppsModel::showSeparators() const { return m_showSeparators; } void AppsModel::setShowSeparators(bool showSeparators) { if (m_showSeparators != showSeparators) { m_showSeparators = showSeparators; refresh(); emit showSeparatorsChanged(); } } int AppsModel::appNameFormat() const { return m_appNameFormat; } void AppsModel::setAppNameFormat(int format) { if (m_appNameFormat != (AppEntry::NameFormat)format) { m_appNameFormat = (AppEntry::NameFormat)format; refresh(); emit appNameFormatChanged(); } } QObject* AppsModel::appletInterface() const { return m_appletInterface; } void AppsModel::setAppletInterface(QObject* appletInterface) { if (m_appletInterface != appletInterface) { m_appletInterface = appletInterface; refresh(); emit appletInterfaceChanged(); } } QStringList AppsModel::hiddenEntries() const { return m_hiddenEntries; } void AppsModel::refresh() { if (m_staticEntryList) { return; } if (rootModel() == this && !m_appletInterface) { return; } beginResetModel(); refreshInternal(); endResetModel(); if (favoritesModel()) { favoritesModel()->refresh(); } emit countChanged(); emit separatorCountChanged(); } void AppsModel::refreshInternal() { if (m_staticEntryList) { return; } if (m_entryList.count()) { qDeleteAll(m_entryList); m_entryList.clear(); emit cleared(); } m_hiddenEntries.clear(); m_separatorCount = 0; if (m_entryPath.isEmpty()) { KServiceGroup::Ptr group = KServiceGroup::root(); if (!group) { return; } bool sortByGenericName = (appNameFormat() == AppEntry::GenericNameOnly || appNameFormat() == AppEntry::GenericNameAndName); KServiceGroup::List list = group->entries(true /* sorted */, true /* excludeNoDisplay */, true /* allowSeparators */, sortByGenericName /* sortByGenericName */); for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); it++) { const KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KServiceGroup)) { KServiceGroup::Ptr subGroup(static_cast(p.data())); if (!subGroup->noDisplay() && subGroup->childCount() > 0) { - AppGroupEntry *groupEntry = new AppGroupEntry(this, subGroup, m_flat, m_sorted, m_showSeparators, m_appNameFormat); + AppGroupEntry *groupEntry = new AppGroupEntry(this, subGroup, m_paginate, m_pageSize, m_flat, + m_sorted, m_showSeparators, m_appNameFormat); m_entryList << groupEntry; } } } m_changeTimer = new QTimer(this); m_changeTimer->setSingleShot(true); m_changeTimer->setInterval(100); connect(m_changeTimer, SIGNAL(timeout()), this, SLOT(refresh())); connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), SLOT(checkSycocaChanges(QStringList))); } else { KServiceGroup::Ptr group = KServiceGroup::group(m_entryPath); processServiceGroup(group); if (m_entryList.count()) { while (m_entryList.last()->type() == AbstractEntry::SeparatorType) { m_entryList.removeLast(); --m_separatorCount; } } if (m_sorted) { sortEntries(); } + + if (m_paginate) { + QList groups; + + int at = 0; + QList page; + + foreach(AbstractEntry *app, m_entryList) { + page.append(app); + + if (at == (m_pageSize - 1)) { + at = 0; + AppsModel *model = new AppsModel(page, true, this); + groups.append(new GroupEntry(this, QString(), QString(), model)); + page.clear(); + } else { + ++at; + } + } + + if (page.count()) { + AppsModel *model = new AppsModel(page, true, this); + groups.append(new GroupEntry(this, QString(), QString(), model)); + } + + m_entryList = groups; + } } } void AppsModel::processServiceGroup(KServiceGroup::Ptr group) { if (!group || !group->isValid()) { return; } bool hasSubGroups = false; foreach(KServiceGroup::Ptr subGroup, group->groupEntries(KServiceGroup::ExcludeNoDisplay)) { if (subGroup->childCount() > 0) { hasSubGroups = true; break; } } bool sortByGenericName = (appNameFormat() == AppEntry::GenericNameOnly || appNameFormat() == AppEntry::GenericNameAndName); KServiceGroup::List list = group->entries(true /* sorted */, true /* excludeNoDisplay */, (!m_flat || (m_flat && !hasSubGroups)) /* allowSeparators */, sortByGenericName /* sortByGenericName */); QStringList hiddenApps; QObject *appletInterface = rootModel()->property("appletInterface").value(); QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains("hiddenApplications")) { hiddenApps = appletConfig->value("hiddenApplications").toStringList(); } for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); it++) { const KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KService)) { const KService::Ptr service(static_cast(p.data())); if (service->noDisplay()) { continue; } if (hiddenApps.contains(service->menuId())) { m_hiddenEntries << service->menuId(); continue; } bool found = false; foreach (const AbstractEntry *entry, m_entryList) { if (entry->type() == AbstractEntry::RunnableType && static_cast(entry)->service()->storageId() == service->storageId()) { found = true; } } if (!found) { m_entryList << new AppEntry(this, service, m_appNameFormat); } } else if (p->isType(KST_KServiceSeparator) && m_showSeparators) { if (!m_entryList.count()) { continue; } if (m_entryList.last()->type() == AbstractEntry::SeparatorType) { continue; } m_entryList << new SeparatorEntry(this); ++m_separatorCount; } else if (p->isType(KST_KServiceGroup)) { const KServiceGroup::Ptr subGroup(static_cast(p.data())); if (subGroup->childCount() == 0) { continue; } if (m_flat) { m_sorted = true; const KServiceGroup::Ptr serviceGroup(static_cast(p.data())); processServiceGroup(serviceGroup); } else { - AppGroupEntry *groupEntry = new AppGroupEntry(this, subGroup, m_flat, m_sorted, m_showSeparators, m_appNameFormat); + AppGroupEntry *groupEntry = new AppGroupEntry(this, subGroup, m_paginate, m_pageSize, m_flat, + m_sorted, m_showSeparators, m_appNameFormat); m_entryList << groupEntry; } } } } void AppsModel::sortEntries() { QCollator c; std::sort(m_entryList.begin(), m_entryList.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; } }); } void AppsModel::checkSycocaChanges(const QStringList &changes) { if (changes.contains("services") || changes.contains("apps") || changes.contains("xdgdata-apps")) { m_changeTimer->start(); } } void AppsModel::entryChanged(AbstractEntry *entry) { int i = m_entryList.indexOf(entry); if (i != -1) { QModelIndex idx = index(i, 0); emit dataChanged(idx, idx); } } diff --git a/appsmodel.h b/appsmodel.h index 6aa729b4c..b59804181 100644 --- a/appsmodel.h +++ b/appsmodel.h @@ -1,123 +1,137 @@ /*************************************************************************** * Copyright (C) 2012 Aurélien Gâteau * * Copyright (C) 2013-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 APPSMODEL_H #define APPSMODEL_H #include "abstractmodel.h" #include "appentry.h" #include class AppGroupEntry; class QTimer; class AppsModel : public AbstractModel { Q_OBJECT + Q_PROPERTY(bool paginate READ paginate WRITE setPaginate NOTIFY paginateChanged) + Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged) Q_PROPERTY(bool flat READ flat WRITE setFlat NOTIFY flatChanged) Q_PROPERTY(bool sorted READ sorted WRITE setSorted NOTIFY sortedChanged) Q_PROPERTY(bool showSeparators READ showSeparators WRITE setShowSeparators NOTIFY showSeparatorsChanged) Q_PROPERTY(int appNameFormat READ appNameFormat WRITE setAppNameFormat NOTIFY appNameFormatChanged) Q_PROPERTY(QObject* appletInterface READ appletInterface WRITE setAppletInterface NOTIFY appletInterfaceChanged); public: - explicit AppsModel(const QString &entryPath = QString(), bool flat = false, bool sorted = true, bool separators = true, QObject *parent = 0); + explicit AppsModel(const QString &entryPath = QString(), bool paginate = false, int pageSize = 24, + bool flat = false, bool sorted = true, bool separators = true, QObject *parent = 0); explicit AppsModel(const QList entryList, bool deleteEntriesOnDestruction, QObject *parent = 0); ~AppsModel(); QString description() const; void setDescription(const QString &text); virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; Q_INVOKABLE virtual bool trigger(int row, const QString &actionId, const QVariant &argument); Q_INVOKABLE AbstractModel *modelForRow(int row); Q_INVOKABLE int rowForModel(AbstractModel *model); int separatorCount() const; + bool paginate() const; + void setPaginate(bool paginate); + + int pageSize() const; + void setPageSize(int size); + bool flat() const; void setFlat(bool flat); bool sorted() const; void setSorted(bool sorted); bool showSeparators() const; void setShowSeparators(bool showSeparators); int appNameFormat() const; void setAppNameFormat(int format); QObject *appletInterface() const; void setAppletInterface(QObject *appletInterface); QStringList hiddenEntries() const; void entryChanged(AbstractEntry *entry); Q_SIGNALS: void cleared() const; + void paginateChanged() const; + void pageSizeChanged() const; void flatChanged() const; void sortedChanged() const; void showSeparatorsChanged() const; void appNameFormatChanged() const; void appletInterfaceChanged() const; void hiddenEntriesChanged() const; protected Q_SLOTS: virtual void refresh(); protected: void refreshInternal(); + bool m_paginate; + int m_pageSize; + QList m_entryList; bool m_deleteEntriesOnDestruction; int m_separatorCount; bool m_showSeparators; QObject *m_appletInterface; private Q_SLOTS: void checkSycocaChanges(const QStringList &changes); private: void processServiceGroup(KServiceGroup::Ptr group); void sortEntries(); QString m_description; QString m_entryPath; bool m_staticEntryList; QTimer *m_changeTimer; bool m_flat; bool m_sorted; AppEntry::NameFormat m_appNameFormat; QStringList m_hiddenEntries; static MenuEntryEditor *m_menuEntryEditor; }; #endif diff --git a/rootmodel.cpp b/rootmodel.cpp index 877523de4..17a557949 100644 --- a/rootmodel.cpp +++ b/rootmodel.cpp @@ -1,314 +1,408 @@ /*************************************************************************** * 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 -GroupEntry::GroupEntry(RootModel *parentModel, const QString &name, +#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_showAllSubtree(false) +, 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::showRecentApps() const + +bool RootModel::showAllApps() const { - return m_showRecentApps; + return m_showAllApps; } -void RootModel::setShowRecentApps(bool show) +void RootModel::setShowAllApps(bool show) { - if (show != m_showRecentApps) { - m_showRecentApps = show; + if (m_showAllApps != show) { + m_showAllApps = show; refresh(); - emit showRecentAppsChanged(); + emit showAllAppsChanged(); } } -bool RootModel::showAllSubtree() const +bool RootModel::showRecentApps() const { - return m_showAllSubtree; + return m_showRecentApps; } -void RootModel::setShowAllSubtree(bool show) +void RootModel::setShowRecentApps(bool show) { - if (m_showAllSubtree != show) { - m_showAllSubtree = show; + if (show != m_showRecentApps) { + m_showRecentApps = show; refresh(); - emit showAllSubtreeChanged(); + 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(); +} + void RootModel::refresh() { - if (!m_appletInterface) { + if (!m_complete) { return; } beginResetModel(); AppsModel::refreshInternal(); AppsModel *allModel = nullptr; m_recentAppsModel = nullptr; m_recentDocsModel = nullptr; m_recentContactsModel = nullptr; - if (m_showAllSubtree) { - QHash> m_categoryHash; + 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(); - foreach (const AbstractEntry *groupEntry, m_entryList) { - AbstractModel *model = groupEntry->childModel(); + for (int j = 0; j < subModel->count(); ++j) { + AppEntry *appEntry = static_cast(subModel->index(i, 0).internalPointer()); - for (int i = 0; i < model->count(); ++i) { - AbstractEntry *appEntry = static_cast(model->index(i, 0).internalPointer()); + if (appEntry->name().isEmpty()) { + continue; + } - 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; + } + }); - const QChar &first = appEntry->name().at(0).toUpper(); - m_categoryHash[first.isDigit() ? QStringLiteral("0-9") : first].append(appEntry); + + 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; + } } - } - QList groups; - QHashIterator> i(m_categoryHash); + if (!page.isEmpty()) { + AppsModel *model = new AppsModel(page, false, this); + groups.append(new GroupEntry(this, QString(), QString(), model)); + } - 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)); + 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); + } + } + + QList groups; + 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); - m_entryList << new GroupEntry(this, i18n("Power / Session"), QString(), m_systemModel); + + 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(); } - -void RootModel::extendEntryList() -{ - -} diff --git a/rootmodel.h b/rootmodel.h index 277cb2225..9be2b3ead 100644 --- a/rootmodel.h +++ b/rootmodel.h @@ -1,112 +1,123 @@ /*************************************************************************** * 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(RootModel *parentModel, const QString &name, + 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 +class RootModel : public AppsModel, public QQmlParserStatus { Q_OBJECT + Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QObject* systemFavoritesModel READ systemFavoritesModel NOTIFY systemFavoritesModelChanged) - - Q_PROPERTY(bool showAllSubtree READ showAllSubtree WRITE setShowAllSubtree NOTIFY showAllSubtreeChanged) + 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 showAllSubtree() const; - void setShowAllSubtree(bool show); + 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 showAllSubtreeChanged() 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: - void extendEntryList(); + bool m_complete; FavoritesModel *m_favorites; SystemModel *m_systemModel; - bool m_showAllSubtree; + 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 diff --git a/wheelinterceptor.cpp b/wheelinterceptor.cpp index 7d82fc0f3..804c2fe88 100644 --- a/wheelinterceptor.cpp +++ b/wheelinterceptor.cpp @@ -1,70 +1,72 @@ /*************************************************************************** * 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 "wheelinterceptor.h" #include WheelInterceptor::WheelInterceptor(QQuickItem *parent) : QQuickItem(parent) { } WheelInterceptor::~WheelInterceptor() { } QQuickItem* WheelInterceptor::destination() const { return m_destination; } void WheelInterceptor::setDestination(QQuickItem *destination) { if (m_destination != destination) { m_destination = destination; emit destinationChanged(); } } void WheelInterceptor::wheelEvent(QWheelEvent* event) { if (m_destination) { QCoreApplication::sendEvent(m_destination, event); } + + emit wheelMoved(event->angleDelta()); } QQuickItem *WheelInterceptor::findWheelArea(QQuickItem *parent) const { if (!parent) { return nullptr; } foreach(QQuickItem *child, parent->childItems()) { // HACK: ScrollView adds the WheelArea below its flickableItem with // z==-1. This is reasonable non-risky considering we know about // everything else in there, and worst case we break the mouse wheel. if (child->z() == -1) { return child; } } return nullptr; } diff --git a/wheelinterceptor.h b/wheelinterceptor.h index 375f8ac2c..a43eefc41 100644 --- a/wheelinterceptor.h +++ b/wheelinterceptor.h @@ -1,51 +1,52 @@ /************************************************************************** * 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 WHEELINTERCEPTOR_H #define WHEELINTERCEPTOR_H #include #include class WheelInterceptor : public QQuickItem { Q_OBJECT Q_PROPERTY(QQuickItem* destination READ destination WRITE setDestination NOTIFY destinationChanged) public: WheelInterceptor(QQuickItem *parent = 0); ~WheelInterceptor(); QQuickItem *destination() const; void setDestination(QQuickItem *destination); Q_INVOKABLE QQuickItem *findWheelArea(QQuickItem *parent) const; Q_SIGNALS: void destinationChanged() const; + void wheelMoved(QPoint delta) const; protected: void wheelEvent(QWheelEvent *event); private: QPointer m_destination; }; #endif