]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/places/placespanel.cpp
Merge branch 'release/21.12'
[dolphin.git] / src / panels / places / placespanel.cpp
1 /*
2 * SPDX-FileCopyrightText: 2008-2012 Peter Penz <peter.penz19@gmail.com>
3 *
4 * Based on KFilePlacesView from kdelibs:
5 * SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
6 * SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "placespanel.h"
12
13 #include "dolphin_generalsettings.h"
14 #include "global.h"
15 #include "kitemviews/kitemlistcontainer.h"
16 #include "kitemviews/kitemlistcontroller.h"
17 #include "kitemviews/kitemlistselectionmanager.h"
18 #include "kitemviews/kstandarditem.h"
19 #include "placesitem.h"
20 #include "placesitemlistgroupheader.h"
21 #include "placesitemlistwidget.h"
22 #include "placesitemmodel.h"
23 #include "placesview.h"
24 #include "trash/dolphintrash.h"
25 #include "views/draganddrophelper.h"
26 #include "settings/dolphinsettingsdialog.h"
27
28 #include <KFilePlaceEditDialog>
29 #include <KFilePlacesModel>
30 #include <KIO/DropJob>
31 #include <KIO/EmptyTrashJob>
32 #include <KIO/Job>
33 #include <KIconLoader>
34 #include <KLocalizedString>
35 #include <KMountPoint>
36 #include <KPropertiesDialog>
37
38 #include <QActionGroup>
39 #include <QApplication>
40 #include <QGraphicsSceneDragDropEvent>
41 #include <QIcon>
42 #include <QMenu>
43 #include <QMimeData>
44 #include <QVBoxLayout>
45 #include <QToolTip>
46
47 PlacesPanel::PlacesPanel(QWidget* parent) :
48 Panel(parent),
49 m_controller(nullptr),
50 m_model(nullptr),
51 m_view(nullptr),
52 m_storageSetupFailedUrl(),
53 m_triggerStorageSetupModifier(),
54 m_itemDropEventIndex(-1),
55 m_itemDropEventMimeData(nullptr),
56 m_itemDropEvent(nullptr),
57 m_tooltipTimer()
58 {
59 m_tooltipTimer.setInterval(500);
60 m_tooltipTimer.setSingleShot(true);
61 connect(&m_tooltipTimer, &QTimer::timeout, this, &PlacesPanel::slotShowTooltip);
62 }
63
64 PlacesPanel::~PlacesPanel()
65 {
66 }
67
68 void PlacesPanel::proceedWithTearDown()
69 {
70 m_model->proceedWithTearDown();
71 }
72
73 bool PlacesPanel::urlChanged()
74 {
75 if (!url().isValid() || url().scheme().contains(QLatin1String("search"))) {
76 // Skip results shown by a search, as possible identical
77 // directory names are useless without parent-path information.
78 return false;
79 }
80
81 if (m_controller) {
82 selectItem();
83 }
84
85 return true;
86 }
87
88 void PlacesPanel::readSettings()
89 {
90 if (m_controller) {
91 const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
92 m_controller->setAutoActivationDelay(delay);
93 }
94 }
95
96 void PlacesPanel::showEvent(QShowEvent* event)
97 {
98 if (event->spontaneous()) {
99 Panel::showEvent(event);
100 return;
101 }
102
103 if (!m_controller) {
104 // Postpone the creating of the controller to the first show event.
105 // This assures that no performance and memory overhead is given when the folders panel is not
106 // used at all and stays invisible.
107 m_model = new PlacesItemModel(this);
108 m_model->setGroupedSorting(true);
109 connect(m_model, &PlacesItemModel::errorMessage,
110 this, &PlacesPanel::errorMessage);
111 connect(m_model, &PlacesItemModel::storageTearDownRequested,
112 this, &PlacesPanel::storageTearDownRequested);
113 connect(m_model, &PlacesItemModel::storageTearDownExternallyRequested,
114 this, &PlacesPanel::storageTearDownExternallyRequested);
115 connect(m_model, &PlacesItemModel::storageTearDownSuccessful,
116 this, &PlacesPanel::storageTearDownSuccessful);
117
118 m_view = new PlacesView();
119 m_view->setWidgetCreator(new KItemListWidgetCreator<PlacesItemListWidget>());
120 m_view->setGroupHeaderCreator(new KItemListGroupHeaderCreator<PlacesItemListGroupHeader>());
121
122 installEventFilter(this);
123
124 m_controller = new KItemListController(m_model, m_view, this);
125 m_controller->setSelectionBehavior(KItemListController::SingleSelection);
126 m_controller->setSingleClickActivationEnforced(true);
127
128 readSettings();
129
130 connect(m_controller, &KItemListController::itemActivated, this, &PlacesPanel::slotItemActivated);
131 connect(m_controller, &KItemListController::itemMiddleClicked, this, &PlacesPanel::slotItemMiddleClicked);
132 connect(m_controller, &KItemListController::itemContextMenuRequested, this, &PlacesPanel::slotItemContextMenuRequested);
133 connect(m_controller, &KItemListController::viewContextMenuRequested, this, &PlacesPanel::slotViewContextMenuRequested);
134 connect(m_controller, &KItemListController::itemDropEvent, this, &PlacesPanel::slotItemDropEvent);
135 connect(m_controller, &KItemListController::aboveItemDropEvent, this, &PlacesPanel::slotAboveItemDropEvent);
136
137 KItemListContainer* container = new KItemListContainer(m_controller, this);
138 container->setEnabledFrame(false);
139
140 QVBoxLayout* layout = new QVBoxLayout(this);
141 layout->setContentsMargins(0, 0, 0, 0);
142 layout->addWidget(container);
143
144 selectItem();
145 }
146
147 Panel::showEvent(event);
148 }
149
150 bool PlacesPanel::eventFilter(QObject * /* obj */, QEvent *event)
151 {
152 if (event->type() == QEvent::ToolTip) {
153
154 QHelpEvent *hoverEvent = reinterpret_cast<QHelpEvent *>(event);
155
156 m_hoveredIndex = m_view->itemAt(hoverEvent->pos());
157 m_hoverPos = mapToGlobal(hoverEvent->pos());
158
159 m_tooltipTimer.start();
160 return true;
161 }
162 return false;
163 }
164
165 void PlacesPanel::slotItemActivated(int index)
166 {
167 const auto modifiers = QGuiApplication::keyboardModifiers();
168 // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
169 if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) {
170 triggerItem(index, TriggerItemModifier::ToNewActiveTab);
171 } else if (modifiers & Qt::ControlModifier) {
172 triggerItem(index, TriggerItemModifier::ToNewTab);
173 } else if (modifiers & Qt::ShiftModifier) {
174 triggerItem(index, TriggerItemModifier::ToNewWindow);
175 } else {
176 triggerItem(index, TriggerItemModifier::None);
177 }
178 }
179
180 void PlacesPanel::slotItemMiddleClicked(int index)
181 {
182 const auto modifiers = QGuiApplication::keyboardModifiers();
183 // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
184 if (modifiers & Qt::ShiftModifier) {
185 triggerItem(index, TriggerItemModifier::ToNewActiveTab);
186 } else {
187 triggerItem(index, TriggerItemModifier::ToNewTab);
188 }
189 }
190
191 void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
192 {
193 PlacesItem* item = m_model->placesItem(index);
194 if (!item) {
195 return;
196 }
197
198 QMenu menu(this);
199
200 QAction* emptyTrashAction = nullptr;
201 QAction* configureTrashAction = nullptr;
202 QAction* editAction = nullptr;
203 QAction* teardownAction = nullptr;
204 QAction* ejectAction = nullptr;
205 QAction* mountAction = nullptr;
206
207 const bool isDevice = !item->udi().isEmpty();
208 const bool isTrash = (item->url().scheme() == QLatin1String("trash"));
209 if (isTrash) {
210 emptyTrashAction = menu.addAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18nc("@action:inmenu", "Empty Trash"));
211 emptyTrashAction->setEnabled(item->icon() == QLatin1String("user-trash-full"));
212 menu.addSeparator();
213 }
214
215 QAction* openInNewTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@item:inmenu", "Open in New Tab"));
216 QAction* openInNewWindowAction = menu.addAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("@item:inmenu", "Open in New Window"));
217 QAction* propertiesAction = nullptr;
218 if (item->url().isLocalFile()) {
219 propertiesAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action:inmenu", "Properties"));
220 }
221 if (!isDevice) {
222 menu.addSeparator();
223 }
224
225 if (isDevice) {
226 ejectAction = m_model->ejectAction(index);
227 if (ejectAction) {
228 ejectAction->setParent(&menu);
229 menu.addAction(ejectAction);
230 }
231
232 teardownAction = m_model->teardownAction(index);
233 if (teardownAction) {
234 // Disable teardown option for root and home partitions
235 bool teardownEnabled = item->url() != QUrl::fromLocalFile(QDir::rootPath());
236 if (teardownEnabled) {
237 KMountPoint::Ptr mountPoint = KMountPoint::currentMountPoints().findByPath(QDir::homePath());
238 if (mountPoint && item->url() == QUrl::fromLocalFile(mountPoint->mountPoint())) {
239 teardownEnabled = false;
240 }
241 }
242 teardownAction->setEnabled(teardownEnabled);
243
244 teardownAction->setParent(&menu);
245 menu.addAction(teardownAction);
246 }
247
248 if (item->storageSetupNeeded()) {
249 mountAction = menu.addAction(QIcon::fromTheme(QStringLiteral("media-mount")), i18nc("@action:inmenu", "Mount"));
250 }
251
252 if (teardownAction || ejectAction || mountAction) {
253 menu.addSeparator();
254 }
255 }
256
257 if (isTrash) {
258 configureTrashAction = menu.addAction(QIcon::fromTheme(QStringLiteral("configure")), i18nc("@action:inmenu", "Configure Trash..."));
259 }
260
261 if (!isDevice) {
262 editAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-entry")), i18nc("@item:inmenu", "Edit..."));
263 }
264
265 QAction* removeAction = nullptr;
266 if (!isDevice && !item->isSystemItem()) {
267 removeAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@item:inmenu", "Remove"));
268 }
269
270 QAction* hideAction = menu.addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide"));
271 hideAction->setCheckable(true);
272 hideAction->setChecked(item->isHidden());
273
274 buildGroupContextMenu(&menu, index);
275
276 QAction* action = menu.exec(pos.toPoint());
277 if (action) {
278 if (action == emptyTrashAction) {
279 Trash::empty(this);
280 } else if (action == configureTrashAction) {
281 DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(item->url(), this);
282 settingsDialog->setCurrentPage(settingsDialog->trashSettings);
283 settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
284 settingsDialog->show();
285 } else {
286 // The index might have changed if devices were added/removed while
287 // the context menu was open.
288 index = m_model->index(item);
289 if (index < 0) {
290 // The item is not in the model any more, probably because it was an
291 // external device that has been removed while the context menu was open.
292 return;
293 }
294
295 if (action == editAction) {
296 editEntry(index);
297 } else if (action == removeAction) {
298 m_model->deleteItem(index);
299 } else if (action == hideAction) {
300 item->setHidden(hideAction->isChecked());
301 if (!m_model->hiddenCount()) {
302 showHiddenEntries(false);
303 }
304 } else if (action == openInNewWindowAction) {
305 Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(m_model->data(index).value("url").toUrl())}, this);
306 } else if (action == openInNewTabAction) {
307 triggerItem(index, TriggerItemModifier::ToNewTab);
308 } else if (action == mountAction) {
309 m_model->requestStorageSetup(index);
310 } else if (action == teardownAction) {
311 m_model->requestTearDown(index);
312 } else if (action == ejectAction) {
313 m_model->requestEject(index);
314 } else if (action == propertiesAction) {
315 KPropertiesDialog* dialog = new KPropertiesDialog(item->url(), this);
316 dialog->setAttribute(Qt::WA_DeleteOnClose);
317 dialog->show();
318 }
319 }
320 }
321
322 selectItem();
323 }
324
325 void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos)
326 {
327 QMenu menu(this);
328
329 QAction* addAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-new")), i18nc("@item:inmenu", "Add Entry..."));
330
331 QAction* showAllAction = menu.addAction(i18nc("@item:inmenu", "Show Hidden Places"));
332 showAllAction->setCheckable(true);
333 showAllAction->setChecked(m_model->hiddenItemsShown());
334 showAllAction->setIcon(QIcon::fromTheme(m_model->hiddenItemsShown() ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
335 showAllAction->setEnabled(m_model->hiddenCount());
336
337 buildGroupContextMenu(&menu, m_controller->indexCloseToMousePressedPosition());
338
339 QMenu* iconSizeSubMenu = new QMenu(i18nc("@item:inmenu", "Icon Size"), &menu);
340
341 struct IconSizeInfo
342 {
343 int size;
344 const char* context;
345 const char* text;
346 };
347
348 const int iconSizeCount = 4;
349 static const IconSizeInfo iconSizes[iconSizeCount] = {
350 {KIconLoader::SizeSmall, I18NC_NOOP("Small icon size", "Small (%1x%2)")},
351 {KIconLoader::SizeSmallMedium, I18NC_NOOP("Medium icon size", "Medium (%1x%2)")},
352 {KIconLoader::SizeMedium, I18NC_NOOP("Large icon size", "Large (%1x%2)")},
353 {KIconLoader::SizeLarge, I18NC_NOOP("Huge icon size", "Huge (%1x%2)")}
354 };
355
356 QHash<QAction*, int> iconSizeActionMap;
357 QActionGroup* iconSizeGroup = new QActionGroup(iconSizeSubMenu);
358
359 for (int i = 0; i < iconSizeCount; ++i) {
360 const int size = iconSizes[i].size;
361 const QString text = i18nc(iconSizes[i].context, iconSizes[i].text,
362 size, size);
363
364 QAction* action = iconSizeSubMenu->addAction(text);
365 iconSizeActionMap.insert(action, size);
366 action->setActionGroup(iconSizeGroup);
367 action->setCheckable(true);
368 action->setChecked(m_view->iconSize() == size);
369 }
370
371 menu.addMenu(iconSizeSubMenu);
372
373 menu.addSeparator();
374 const auto actions = customContextMenuActions();
375 for (QAction* action : actions) {
376 menu.addAction(action);
377 }
378
379 QAction* action = menu.exec(pos.toPoint());
380 if (action) {
381 if (action == addAction) {
382 addEntry();
383 } else if (action == showAllAction) {
384 showHiddenEntries(showAllAction->isChecked());
385 } else if (iconSizeActionMap.contains(action)) {
386 m_view->setIconSize(iconSizeActionMap.value(action));
387 }
388 }
389
390 selectItem();
391 }
392
393 QAction *PlacesPanel::buildGroupContextMenu(QMenu *menu, int index)
394 {
395 if (index == -1) {
396 return nullptr;
397 }
398
399 KFilePlacesModel::GroupType groupType = m_model->groupType(index);
400 QAction *hideGroupAction = menu->addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide Section '%1'", m_model->item(index)->group()));
401 hideGroupAction->setCheckable(true);
402 hideGroupAction->setChecked(m_model->isGroupHidden(groupType));
403
404 connect(hideGroupAction, &QAction::triggered, this, [this, groupType, hideGroupAction]{
405 m_model->setGroupHidden(groupType, hideGroupAction->isChecked());
406 if (!m_model->hiddenCount()) {
407 showHiddenEntries(false);
408 }
409 });
410
411 return hideGroupAction;
412 }
413
414 void PlacesPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
415 {
416 if (index < 0) {
417 return;
418 }
419
420 const PlacesItem* destItem = m_model->placesItem(index);
421
422 if (destItem->isSearchOrTimelineUrl()) {
423 return;
424 }
425
426 if (m_model->storageSetupNeeded(index)) {
427 connect(m_model, &PlacesItemModel::storageSetupDone,
428 this, &PlacesPanel::slotItemDropEventStorageSetupDone);
429
430 m_itemDropEventIndex = index;
431
432 // Make a full copy of the Mime-Data
433 m_itemDropEventMimeData = new QMimeData;
434 m_itemDropEventMimeData->setText(event->mimeData()->text());
435 m_itemDropEventMimeData->setHtml(event->mimeData()->html());
436 m_itemDropEventMimeData->setUrls(event->mimeData()->urls());
437 m_itemDropEventMimeData->setImageData(event->mimeData()->imageData());
438 m_itemDropEventMimeData->setColorData(event->mimeData()->colorData());
439
440 m_itemDropEvent = new QDropEvent(event->pos().toPoint(),
441 event->possibleActions(),
442 m_itemDropEventMimeData,
443 event->buttons(),
444 event->modifiers());
445
446 m_model->requestStorageSetup(index);
447 return;
448 }
449
450 QUrl destUrl = destItem->url();
451 QDropEvent dropEvent(event->pos().toPoint(),
452 event->possibleActions(),
453 event->mimeData(),
454 event->buttons(),
455 event->modifiers());
456
457 slotUrlsDropped(destUrl, &dropEvent, this);
458 }
459
460 void PlacesPanel::slotItemDropEventStorageSetupDone(int index, bool success)
461 {
462 disconnect(m_model, &PlacesItemModel::storageSetupDone,
463 this, &PlacesPanel::slotItemDropEventStorageSetupDone);
464
465 if ((index == m_itemDropEventIndex) && m_itemDropEvent && m_itemDropEventMimeData) {
466 if (success) {
467 QUrl destUrl = m_model->placesItem(index)->url();
468 slotUrlsDropped(destUrl, m_itemDropEvent, this);
469 }
470
471 delete m_itemDropEventMimeData;
472 delete m_itemDropEvent;
473
474 m_itemDropEventIndex = -1;
475 m_itemDropEventMimeData = nullptr;
476 m_itemDropEvent = nullptr;
477 }
478 }
479
480 void PlacesPanel::slotAboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
481 {
482 m_model->dropMimeDataBefore(index, event->mimeData());
483 }
484
485 void PlacesPanel::slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget* parent)
486 {
487 KIO::DropJob *job = DragAndDropHelper::dropUrls(dest, event, parent);
488 if (job) {
489 connect(job, &KIO::DropJob::result, this, [this](KJob *job) { if (job->error()) Q_EMIT errorMessage(job->errorString()); });
490 }
491 }
492
493 void PlacesPanel::slotStorageSetupDone(int index, bool success)
494 {
495 disconnect(m_model, &PlacesItemModel::storageSetupDone,
496 this, &PlacesPanel::slotStorageSetupDone);
497
498 if (m_triggerStorageSetupModifier == TriggerItemModifier::None) {
499 return;
500 }
501
502 if (success) {
503 Q_ASSERT(!m_model->storageSetupNeeded(index));
504 triggerItem(index, m_triggerStorageSetupModifier);
505 m_triggerStorageSetupModifier = TriggerItemModifier::None;
506 } else {
507 setUrl(m_storageSetupFailedUrl);
508 m_storageSetupFailedUrl = QUrl();
509 }
510 }
511
512 void PlacesPanel::slotShowTooltip()
513 {
514 const QUrl url = m_model->data(m_hoveredIndex).value("url").value<QUrl>();
515 const QString text = url.toDisplayString(QUrl::PreferLocalFile);
516 QToolTip::showText(m_hoverPos, text);
517 }
518
519 void PlacesPanel::addEntry()
520 {
521 const int index = m_controller->selectionManager()->currentItem();
522 const QUrl url = m_model->data(index).value("url").toUrl();
523 const QString text = url.fileName().isEmpty() ? url.toDisplayString(QUrl::PreferLocalFile) : url.fileName();
524
525 QPointer<KFilePlaceEditDialog> dialog = new KFilePlaceEditDialog(true, url, text, QString(), true, false, KIconLoader::SizeMedium, this);
526 if (dialog->exec() == QDialog::Accepted) {
527 const QString appName = dialog->applicationLocal() ? QCoreApplication::applicationName() : QString();
528 m_model->createPlacesItem(dialog->label(), dialog->url(), dialog->icon(), appName);
529 }
530
531 delete dialog;
532 }
533
534 void PlacesPanel::editEntry(int index)
535 {
536 QHash<QByteArray, QVariant> data = m_model->data(index);
537 const QUrl url = data.value("url").toUrl();
538 const QString text = data.value("text").toString();
539 const QString iconName = data.value("iconName").toString();
540 const bool applicationLocal = !data.value("applicationName").toString().isEmpty();
541
542 QPointer<KFilePlaceEditDialog> dialog = new KFilePlaceEditDialog(true, url, text, iconName, true, applicationLocal, KIconLoader::SizeMedium, this);
543 if (dialog->exec() == QDialog::Accepted) {
544 PlacesItem* oldItem = m_model->placesItem(index);
545 if (oldItem) {
546 const QString appName = dialog->applicationLocal() ? QCoreApplication::applicationName() : QString();
547 oldItem->setApplicationName(appName);
548 oldItem->setText(dialog->label());
549 oldItem->setUrl(dialog->url());
550 oldItem->setIcon(dialog->icon());
551 m_model->refresh();
552 }
553 }
554
555 delete dialog;
556 }
557
558 void PlacesPanel::selectItem()
559 {
560 const int index = m_model->closestItem(url());
561 KItemListSelectionManager* selectionManager = m_controller->selectionManager();
562 selectionManager->setCurrentItem(index);
563 selectionManager->clearSelection();
564
565 const QUrl closestUrl = m_model->url(index);
566 if (!closestUrl.path().isEmpty() && url() == closestUrl) {
567 selectionManager->setSelected(index);
568 }
569 }
570
571 void PlacesPanel::triggerItem(int index, TriggerItemModifier modifier)
572 {
573 const PlacesItem* item = m_model->placesItem(index);
574 if (!item) {
575 return;
576 }
577
578 if (m_model->storageSetupNeeded(index)) {
579 m_triggerStorageSetupModifier = modifier;
580 m_storageSetupFailedUrl = url();
581
582 connect(m_model, &PlacesItemModel::storageSetupDone,
583 this, &PlacesPanel::slotStorageSetupDone);
584
585 m_model->requestStorageSetup(index);
586 } else {
587 m_triggerStorageSetupModifier = TriggerItemModifier::None;
588
589 const QUrl url = m_model->data(index).value("url").toUrl();
590 if (!url.isEmpty()) {
591 switch (modifier) {
592 case TriggerItemModifier::ToNewTab:
593 Q_EMIT placeActivatedInNewTab(KFilePlacesModel::convertedUrl(url));
594 break;
595 case TriggerItemModifier::ToNewActiveTab:
596 Q_EMIT placeActivatedInNewActiveTab(KFilePlacesModel::convertedUrl(url));
597 break;
598 case TriggerItemModifier::ToNewWindow:
599 Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(url)}, this);
600 break;
601 case TriggerItemModifier::None:
602 Q_EMIT placeActivated(KFilePlacesModel::convertedUrl(url));
603 break;
604 }
605 }
606 }
607 }
608
609 void PlacesPanel::showHiddenEntries(bool shown)
610 {
611 m_model->setHiddenItemsShown(shown);
612 Q_EMIT showHiddenEntriesChanged(shown);
613 }
614
615 int PlacesPanel::hiddenListCount()
616 {
617 if(!m_model) {
618 return 0;
619 }
620 return m_model->hiddenCount();
621 }