Changeset View
Changeset View
Standalone View
Standalone View
sidebar/SidebarMode.cpp
Show All 27 Lines | |||||
28 | #include "BaseData.h" | 28 | #include "BaseData.h" | ||
29 | #include "SidebarDelegate.h" | 29 | #include "SidebarDelegate.h" | ||
30 | #include "ToolTips/tooltipmanager.h" | 30 | #include "ToolTips/tooltipmanager.h" | ||
31 | 31 | | |||
32 | #include <QHBoxLayout> | 32 | #include <QHBoxLayout> | ||
33 | 33 | | |||
34 | #include <QAction> | 34 | #include <QAction> | ||
35 | #include <KAboutData> | 35 | #include <KAboutData> | ||
36 | #include <KCModuleInfo> | ||||
36 | #include <KStandardAction> | 37 | #include <KStandardAction> | ||
37 | #include <KLocalizedString> | 38 | #include <KLocalizedString> | ||
38 | #include <KIconLoader> | 39 | #include <KIconLoader> | ||
39 | #include <KLocalizedContext> | 40 | #include <KLocalizedContext> | ||
40 | #include <KServiceTypeTrader> | 41 | #include <KServiceTypeTrader> | ||
41 | #include <KXmlGuiWindow> | 42 | #include <KXmlGuiWindow> | ||
42 | #include <KActionCollection> | 43 | #include <KActionCollection> | ||
43 | #include <KPackage/Package> | 44 | #include <KPackage/Package> | ||
44 | #include <KPackage/PackageLoader> | 45 | #include <KPackage/PackageLoader> | ||
45 | #include <KDeclarative/KDeclarative> | 46 | #include <KDeclarative/KDeclarative> | ||
46 | #include <QStandardItemModel> | 47 | #include <QStandardItemModel> | ||
47 | #include <QQuickWidget> | 48 | #include <QQuickWidget> | ||
48 | #include <QQmlEngine> | 49 | #include <QQmlEngine> | ||
49 | #include <QQmlContext> | 50 | #include <QQmlContext> | ||
50 | #include <QGraphicsOpacityEffect> | 51 | #include <QGraphicsOpacityEffect> | ||
51 | #include <QLabel> | 52 | #include <QLabel> | ||
52 | #include <QDebug> | 53 | #include <QDebug> | ||
53 | 54 | | |||
55 | #include <KActivities/Stats/ResultModel> | ||||
56 | #include <KActivities/Stats/ResultSet> | ||||
57 | #include <KActivities/Stats/Terms> | ||||
58 | | ||||
59 | namespace KAStats = KActivities::Stats; | ||||
60 | | ||||
61 | using namespace KAStats; | ||||
62 | using namespace KAStats::Terms; | ||||
63 | | ||||
54 | K_PLUGIN_FACTORY( SidebarModeFactory, registerPlugin<SidebarMode>(); ) | 64 | K_PLUGIN_FACTORY( SidebarModeFactory, registerPlugin<SidebarMode>(); ) | ||
55 | 65 | | |||
56 | class SubcategoryModel : public QStandardItemModel | 66 | class SubcategoryModel : public QStandardItemModel | ||
57 | { | 67 | { | ||
58 | public: | 68 | public: | ||
59 | SubcategoryModel(QAbstractItemModel *parentModel, QObject *parent = 0) | 69 | SubcategoryModel(QAbstractItemModel *parentModel, QObject *parent = 0) | ||
60 | : QStandardItemModel(parent), | 70 | : QStandardItemModel(parent), | ||
61 | m_parentModel(parentModel) | 71 | m_parentModel(parentModel) | ||
Show All 19 Lines | 75 | { | |||
81 | beginResetModel(); | 91 | beginResetModel(); | ||
82 | endResetModel(); | 92 | endResetModel(); | ||
83 | } | 93 | } | ||
84 | 94 | | |||
85 | private: | 95 | private: | ||
86 | QAbstractItemModel *m_parentModel; | 96 | QAbstractItemModel *m_parentModel; | ||
87 | }; | 97 | }; | ||
88 | 98 | | |||
99 | class MostUsedModel : public QSortFilterProxyModel | ||||
100 | { | ||||
101 | public: | ||||
102 | MostUsedModel(QObject *parent = 0) | ||||
103 | : QSortFilterProxyModel (parent) | ||||
104 | { | ||||
105 | sort(0, Qt::DescendingOrder); | ||||
106 | setSortRole(ResultModel::ScoreRole); | ||||
107 | setDynamicSortFilter(true); | ||||
108 | //prepare default items | ||||
109 | m_defaultModel = new QStandardItemModel(this); | ||||
110 | QStandardItem *item = new QStandardItem(); | ||||
111 | item->setData(QUrl(QStringLiteral("kcm:kcm_lookandfeel.desktop")), ResultModel::ResourceRole); | ||||
112 | m_defaultModel->appendRow(item); | ||||
113 | item = new QStandardItem(); | ||||
114 | item->setData(QUrl(QStringLiteral("kcm:user_manager.desktop")), ResultModel::ResourceRole); | ||||
115 | m_defaultModel->appendRow(item); | ||||
116 | item = new QStandardItem(); | ||||
117 | item->setData(QUrl(QStringLiteral("kcm:screenlocker.desktop")), ResultModel::ResourceRole); | ||||
118 | m_defaultModel->appendRow(item); | ||||
119 | item = new QStandardItem(); | ||||
120 | item->setData(QUrl(QStringLiteral("kcm:powerdevilprofilesconfig.desktop")), ResultModel::ResourceRole); | ||||
121 | m_defaultModel->appendRow(item); | ||||
122 | item = new QStandardItem(); | ||||
123 | item->setData(QUrl(QStringLiteral("kcm:kcm_kscreen.desktop")), ResultModel::ResourceRole); | ||||
124 | m_defaultModel->appendRow(item); | ||||
125 | } | ||||
126 | | ||||
127 | void setResultModel(ResultModel *model) | ||||
128 | { | ||||
129 | if (m_resultModel == model) { | ||||
130 | return; | ||||
131 | } | ||||
132 | | ||||
133 | auto updateModel = [this]() { | ||||
davidedmundson: Can I propose an alternative:
At the moment you have
QSortFilterProxy -> (ResultModel or… | |||||
I can see a problem with this approach: if i open a module from the default list, i would then have a duplicate in the list, unless i scan the model of defaults and remove manually all the duplicates, which may become a bit complex. mart: I can see a problem with this approach: if i open a module from the default list, i would then… | |||||
134 | if (m_resultModel->rowCount() >= 5) { | ||||
135 | setSourceModel(m_resultModel); | ||||
136 | } else { | ||||
137 | setSourceModel(m_defaultModel); | ||||
138 | } | ||||
139 | }; | ||||
140 | | ||||
141 | m_resultModel = model; | ||||
142 | | ||||
143 | connect(m_resultModel, &QAbstractItemModel::rowsInserted, this, updateModel); | ||||
144 | connect(m_resultModel, &QAbstractItemModel::rowsRemoved, this, updateModel); | ||||
145 | | ||||
146 | updateModel(); | ||||
147 | } | ||||
148 | | ||||
149 | QHash<int, QByteArray> roleNames() const | ||||
150 | { | ||||
151 | QHash<int, QByteArray> roleNames; | ||||
152 | roleNames.insert(Qt::DisplayRole, "display"); | ||||
153 | roleNames.insert(Qt::DecorationRole, "decoration"); | ||||
154 | roleNames.insert(ResultModel::ScoreRole, "score"); | ||||
155 | return roleNames; | ||||
156 | } | ||||
157 | | ||||
158 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override | ||||
159 | { | ||||
160 | MenuItem *mi; | ||||
161 | const QModelIndex &mappedIndex = mapToSource(index); | ||||
162 | const QString desktopName = sourceModel()->data(mappedIndex, ResultModel::ResourceRole).toUrl().path(); | ||||
163 | | ||||
davidedmundson: just
desktopName = QSortFilterProxyModel::data(index). | |||||
mart: I need to remove the kcm: part | |||||
Right, but I meant don't call sourceModel()->data(mapToSource....) when you can just call the superclasses data method. davidedmundson: Right, but I meant don't call sourceModel()->data(mapToSource....) when you can just call the… | |||||
164 | if (m_menuItems.contains(desktopName)) { | ||||
165 | mi = m_menuItems.value(desktopName); | ||||
166 | } else { | ||||
167 | mi = new MenuItem(false, nullptr); | ||||
168 | const_cast<MostUsedModel *>(this)->m_menuItems.insert(desktopName, mi); | ||||
169 | | ||||
170 | KService::Ptr service = KService::serviceByStorageId(desktopName); | ||||
171 | | ||||
172 | if (!service || !service->isValid()) { | ||||
173 | return QVariant(); | ||||
174 | } | ||||
175 | mi->setService(service); | ||||
davidedmundson: don't you only need to do this when you create new MenuItem? | |||||
176 | } | ||||
177 | | ||||
178 | switch (role) { | ||||
179 | case Qt::UserRole: | ||||
180 | return QVariant::fromValue(mi); | ||||
181 | case Qt::DisplayRole: | ||||
182 | return mi->service()->name(); | ||||
183 | case Qt::DecorationRole: | ||||
184 | return mi->service()->icon(); | ||||
185 | case ResultModel::ScoreRole: | ||||
186 | return sourceModel()->data(mappedIndex, ResultModel::ScoreRole).toInt(); | ||||
187 | default: | ||||
188 | return QVariant(); | ||||
189 | } | ||||
190 | } | ||||
191 | | ||||
192 | private: | ||||
193 | QHash<QString, MenuItem *> m_menuItems; | ||||
194 | QStandardItemModel *m_defaultModel; | ||||
195 | ResultModel *m_resultModel; | ||||
196 | }; | ||||
197 | | ||||
89 | class SidebarMode::Private { | 198 | class SidebarMode::Private { | ||
90 | public: | 199 | public: | ||
91 | Private() | 200 | Private() | ||
92 | : quickWidget( nullptr ), | 201 | : quickWidget( nullptr ), | ||
93 | moduleView( nullptr ), | 202 | moduleView( nullptr ), | ||
94 | collection( nullptr ), | 203 | collection( nullptr ), | ||
95 | activeCategory( -1 ), | 204 | activeCategory( -1 ), | ||
96 | activeSubCategory( -1 ) | 205 | activeSubCategory( -1 ) | ||
97 | {} | 206 | {} | ||
98 | 207 | | |||
99 | virtual ~Private() { | 208 | virtual ~Private() { | ||
100 | delete aboutIcon; | 209 | delete aboutIcon; | ||
101 | } | 210 | } | ||
102 | 211 | | |||
103 | ToolTipManager *toolTipManager; | 212 | ToolTipManager *toolTipManager; | ||
104 | QQuickWidget * quickWidget; | 213 | QQuickWidget * quickWidget; | ||
105 | KPackage::Package package; | 214 | KPackage::Package package; | ||
106 | SubcategoryModel * subCategoryModel; | 215 | SubcategoryModel * subCategoryModel; | ||
216 | MostUsedModel * mostUsedModel; | ||||
107 | QWidget * mainWidget; | 217 | QWidget * mainWidget; | ||
108 | QQuickWidget * placeHolderWidget; | 218 | QQuickWidget * placeHolderWidget; | ||
109 | QHBoxLayout * mainLayout; | 219 | QHBoxLayout * mainLayout; | ||
110 | KDeclarative::KDeclarative kdeclarative; | 220 | KDeclarative::KDeclarative kdeclarative; | ||
111 | MenuProxyModel * proxyModel; | 221 | MenuProxyModel * proxyModel; | ||
112 | KAboutData * aboutIcon; | 222 | KAboutData * aboutIcon; | ||
113 | ModuleView * moduleView; | 223 | ModuleView * moduleView; | ||
114 | KActionCollection *collection; | 224 | KActionCollection *collection; | ||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | 267 | { | |||
158 | return d->proxyModel; | 268 | return d->proxyModel; | ||
159 | } | 269 | } | ||
160 | 270 | | |||
161 | QAbstractItemModel * SidebarMode::subCategoryModel() const | 271 | QAbstractItemModel * SidebarMode::subCategoryModel() const | ||
162 | { | 272 | { | ||
163 | return d->subCategoryModel; | 273 | return d->subCategoryModel; | ||
164 | } | 274 | } | ||
165 | 275 | | |||
276 | QAbstractItemModel * SidebarMode::mostUsedModel() const | ||||
277 | { | ||||
278 | return d->mostUsedModel; | ||||
279 | } | ||||
280 | | ||||
166 | QList<QAbstractItemView*> SidebarMode::views() const | 281 | QList<QAbstractItemView*> SidebarMode::views() const | ||
167 | { | 282 | { | ||
168 | QList<QAbstractItemView*> list; | 283 | QList<QAbstractItemView*> list; | ||
169 | //list.append( d->categoryView ); | 284 | //list.append( d->categoryView ); | ||
170 | return list; | 285 | return list; | ||
171 | } | 286 | } | ||
172 | 287 | | |||
173 | void SidebarMode::initEvent() | 288 | void SidebarMode::initEvent() | ||
174 | { | 289 | { | ||
175 | MenuModel * model = new MenuModel( rootItem(), this ); | 290 | MenuModel * model = new MenuModel( rootItem(), this ); | ||
176 | foreach( MenuItem * child, rootItem()->children() ) { | 291 | foreach( MenuItem * child, rootItem()->children() ) { | ||
177 | model->addException( child ); | 292 | model->addException( child ); | ||
178 | } | 293 | } | ||
179 | 294 | | |||
180 | d->proxyModel = new MenuProxyModel( this ); | 295 | d->proxyModel = new MenuProxyModel( this ); | ||
181 | d->proxyModel->setCategorizedModel( true ); | 296 | d->proxyModel->setCategorizedModel( true ); | ||
182 | d->proxyModel->setSourceModel( model ); | 297 | d->proxyModel->setSourceModel( model ); | ||
183 | d->proxyModel->setFilterHighlightsEntries( false ); | 298 | d->proxyModel->setFilterHighlightsEntries( false ); | ||
184 | connect( d->proxyModel, &MenuProxyModel::filterRegExpChanged, this, &SidebarMode::activeCategoryChanged ); | 299 | connect( d->proxyModel, &MenuProxyModel::filterRegExpChanged, this, &SidebarMode::activeCategoryChanged ); | ||
185 | 300 | | |||
301 | d->mostUsedModel = new MostUsedModel( this ); | ||||
302 | | ||||
186 | d->subCategoryModel = new SubcategoryModel( d->proxyModel, this ); | 303 | d->subCategoryModel = new SubcategoryModel( d->proxyModel, this ); | ||
187 | d->mainWidget = new QWidget(); | 304 | d->mainWidget = new QWidget(); | ||
188 | d->mainWidget->installEventFilter(this); | 305 | d->mainWidget->installEventFilter(this); | ||
189 | d->mainLayout = new QHBoxLayout(d->mainWidget); | 306 | d->mainLayout = new QHBoxLayout(d->mainWidget); | ||
190 | d->mainLayout->setContentsMargins(0, 0, 0, 0); | 307 | d->mainLayout->setContentsMargins(0, 0, 0, 0); | ||
191 | d->moduleView = new ModuleView( d->mainWidget ); | 308 | d->moduleView = new ModuleView( d->mainWidget ); | ||
192 | connect( d->moduleView, &ModuleView::moduleChanged, this, &SidebarMode::moduleLoaded ); | 309 | connect( d->moduleView, &ModuleView::moduleChanged, this, &SidebarMode::moduleLoaded ); | ||
193 | connect( d->moduleView, &ModuleView::closeRequest, this, &SidebarMode::leaveModuleView ); | 310 | connect( d->moduleView, &ModuleView::closeRequest, this, &SidebarMode::leaveModuleView ); | ||
Show All 20 Lines | 328 | { | |||
214 | } | 331 | } | ||
215 | } | 332 | } | ||
216 | 333 | | |||
217 | void SidebarMode::hideToolTip() | 334 | void SidebarMode::hideToolTip() | ||
218 | { | 335 | { | ||
219 | d->toolTipManager->hideToolTip(); | 336 | d->toolTipManager->hideToolTip(); | ||
220 | } | 337 | } | ||
221 | 338 | | |||
339 | Q_INVOKABLE void SidebarMode::loadMostUsed(int index) | ||||
340 | { | ||||
341 | const QModelIndex idx = d->mostUsedModel->index(index, 0); | ||||
342 | d->moduleView->closeModules(); | ||||
343 | d->moduleView->loadModule( idx ); | ||||
344 | } | ||||
345 | | ||||
222 | void SidebarMode::changeModule( const QModelIndex& activeModule ) | 346 | void SidebarMode::changeModule( const QModelIndex& activeModule ) | ||
223 | { | 347 | { | ||
224 | d->moduleView->closeModules(); | 348 | d->moduleView->closeModules(); | ||
225 | 349 | | |||
226 | const int subRows = d->proxyModel->rowCount(activeModule); | 350 | const int subRows = d->proxyModel->rowCount(activeModule); | ||
227 | if ( subRows < 2) { | 351 | if ( subRows < 2) { | ||
228 | d->moduleView->loadModule( activeModule ); | 352 | d->moduleView->loadModule( activeModule ); | ||
229 | } else { | 353 | } else { | ||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Line(s) | 409 | { | |||
329 | d->placeHolderWidget->engine()->rootContext()->setContextProperty("systemsettings", this); | 453 | d->placeHolderWidget->engine()->rootContext()->setContextProperty("systemsettings", this); | ||
330 | d->placeHolderWidget->setSource(d->package.filePath("ui", "introPage.qml")); | 454 | d->placeHolderWidget->setSource(d->package.filePath("ui", "introPage.qml")); | ||
331 | 455 | | |||
332 | d->mainLayout->addWidget( d->quickWidget ); | 456 | d->mainLayout->addWidget( d->quickWidget ); | ||
333 | d->moduleView->hide(); | 457 | d->moduleView->hide(); | ||
334 | d->mainLayout->addWidget( d->moduleView ); | 458 | d->mainLayout->addWidget( d->moduleView ); | ||
335 | d->mainLayout->addWidget( d->placeHolderWidget ); | 459 | d->mainLayout->addWidget( d->placeHolderWidget ); | ||
336 | emit changeToolBarItems(BaseMode::NoItems); | 460 | emit changeToolBarItems(BaseMode::NoItems); | ||
461 | | ||||
462 | d->mostUsedModel->setResultModel(new ResultModel( AllResources | Agent("org.kde.systemsettings") | HighScoredFirst | Limit(5), this)); | ||||
337 | } | 463 | } | ||
338 | 464 | | |||
339 | bool SidebarMode::eventFilter(QObject* watched, QEvent* event) | 465 | bool SidebarMode::eventFilter(QObject* watched, QEvent* event) | ||
340 | { | 466 | { | ||
341 | //TODO: patch Qt | 467 | //TODO: patch Qt | ||
342 | if (watched == d->quickWidget && event->type() == QEvent::Leave) { | 468 | if (watched == d->quickWidget && event->type() == QEvent::Leave) { | ||
343 | QCoreApplication::sendEvent(d->quickWidget->quickWindow(), event); | 469 | QCoreApplication::sendEvent(d->quickWidget->quickWindow(), event); | ||
344 | } else if (watched == d->mainWidget && event->type() == QEvent::Resize) { | 470 | } else if (watched == d->mainWidget && event->type() == QEvent::Resize) { | ||
Show All 16 Lines |
Can I propose an alternative:
At the moment you have
QSortFilterProxy -> (ResultModel or DefaultModel)
It might be neater to have
QSortFilterProxy -> KConcatanateRowsProxyModel (ResultModel and DefaultModel)
this means it'll start showing recently used as soon as you open 1 module and you don't need to have any logic code here.