]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Port back to KFilePlacesView
authorKai Uwe Broulik <kde@privat.broulik.de>
Thu, 16 Dec 2021 18:29:22 +0000 (19:29 +0100)
committerKai Uwe Broulik <kde@privat.broulik.de>
Sun, 9 Jan 2022 17:09:10 +0000 (18:09 +0100)
This removes the custom-view engine version of the places panel
and replaces it with the upstream `KFilePlacesView` from KIO.

24 files changed:
CMakeLists.txt
src/CMakeLists.txt
src/dolphincontextmenu.cpp
src/dolphinmainwindow.cpp
src/dolphinplacesmodelsingleton.cpp
src/dolphinplacesmodelsingleton.h
src/panels/places/dolphin_placespanelsettings.kcfg
src/panels/places/placesitem.cpp [deleted file]
src/panels/places/placesitem.h [deleted file]
src/panels/places/placesitemlistgroupheader.cpp [deleted file]
src/panels/places/placesitemlistgroupheader.h [deleted file]
src/panels/places/placesitemlistwidget.cpp [deleted file]
src/panels/places/placesitemlistwidget.h [deleted file]
src/panels/places/placesitemmodel.cpp [deleted file]
src/panels/places/placesitemmodel.h [deleted file]
src/panels/places/placesitemsignalhandler.cpp [deleted file]
src/panels/places/placesitemsignalhandler.h [deleted file]
src/panels/places/placespanel.cpp
src/panels/places/placespanel.h
src/panels/places/placesview.cpp [deleted file]
src/panels/places/placesview.h [deleted file]
src/search/dolphinsearchbox.cpp
src/tests/CMakeLists.txt
src/tests/placesitemmodeltest.cpp [deleted file]

index 2f26ae85f96ac7f3a9501518b95a3135c2107073..f58fab1fa7aa16bfbf7cd8f6d87cec7c5a6273fe 100644 (file)
@@ -8,7 +8,7 @@ set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE
 project(Dolphin VERSION ${RELEASE_SERVICE_VERSION})
 
 set(QT_MIN_VERSION "5.15.0")
-set(KF5_MIN_VERSION "5.90.0")
+set(KF5_MIN_VERSION "5.91.0")
 
 # ECM setup
 find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED)
index 651f021e6400841e6e36766ba5371f9027be5475..a3a15aaf3beb8c976dc77930a399b8a60729975f 100644 (file)
@@ -223,12 +223,6 @@ target_sources(dolphinstatic PRIVATE
     trash/dolphintrash.cpp
     filterbar/filterbar.cpp
     panels/places/placespanel.cpp
-    panels/places/placesitem.cpp
-    panels/places/placesitemlistgroupheader.cpp
-    panels/places/placesitemlistwidget.cpp
-    panels/places/placesitemmodel.cpp
-    panels/places/placesitemsignalhandler.cpp
-    panels/places/placesview.cpp
     panels/panel.cpp
     panels/folders/foldersitemlistwidget.cpp
     panels/folders/treeviewcontextmenu.cpp
index 028fd98bd26269bb125f4e2bfcc372a3801f8960..340af6bd0223be8e0c68e81725cda0719cd62c4c 100644 (file)
@@ -13,8 +13,6 @@
 #include "dolphinplacesmodelsingleton.h"
 #include "dolphinremoveaction.h"
 #include "dolphinviewcontainer.h"
-#include "panels/places/placesitem.h"
-#include "panels/places/placesitemmodel.h"
 #include "trash/dolphintrash.h"
 #include "views/dolphinview.h"
 #include "views/viewmodecontroller.h"
index c03095c3c0c824b0ecb976e419789f44f4d5b857..644989be02f7995a2bb3c9bf9b80986ec13b9eeb 100644 (file)
 #include "dolphinnavigatorswidgetaction.h"
 #include "dolphinnewfilemenu.h"
 #include "dolphinrecenttabsmenu.h"
+#include "dolphinplacesmodelsingleton.h"
 #include "dolphinurlnavigatorscontroller.h"
 #include "dolphinviewcontainer.h"
 #include "dolphintabpage.h"
 #include "middleclickactioneventfilter.h"
 #include "panels/folders/folderspanel.h"
-#include "panels/places/placesitemmodel.h"
 #include "panels/places/placespanel.h"
 #include "panels/terminal/terminalpanel.h"
 #include "settings/dolphinsettingsdialog.h"
@@ -429,14 +429,13 @@ void DolphinMainWindow::addToPlaces()
         name = dirToAdd.name();
     }
     if (url.isValid()) {
-        PlacesItemModel model;
         QString icon;
         if (m_activeViewContainer->isSearchModeEnabled()) {
             icon = QStringLiteral("folder-saved-search-symbolic");
         } else {
             icon = KIO::iconNameForUrl(url);
         }
-        model.createPlacesItem(name, url, icon);
+        DolphinPlacesModelSingleton::instance().placesModel()->addPlace(name, url, icon);
     }
 }
 
@@ -1954,10 +1953,13 @@ void DolphinMainWindow::setupDockWidgets()
     addDockWidget(Qt::LeftDockWidgetArea, placesDock);
     connect(m_placesPanel, &PlacesPanel::placeActivated,
             this, &DolphinMainWindow::slotPlaceActivated);
-    connect(m_placesPanel, &PlacesPanel::placeActivatedInNewTab,
+    connect(m_placesPanel, &PlacesPanel::tabRequested,
             this, &DolphinMainWindow::openNewTab);
-    connect(m_placesPanel, &PlacesPanel::placeActivatedInNewActiveTab,
+    connect(m_placesPanel, &PlacesPanel::activeTabRequested,
             this, &DolphinMainWindow::openNewTabAndActivate);
+    connect(m_placesPanel, &PlacesPanel::newWindowRequested, this, [this](const QUrl &url) {
+        Dolphin::openNewWindow({url}, this);
+    });
     connect(m_placesPanel, &PlacesPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
     connect(this, &DolphinMainWindow::urlChanged,
@@ -1980,14 +1982,9 @@ void DolphinMainWindow::setupDockWidgets()
         "appear semi-transparent unless you uncheck their hide property."));
 
     connect(actionShowAllPlaces, &QAction::triggered, this, [actionShowAllPlaces, this](bool checked){
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
-        m_placesPanel->showHiddenEntries(checked);
+        m_placesPanel->setShowAll(checked);
     });
-
-    connect(m_placesPanel, &PlacesPanel::showHiddenEntriesChanged, this, [actionShowAllPlaces] (bool checked){
-        actionShowAllPlaces->setChecked(checked);
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
-   });
+    connect(m_placesPanel, &PlacesPanel::allPlacesShownChanged, actionShowAllPlaces, &QAction::setChecked);
 
     actionCollection()->action(QStringLiteral("show_places_panel"))
         ->setWhatsThis(xi18nc("@info:whatsthis", "<para>This toggles the "
@@ -2025,7 +2022,7 @@ void DolphinMainWindow::setupDockWidgets()
     panelsMenu->addAction(lockLayoutAction);
 
     connect(panelsMenu->menu(), &QMenu::aboutToShow, this, [actionShowAllPlaces, this]{
-        actionShowAllPlaces->setEnabled(m_placesPanel->hiddenListCount());
+        actionShowAllPlaces->setEnabled(DolphinPlacesModelSingleton::instance().placesModel()->hiddenCount());
     });
 }
 
index 30ec1b9b634283610b4e55a863dfc6180a6be7e9..754070c9298bc6f610f5119a8b3d5dfd1a7dd895 100644 (file)
@@ -5,12 +5,61 @@
  */
 
 #include "dolphinplacesmodelsingleton.h"
+#include "trash/dolphintrash.h"
 
 #include <KAboutData>
 #include <KFilePlacesModel>
 
+#include <QIcon>
+
+DolphinPlacesModel::DolphinPlacesModel(const QString &alternativeApplicationName, QObject *parent)
+    : KFilePlacesModel(alternativeApplicationName, parent)
+{
+    connect(&Trash::instance(), &Trash::emptinessChanged, this, &DolphinPlacesModel::slotTrashEmptinessChanged);
+}
+
+DolphinPlacesModel::~DolphinPlacesModel() = default;
+
+QVariant DolphinPlacesModel::data(const QModelIndex &index, int role) const
+{
+    if (role == Qt::DecorationRole) {
+        if (isTrash(index)) {
+            if (m_isEmpty) {
+                return QIcon::fromTheme(QStringLiteral("user-trash"));
+            } else {
+                return QIcon::fromTheme(QStringLiteral("user-trash-full"));
+            }
+        }
+    }
+
+    return KFilePlacesModel::data(index, role);
+}
+
+void DolphinPlacesModel::slotTrashEmptinessChanged(bool isEmpty)
+{
+    if (m_isEmpty == isEmpty) {
+        return;
+    }
+
+    // NOTE Trash::isEmpty() reads the config file whereas emptinessChanged is
+    // hooked up to whether a dirlister in trash:/ has any files and they disagree...
+    m_isEmpty = isEmpty;
+
+    for (int i = 0; i < rowCount(); ++i) {
+        const QModelIndex index = this->index(i, 0);
+        if (isTrash(index)) {
+            Q_EMIT dataChanged(index, index, {Qt::DecorationRole});
+        }
+    }
+}
+
+bool DolphinPlacesModel::isTrash(const QModelIndex &index) const
+{
+    return url(index) == QUrl(QStringLiteral("trash:/"));
+}
+
 DolphinPlacesModelSingleton::DolphinPlacesModelSingleton()
-    : m_placesModel(new KFilePlacesModel(KAboutData::applicationData().componentName() + applicationNameSuffix()))
+    : m_placesModel(new DolphinPlacesModel(KAboutData::applicationData().componentName() + applicationNameSuffix()))
 {
 
 }
index 645947aaa0c190cb189cd75dbb5e67a0c69dd46b..7efe6e093cc6ff08e7bb8cd31b6cd1b45d172a44 100644 (file)
 #include <QString>
 #include <QScopedPointer>
 
-class KFilePlacesModel;
+#include <KFilePlacesModel>
+
+/**
+ * @brief Dolphin's special-cased KFilePlacesModel
+ *
+ * It returns the trash's icon based on whether
+ * it is full or not.
+ */
+class DolphinPlacesModel : public KFilePlacesModel
+{
+    Q_OBJECT
+
+public:
+    explicit DolphinPlacesModel(const QString &alternativeApplicationName, QObject *parent = nullptr);
+    ~DolphinPlacesModel() override;
+
+protected:
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+private Q_SLOTS:
+    void slotTrashEmptinessChanged(bool isEmpty);
+
+private:
+    bool isTrash(const QModelIndex &index) const;
+
+    bool m_isEmpty = false;
+};
 
 /**
  * @brief Provides a global KFilePlacesModel instance.
index db0ac9495b2fe17e5d17220d3ab18ebbc2290e66..58f77a959716a86ab36bc61494afb63819b7b74a 100644 (file)
@@ -8,7 +8,7 @@
     <kcfgfile name="dolphinrc"/>
     <group name="PlacesPanel">
         <entry name="IconSize" type="Int">
-            <label>Size of icons in the Places Panel (-1 means "use the style's small size")</label>
+            <label>Size of icons in the Places Panel (-1 means "automatic")</label>
             <default code="true">KIconLoader::SizeSmallMedium</default>
         </entry>
     </group>
diff --git a/src/panels/places/placesitem.cpp b/src/panels/places/placesitem.cpp
deleted file mode 100644 (file)
index 18f3f00..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- * SPDX-FileCopyrightText: 2018 Elvis Angelaccio <elvis.angelaccio@kde.org>
- *
- * Based on KFilePlacesItem from kdelibs:
- * SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesitem.h"
-#include "trash/dolphintrash.h"
-
-#include "dolphindebug.h"
-#include "placesitemsignalhandler.h"
-
-#include <KDirLister>
-#include <KLocalizedString>
-#include <Solid/Block>
-
-PlacesItem::PlacesItem(const KBookmark& bookmark, PlacesItem* parent) :
-    KStandardItem(parent),
-    m_device(),
-    m_access(),
-    m_volume(),
-    m_disc(),
-    m_player(),
-    m_signalHandler(nullptr),
-    m_bookmark()
-{
-    m_signalHandler = new PlacesItemSignalHandler(this);
-    setBookmark(bookmark);
-}
-
-PlacesItem::~PlacesItem()
-{
-    delete m_signalHandler;
-}
-
-void PlacesItem::setUrl(const QUrl &url)
-{
-    // The default check in KStandardItem::setDataValue()
-    // for equal values does not work with a custom value
-    // like QUrl. Hence do a manual check to prevent that
-    // setting an equal URL results in an itemsChanged()
-    // signal.
-    if (dataValue("url").toUrl() != url) {
-        if (url.scheme() == QLatin1String("trash")) {
-            QObject::connect(&Trash::instance(), &Trash::emptinessChanged, m_signalHandler.data(), &PlacesItemSignalHandler::onTrashEmptinessChanged);
-        }
-
-        setDataValue("url", url);
-    }
-}
-
-QUrl PlacesItem::url() const
-{
-    return dataValue("url").toUrl();
-}
-
-void PlacesItem::setUdi(const QString& udi)
-{
-    setDataValue("udi", udi);
-}
-
-QString PlacesItem::udi() const
-{
-    return dataValue("udi").toString();
-}
-
-void PlacesItem::setApplicationName(const QString &applicationName)
-{
-    setDataValue("applicationName", applicationName);
-}
-
-QString PlacesItem::applicationName() const
-{
-    return dataValue("applicationName").toString();
-}
-
-void PlacesItem::setHidden(bool hidden)
-{
-    setDataValue("isHidden", hidden);
-}
-
-bool PlacesItem::isHidden() const
-{
-    return dataValue("isHidden").toBool();
-}
-
-bool PlacesItem::isGroupHidden() const
-{
-    return dataValue("isGroupHidden").toBool();
-}
-
-void PlacesItem::setGroupHidden(bool hidden)
-{
-    setDataValue("isGroupHidden", hidden);
-}
-
-void PlacesItem::setSystemItem(bool isSystemItem)
-{
-    setDataValue("isSystemItem", isSystemItem);
-}
-
-bool PlacesItem::isSystemItem() const
-{
-    return dataValue("isSystemItem").toBool();
-}
-
-Solid::Device PlacesItem::device() const
-{
-    return m_device;
-}
-
-void PlacesItem::setBookmark(const KBookmark& bookmark)
-{
-    const bool bookmarkDataChanged = !(bookmark == m_bookmark);
-
-    // bookmark object must be updated to keep in sync with source model
-    m_bookmark = bookmark;
-
-    if (!bookmarkDataChanged) {
-        return;
-    }
-
-    delete m_access;
-    delete m_volume;
-    delete m_disc;
-    delete m_player;
-
-    const QString udi = bookmark.metaDataItem(QStringLiteral("UDI"));
-    if (udi.isEmpty()) {
-        setIcon(bookmark.icon());
-        setText(i18ndc("kio5", "KFile System Bookmarks", bookmark.text().toUtf8().constData()));
-        setUrl(bookmark.url());
-        setSystemItem(bookmark.metaDataItem(QStringLiteral("isSystemItem")) == QLatin1String("true"));
-    } else {
-        initializeDevice(udi);
-    }
-
-    setHidden(bookmark.metaDataItem(QStringLiteral("IsHidden")) == QLatin1String("true"));
-}
-
-KBookmark PlacesItem::bookmark() const
-{
-    return m_bookmark;
-}
-
-bool PlacesItem::storageSetupNeeded() const
-{
-    return m_access ? !m_access->isAccessible() : false;
-}
-
-bool PlacesItem::isSearchOrTimelineUrl() const
-{
-    const QString urlScheme = url().scheme();
-    return (urlScheme.contains("search") || urlScheme.contains("timeline"));
-}
-
-void PlacesItem::onDataValueChanged(const QByteArray& role,
-                                    const QVariant& current,
-                                    const QVariant& previous)
-{
-    Q_UNUSED(current)
-    Q_UNUSED(previous)
-
-    if (!m_bookmark.isNull()) {
-        updateBookmarkForRole(role);
-    }
-}
-
-void PlacesItem::onDataChanged(const QHash<QByteArray, QVariant>& current,
-                               const QHash<QByteArray, QVariant>& previous)
-{
-    Q_UNUSED(previous)
-
-    if (!m_bookmark.isNull()) {
-        QHashIterator<QByteArray, QVariant> it(current);
-        while (it.hasNext()) {
-            it.next();
-            updateBookmarkForRole(it.key());
-        }
-    }
-}
-
-void PlacesItem::initializeDevice(const QString& udi)
-{
-    m_device = Solid::Device(udi);
-    if (!m_device.isValid()) {
-        return;
-    }
-
-    m_access = m_device.as<Solid::StorageAccess>();
-    m_volume = m_device.as<Solid::StorageVolume>();
-    m_disc = m_device.as<Solid::OpticalDisc>();
-    m_player = m_device.as<Solid::PortableMediaPlayer>();
-
-    setText(m_device.displayName());
-    setIcon(m_device.icon());
-    setIconOverlays(m_device.emblems());
-    setUdi(udi);
-
-    if (m_access) {
-        setUrl(QUrl::fromLocalFile(m_access->filePath()));
-        QObject::connect(m_access.data(), &Solid::StorageAccess::accessibilityChanged,
-                         m_signalHandler.data(), &PlacesItemSignalHandler::onAccessibilityChanged);
-        QObject::connect(m_access.data(), &Solid::StorageAccess::teardownRequested,
-                         m_signalHandler.data(), &PlacesItemSignalHandler::onTearDownRequested);
-    } else if (m_disc && (m_disc->availableContent() & Solid::OpticalDisc::Audio) != 0) {
-        Solid::Block *block = m_device.as<Solid::Block>();
-        if (block) {
-            const QString device = block->device();
-            setUrl(QUrl(QStringLiteral("audiocd:/?device=%1").arg(device)));
-        } else {
-            setUrl(QUrl(QStringLiteral("audiocd:/")));
-        }
-    } else if (m_player) {
-        const QStringList protocols = m_player->supportedProtocols();
-        if (!protocols.isEmpty()) {
-            setUrl(QUrl(QStringLiteral("%1:udi=%2").arg(protocols.first(), m_device.udi())));
-        }
-    }
-}
-
-void PlacesItem::onAccessibilityChanged()
-{
-    setIconOverlays(m_device.emblems());
-    setUrl(QUrl::fromLocalFile(m_access->filePath()));
-}
-
-void PlacesItem::updateBookmarkForRole(const QByteArray& role)
-{
-    Q_ASSERT(!m_bookmark.isNull());
-    if (role == "iconName") {
-        m_bookmark.setIcon(icon());
-    } else if (role == "text") {
-        // Only store the text in the KBookmark if it is not the translation of
-        // the current text. This makes sure that the text is re-translated if
-        // the user chooses another language, or the translation itself changes.
-        //
-        // NOTE: It is important to use "KFile System Bookmarks" as context
-        // (see PlacesItemModel::createSystemBookmarks()).
-        if (text() != i18ndc("kio5", "KFile System Bookmarks", m_bookmark.text().toUtf8().data())) {
-            m_bookmark.setFullText(text());
-        }
-    } else if (role == "url") {
-        m_bookmark.setUrl(url());
-    } else if (role == "udi") {
-        m_bookmark.setMetaDataItem(QStringLiteral("UDI"), udi());
-    } else if (role == "applicationName") {
-        m_bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), applicationName());
-    } else if (role == "isSystemItem") {
-        m_bookmark.setMetaDataItem(QStringLiteral("isSystemItem"), isSystemItem() ? QStringLiteral("true") : QStringLiteral("false"));
-    } else if (role == "isHidden") {
-        m_bookmark.setMetaDataItem(QStringLiteral("IsHidden"), isHidden() ? QStringLiteral("true") : QStringLiteral("false"));
-    }
-}
-
-QString PlacesItem::generateNewId()
-{
-    // The ID-generation must be different as done in KFilePlacesItem from kdelibs
-    // to prevent identical IDs, because 'count' is of course not shared. We append a
-    // " (V2)" to indicate that the ID has been generated by
-    // a new version of the places view.
-    static int count = 0;
-    return QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch()) +
-            '/' + QString::number(count++) + " (V2)";
-}
-
-PlacesItemSignalHandler *PlacesItem::signalHandler() const
-{
-    return m_signalHandler.data();
-}
diff --git a/src/panels/places/placesitem.h b/src/panels/places/placesitem.h
deleted file mode 100644 (file)
index 8325923..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESITEM_H
-#define PLACESITEM_H
-
-#include "kitemviews/kstandarditem.h"
-
-#include <KBookmark>
-#include <Solid/Device>
-#include <Solid/OpticalDisc>
-#include <Solid/PortableMediaPlayer>
-#include <Solid/StorageAccess>
-#include <Solid/StorageVolume>
-
-#include <QPointer>
-#include <QUrl>
-
-
-class KDirLister;
-class PlacesItemSignalHandler;
-
-/**
- * @brief Extends KStandardItem by places-specific properties.
- */
-class PlacesItem : public KStandardItem
-{
-
-public:
-    explicit PlacesItem(const KBookmark& bookmark, PlacesItem* parent = nullptr);
-    ~PlacesItem() override;
-
-    void setUrl(const QUrl& url);
-    QUrl url() const;
-
-    void setUdi(const QString& udi);
-    QString udi() const;
-
-    void setApplicationName(const QString& applicationName);
-    QString applicationName() const;
-
-    void setHidden(bool hidden);
-    bool isHidden() const;
-
-    void setGroupHidden(bool hidden);
-    bool isGroupHidden() const;
-
-    void setSystemItem(bool isSystemItem);
-    bool isSystemItem() const;
-
-    Solid::Device device() const;
-
-    void setBookmark(const KBookmark& bookmark);
-    KBookmark bookmark() const;
-
-    bool storageSetupNeeded() const;
-
-    bool isSearchOrTimelineUrl() const;
-
-    PlacesItemSignalHandler* signalHandler() const;
-
-protected:
-    void onDataValueChanged(const QByteArray& role,
-                                    const QVariant& current,
-                                    const QVariant& previous) override;
-
-    void onDataChanged(const QHash<QByteArray, QVariant>& current,
-                               const QHash<QByteArray, QVariant>& previous) override;
-
-private:
-    PlacesItem(const PlacesItem& item);
-
-    void initializeDevice(const QString& udi);
-
-    /**
-     * Is invoked if the accessibility of the storage access
-     * m_access has been changed and updates the emblem.
-     */
-    void onAccessibilityChanged();
-
-    /**
-     * Applies the data-value from the role to m_bookmark.
-     */
-    void updateBookmarkForRole(const QByteArray& role);
-
-    static QString generateNewId();
-
-private:
-    Solid::Device m_device;
-    QPointer<Solid::StorageAccess> m_access;
-    QPointer<Solid::StorageVolume> m_volume;
-    QPointer<Solid::OpticalDisc> m_disc;
-    QPointer<Solid::PortableMediaPlayer> m_player;
-    QPointer<PlacesItemSignalHandler> m_signalHandler;
-    KBookmark m_bookmark;
-
-    friend class PlacesItemSignalHandler; // Calls onAccessibilityChanged()
-};
-
-#endif
-
-
diff --git a/src/panels/places/placesitemlistgroupheader.cpp b/src/panels/places/placesitemlistgroupheader.cpp
deleted file mode 100644 (file)
index 76fd670..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * Based on the Itemviews NG project from Trolltech Labs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesitemlistgroupheader.h"
-
-PlacesItemListGroupHeader::PlacesItemListGroupHeader(QGraphicsWidget* parent) :
-    KStandardItemListGroupHeader(parent)
-{
-}
-
-PlacesItemListGroupHeader::~PlacesItemListGroupHeader()
-{
-}
-
-void PlacesItemListGroupHeader::paintSeparator(QPainter* painter, const QColor& color)
-{
-    Q_UNUSED(painter)
-    Q_UNUSED(color)
-}
-
-QPalette::ColorRole PlacesItemListGroupHeader::normalTextColorRole() const
-{
-    return QPalette::WindowText;
-}
-
diff --git a/src/panels/places/placesitemlistgroupheader.h b/src/panels/places/placesitemlistgroupheader.h
deleted file mode 100644 (file)
index dfb91f8..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESITEMLISTGROUPHEADER_H
-#define PLACESITEMLISTGROUPHEADER_H
-
-#include "kitemviews/kstandarditemlistgroupheader.h"
-
-class PlacesItemListGroupHeader : public KStandardItemListGroupHeader
-{
-    Q_OBJECT
-
-public:
-    explicit PlacesItemListGroupHeader(QGraphicsWidget* parent = nullptr);
-    ~PlacesItemListGroupHeader() override;
-
-protected:
-    void paintSeparator(QPainter* painter, const QColor& color) override;
-
-    QPalette::ColorRole normalTextColorRole() const override;
-};
-#endif
-
-
diff --git a/src/panels/places/placesitemlistwidget.cpp b/src/panels/places/placesitemlistwidget.cpp
deleted file mode 100644 (file)
index ba7a0c4..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesitemlistwidget.h"
-
-#include <QStyleOption>
-
-#include <KColorScheme>
-
-#include <Solid/Device>
-#include <Solid/NetworkShare>
-
-#define CAPACITYBAR_HEIGHT 2
-#define CAPACITYBAR_MARGIN 2
-#define CAPACITYBAR_CACHE_TTL 60000
-
-
-PlacesItemListWidget::PlacesItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
-    KStandardItemListWidget(informant, parent)
-    , m_drawCapacityBar(false)
-{
-}
-
-PlacesItemListWidget::~PlacesItemListWidget()
-{
-}
-
-bool PlacesItemListWidget::isHidden() const
-{
-    return data().value("isHidden").toBool() ||
-           data().value("isGroupHidden").toBool();
-}
-
-QPalette::ColorRole PlacesItemListWidget::normalTextColorRole() const
-{
-    return QPalette::WindowText;
-}
-
-void PlacesItemListWidget::updateCapacityBar()
-{
-    const QString udi = data().value("udi").toString();
-    if (udi.isEmpty()) {
-        resetCapacityBar();
-        return;
-    }
-    const Solid::Device device = Solid::Device(udi);
-    if (device.isDeviceInterface(Solid::DeviceInterface::NetworkShare)
-            || device.isDeviceInterface(Solid::DeviceInterface::OpticalDrive)
-            || device.isDeviceInterface(Solid::DeviceInterface::OpticalDisc)) {
-        resetCapacityBar();
-        return;
-    }
-    const QUrl url = data().value("url").toUrl();
-
-    if (url.isEmpty() || m_freeSpaceInfo.job || !m_freeSpaceInfo.lastUpdated.hasExpired()) {
-        // No url, job running or cache is still valid.
-        return;
-    }
-
-    m_freeSpaceInfo.job = KIO::fileSystemFreeSpace(url);
-    connect(
-        m_freeSpaceInfo.job,
-        &KIO::FileSystemFreeSpaceJob::result,
-        this,
-        [this](KIO::Job *job, KIO::filesize_t size, KIO::filesize_t available) {
-            // even if we receive an error we want to refresh lastUpdated to avoid repeatedly querying in this case
-            m_freeSpaceInfo.lastUpdated.setRemainingTime(CAPACITYBAR_CACHE_TTL);
-
-            if (job->error()) {
-                return;
-            }
-
-            m_freeSpaceInfo.size = size;
-            m_freeSpaceInfo.used = size - available;
-            m_freeSpaceInfo.usedRatio = (qreal)m_freeSpaceInfo.used / (qreal)m_freeSpaceInfo.size;
-            m_drawCapacityBar = size > 0;
-
-            update();
-        }
-    );
-}
-
-void PlacesItemListWidget::resetCapacityBar()
-{
-    m_drawCapacityBar = false;
-    delete m_freeSpaceInfo.job;
-    m_freeSpaceInfo.lastUpdated.setRemainingTime(0);
-    m_freeSpaceInfo.size = 0;
-    m_freeSpaceInfo.used = 0;
-    m_freeSpaceInfo.usedRatio = 0;
-}
-
-void PlacesItemListWidget::polishEvent()
-{
-    updateCapacityBar();
-
-    QGraphicsWidget::polishEvent();
-}
-
-void PlacesItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
-{
-    KStandardItemListWidget::paint(painter, option, widget);
-
-    // We check if option=nullptr since it is null when the place is dragged (Bug #430441)
-    if (m_drawCapacityBar && option) {
-        const TextInfo* textInfo = m_textInfo.value("text");
-        if (textInfo) { // See KStandarItemListWidget::paint() for info on why we check textInfo.
-            painter->save();
-
-            const QRect capacityRect(
-                textInfo->pos.x(),
-                option->rect.top() + option->rect.height() - CAPACITYBAR_HEIGHT - CAPACITYBAR_MARGIN,
-                qMin((qreal)option->rect.width(), selectionRect().width()) - (textInfo->pos.x() - option->rect.left()),
-                CAPACITYBAR_HEIGHT
-            );
-
-            const QPalette pal = palette();
-            const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
-
-            // Background
-            const QColor bgColor = isSelected()
-                ? pal.color(group, QPalette::Highlight).darker(180)
-                : pal.color(group, QPalette::Window).darker(120);
-
-            painter->fillRect(capacityRect, bgColor);
-
-            // Fill
-            const QRect fillRect(capacityRect.x(), capacityRect.y(), capacityRect.width() * m_freeSpaceInfo.usedRatio, capacityRect.height());
-            if (m_freeSpaceInfo.usedRatio >= 0.95) { // More than 95% full!
-                const QColor dangerUsedColor = KColorScheme(group, KColorScheme::View).foreground(KColorScheme::NegativeText).color();
-                painter->fillRect(fillRect, dangerUsedColor);
-            } else {
-                const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : QPalette::Highlight;
-                const QColor normalUsedColor = styleOption().palette.color(group, role);
-                painter->fillRect(fillRect, normalUsedColor);
-            }
-
-            painter->restore();
-        }
-    }
-
-    updateCapacityBar();
-}
diff --git a/src/panels/places/placesitemlistwidget.h b/src/panels/places/placesitemlistwidget.h
deleted file mode 100644 (file)
index 9c8272f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESITEMLISTWIDGET_H
-#define PLACESITEMLISTWIDGET_H
-
-#include "kitemviews/kstandarditemlistwidget.h"
-
-#include <QDeadlineTimer>
-#include <QPainter>
-#include <QPointer>
-#include <QStyleOptionGraphicsItem>
-#include <QWidget>
-
-#include <KIO/FileSystemFreeSpaceJob>
-
-
-// The free space / capacity bar is based on KFilePlacesView.
-// https://invent.kde.org/frameworks/kio/-/commit/933887dc334f3498505af7a86d25db7faae91019
-struct PlaceFreeSpaceInfo
-{
-    QDeadlineTimer lastUpdated;
-    KIO::filesize_t used = 0;
-    KIO::filesize_t size = 0;
-    qreal usedRatio = 0;
-    QPointer<KIO::FileSystemFreeSpaceJob> job;
-};
-
-
-/**
- * @brief Extends KStandardItemListWidget to interpret the hidden
- *        property of the PlacesModel and use the right text color.
-*/
-class PlacesItemListWidget : public KStandardItemListWidget
-{
-    Q_OBJECT
-
-public:
-    PlacesItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent);
-    ~PlacesItemListWidget() override;
-
-    void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
-    void polishEvent() override;
-
-protected:
-    bool isHidden() const override;
-    QPalette::ColorRole normalTextColorRole() const override;
-    void updateCapacityBar();
-    void resetCapacityBar();
-
-private:
-    bool m_drawCapacityBar;
-    PlaceFreeSpaceInfo m_freeSpaceInfo;
-};
-
-#endif
-
-
diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp
deleted file mode 100644 (file)
index 3da6f7e..0000000
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * Based on KFilePlacesModel from kdelibs:
- * SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
- * SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesitemmodel.h"
-
-#include "dolphin_generalsettings.h"
-#include "dolphindebug.h"
-#include "dolphinplacesmodelsingleton.h"
-#include "placesitem.h"
-#include "placesitemsignalhandler.h"
-#include "views/dolphinview.h"
-#include "views/viewproperties.h"
-
-#include <KAboutData>
-#include <KLocalizedString>
-#include <KUrlMimeData>
-#include <Solid/DeviceNotifier>
-#include <Solid/OpticalDrive>
-#include <KCoreAddons/KProcessList>
-#include <KCoreAddons/KListOpenFilesJob>
-
-#include <QAction>
-#include <QIcon>
-#include <QMimeData>
-#include <QTimer>
-
-PlacesItemModel::PlacesItemModel(QObject* parent) :
-    KStandardItemModel(parent),
-    m_hiddenItemsShown(false),
-    m_deviceToTearDown(nullptr),
-    m_storageSetupInProgress(),
-    m_sourceModel(DolphinPlacesModelSingleton::instance().placesModel())
-{
-    cleanupBookmarks();
-    loadBookmarks();
-    initializeDefaultViewProperties();
-
-    connect(m_sourceModel, &KFilePlacesModel::rowsInserted, this, &PlacesItemModel::onSourceModelRowsInserted);
-    connect(m_sourceModel, &KFilePlacesModel::rowsAboutToBeRemoved, this, &PlacesItemModel::onSourceModelRowsAboutToBeRemoved);
-    connect(m_sourceModel, &KFilePlacesModel::dataChanged, this, &PlacesItemModel::onSourceModelDataChanged);
-    connect(m_sourceModel, &KFilePlacesModel::rowsAboutToBeMoved, this, &PlacesItemModel::onSourceModelRowsAboutToBeMoved);
-    connect(m_sourceModel, &KFilePlacesModel::rowsMoved, this, &PlacesItemModel::onSourceModelRowsMoved);
-    connect(m_sourceModel, &KFilePlacesModel::groupHiddenChanged, this, &PlacesItemModel::onSourceModelGroupHiddenChanged);
-}
-
-PlacesItemModel::~PlacesItemModel()
-{
-}
-
-void PlacesItemModel::createPlacesItem(const QString &text, const QUrl &url, const QString &iconName, const QString &appName)
-{
-    createPlacesItem(text, url, iconName, appName, -1);
-}
-
-void PlacesItemModel::createPlacesItem(const QString &text, const QUrl &url, const QString &iconName, const QString &appName, int after)
-{
-    m_sourceModel->addPlace(text, url, iconName, appName, mapToSource(after));
-}
-
-PlacesItem* PlacesItemModel::placesItem(int index) const
-{
-    return dynamic_cast<PlacesItem*>(item(index));
-}
-
-int PlacesItemModel::hiddenCount() const
-{
-    return m_sourceModel->hiddenCount();
-}
-
-void PlacesItemModel::setHiddenItemsShown(bool show)
-{
-    if (m_hiddenItemsShown == show) {
-        return;
-    }
-
-    m_hiddenItemsShown = show;
-
-    if (show) {
-        for (int r = 0, rMax = m_sourceModel->rowCount(); r < rMax; r++) {
-            const QModelIndex index = m_sourceModel->index(r, 0);
-            if (!m_sourceModel->isHidden(index)) {
-                continue;
-            }
-            addItemFromSourceModel(index);
-        }
-    } else {
-        for (int r = 0, rMax = m_sourceModel->rowCount(); r < rMax; r++) {
-            const QModelIndex index = m_sourceModel->index(r, 0);
-            if (m_sourceModel->isHidden(index)) {
-                removeItemByIndex(index);
-            }
-        }
-    }
-}
-
-bool PlacesItemModel::hiddenItemsShown() const
-{
-    return m_hiddenItemsShown;
-}
-
-int PlacesItemModel::closestItem(const QUrl& url) const
-{
-    return mapFromSource(m_sourceModel->closestItem(url));
-}
-
-// look for the correct position for the item based on source model
-void PlacesItemModel::insertSortedItem(PlacesItem* item)
-{
-    if (!item) {
-        return;
-    }
-
-    const KBookmark iBookmark = item->bookmark();
-    const QString iBookmarkId = bookmarkId(iBookmark);
-    QModelIndex sourceIndex;
-    int pos = 0;
-
-    for(int r = 0, rMax = m_sourceModel->rowCount(); r < rMax; r++) {
-        sourceIndex = m_sourceModel->index(r, 0);
-        const KBookmark sourceBookmark = m_sourceModel->bookmarkForIndex(sourceIndex);
-
-        if (bookmarkId(sourceBookmark) == iBookmarkId) {
-            break;
-        }
-
-        if (m_hiddenItemsShown || !m_sourceModel->isHidden(sourceIndex)) {
-            pos++;
-        }
-    }
-
-    m_indexMap.insert(pos, sourceIndex);
-    insertItem(pos, item);
-}
-
-void PlacesItemModel::onItemInserted(int index)
-{
-    KStandardItemModel::onItemInserted(index);
-}
-
-void PlacesItemModel::onItemRemoved(int index, KStandardItem* removedItem)
-{
-    m_indexMap.removeAt(index);
-
-    KStandardItemModel::onItemRemoved(index, removedItem);
-}
-
-void PlacesItemModel::onItemChanged(int index, const QSet<QByteArray>& changedRoles)
-{
-    const QModelIndex sourceIndex = mapToSource(index);
-    const PlacesItem *changedItem = placesItem(mapFromSource(sourceIndex));
-
-    if (!changedItem || !sourceIndex.isValid()) {
-        qWarning() << "invalid item changed signal";
-        return;
-    }
-    if (changedRoles.contains("isHidden")) {
-        if (m_sourceModel->isHidden(sourceIndex) != changedItem->isHidden()) {
-            m_sourceModel->setPlaceHidden(sourceIndex, changedItem->isHidden());
-        } else {
-            m_sourceModel->refresh();
-        }
-    }
-    KStandardItemModel::onItemChanged(index, changedRoles);
-}
-
-QAction* PlacesItemModel::ejectAction(int index) const
-{
-    const PlacesItem* item = placesItem(index);
-    if (item && item->device().is<Solid::OpticalDisc>()) {
-        return new QAction(QIcon::fromTheme(QStringLiteral("media-eject")), i18nc("@item", "Eject"), nullptr);
-    }
-
-    return nullptr;
-}
-
-QAction* PlacesItemModel::teardownAction(int index) const
-{
-    const PlacesItem* item = placesItem(index);
-    if (!item) {
-        return nullptr;
-    }
-
-    Solid::Device device = item->device();
-    const bool providesTearDown = device.is<Solid::StorageAccess>() &&
-                                  device.as<Solid::StorageAccess>()->isAccessible();
-    if (!providesTearDown) {
-        return nullptr;
-    }
-
-    Solid::StorageDrive* drive = device.as<Solid::StorageDrive>();
-    if (!drive) {
-        drive = device.parent().as<Solid::StorageDrive>();
-    }
-
-    bool hotPluggable = false;
-    bool removable = false;
-    if (drive) {
-        hotPluggable = drive->isHotpluggable();
-        removable = drive->isRemovable();
-    }
-
-    QString iconName;
-    QString text;
-    if (device.is<Solid::OpticalDisc>()) {
-        text = i18nc("@item", "Release");
-    } else if (removable || hotPluggable) {
-        text = i18nc("@item", "Safely Remove");
-        iconName = QStringLiteral("media-eject");
-    } else {
-        text = i18nc("@item", "Unmount");
-        iconName = QStringLiteral("media-eject");
-    }
-
-    if (iconName.isEmpty()) {
-        return new QAction(text, nullptr);
-    }
-
-    return new QAction(QIcon::fromTheme(iconName), text, nullptr);
-}
-
-void PlacesItemModel::requestEject(int index)
-{
-    const PlacesItem* item = placesItem(index);
-    if (item) {
-        Solid::OpticalDrive* drive = item->device().parent().as<Solid::OpticalDrive>();
-        if (drive) {
-            connect(drive, &Solid::OpticalDrive::ejectDone,
-                    this, &PlacesItemModel::slotStorageTearDownDone);
-            drive->eject();
-        } else {
-            const QString label = item->text();
-            const QString message = i18nc("@info", "The device '%1' is not a disk and cannot be ejected.", label);
-            Q_EMIT errorMessage(message);
-        }
-    }
-}
-
-void PlacesItemModel::requestTearDown(int index)
-{
-    const PlacesItem* item = placesItem(index);
-    if (item) {
-        Solid::StorageAccess *tmp = item->device().as<Solid::StorageAccess>();
-        if (tmp) {
-            m_deviceToTearDown = tmp;
-            // disconnect the Solid::StorageAccess::teardownRequested
-            // to prevent emitting PlacesItemModel::storageTearDownExternallyRequested
-            // after we have emitted PlacesItemModel::storageTearDownRequested
-            disconnect(tmp, &Solid::StorageAccess::teardownRequested,
-                       item->signalHandler(), &PlacesItemSignalHandler::onTearDownRequested);
-            Q_EMIT storageTearDownRequested(tmp->filePath());
-        }
-    }
-}
-
-bool PlacesItemModel::storageSetupNeeded(int index) const
-{
-    const PlacesItem* item = placesItem(index);
-    return item ? item->storageSetupNeeded() : false;
-}
-
-void PlacesItemModel::requestStorageSetup(int index)
-{
-    const PlacesItem* item = placesItem(index);
-    if (!item) {
-        return;
-    }
-
-    Solid::Device device = item->device();
-    const bool setup = device.is<Solid::StorageAccess>()
-                       && !m_storageSetupInProgress.contains(device.as<Solid::StorageAccess>())
-                       && !device.as<Solid::StorageAccess>()->isAccessible();
-    if (setup) {
-        Solid::StorageAccess* access = device.as<Solid::StorageAccess>();
-
-        m_storageSetupInProgress[access] = index;
-
-        connect(access, &Solid::StorageAccess::setupDone,
-                this, &PlacesItemModel::slotStorageSetupDone);
-
-        access->setup();
-    }
-}
-
-QMimeData* PlacesItemModel::createMimeData(const KItemSet& indexes) const
-{
-    QList<QUrl> urls;
-    QByteArray itemData;
-
-    QDataStream stream(&itemData, QIODevice::WriteOnly);
-
-    for (int index : indexes) {
-        const QUrl itemUrl = placesItem(index)->url();
-        if (itemUrl.isValid()) {
-            urls << itemUrl;
-        }
-        stream << index;
-    }
-
-    QMimeData* mimeData = new QMimeData();
-    if (!urls.isEmpty()) {
-        mimeData->setUrls(urls);
-    } else {
-        // #378954: prevent itemDropEvent() drops if there isn't a source url.
-        mimeData->setData(blacklistItemDropEventMimeType(), QByteArrayLiteral("true"));
-    }
-    mimeData->setData(internalMimeType(), itemData);
-
-    return mimeData;
-}
-
-bool PlacesItemModel::supportsDropping(int index) const
-{
-    return index >= 0 && index < count();
-}
-
-void PlacesItemModel::dropMimeDataBefore(int index, const QMimeData* mimeData)
-{
-    if (mimeData->hasFormat(internalMimeType())) {
-        // The item has been moved inside the view
-        QByteArray itemData = mimeData->data(internalMimeType());
-        QDataStream stream(&itemData, QIODevice::ReadOnly);
-        int oldIndex;
-        stream >> oldIndex;
-
-        QModelIndex sourceIndex = mapToSource(index);
-        QModelIndex oldSourceIndex = mapToSource(oldIndex);
-
-        m_sourceModel->movePlace(oldSourceIndex.row(), sourceIndex.row());
-    } else if (mimeData->hasFormat(QStringLiteral("text/uri-list"))) {
-        // One or more items must be added to the model
-        const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
-        for (int i = urls.count() - 1; i >= 0; --i) {
-            const QUrl& url = urls[i];
-
-            QString text = url.fileName();
-            if (text.isEmpty()) {
-                text = url.host();
-            }
-
-            if ((url.isLocalFile() && !QFileInfo(url.toLocalFile()).isDir())
-                    || url.scheme() == QLatin1String("trash")) {
-                // Only directories outside the trash are allowed
-                continue;
-            }
-
-            createPlacesItem(text, url, KIO::iconNameForUrl(url), {}, qMax(0, index - 1));
-        }
-    }
-    // will save bookmark alteration and fix sort if that is broken by the drag/drop operation
-    refresh();
-}
-
-void PlacesItemModel::addItemFromSourceModel(const QModelIndex &index)
-{
-    if (!m_hiddenItemsShown && m_sourceModel->isHidden(index)) {
-        return;
-    }
-
-    const KBookmark bookmark = m_sourceModel->bookmarkForIndex(index);
-    Q_ASSERT(!bookmark.isNull());
-    PlacesItem *item = new PlacesItem(bookmark);
-    updateItem(item, index);
-    insertSortedItem(item);
-
-    if (m_sourceModel->isDevice(index)) {
-        connect(item->signalHandler(), &PlacesItemSignalHandler::tearDownExternallyRequested,
-                this, &PlacesItemModel::storageTearDownExternallyRequested);
-    }
-}
-
-void PlacesItemModel::removeItemByIndex(const QModelIndex &sourceIndex)
-{
-    QString id = bookmarkId(m_sourceModel->bookmarkForIndex(sourceIndex));
-
-    for (int i = 0, iMax = count(); i < iMax; ++i) {
-        if (bookmarkId(placesItem(i)->bookmark()) == id) {
-            removeItem(i);
-            return;
-        }
-    }
-}
-
-QString PlacesItemModel::bookmarkId(const KBookmark &bookmark) const
-{
-    QString id = bookmark.metaDataItem(QStringLiteral("UDI"));
-    if (id.isEmpty()) {
-        id = bookmark.metaDataItem(QStringLiteral("ID"));
-    }
-    return id;
-}
-
-void PlacesItemModel::initializeDefaultViewProperties() const
-{
-    for(int i = 0, iMax = m_sourceModel->rowCount(); i < iMax; i++) {
-        const QModelIndex index = m_sourceModel->index(i, 0);
-        const PlacesItem *item = placesItem(mapFromSource(index));
-        if (!item) {
-            continue;
-        }
-
-        // Create default view-properties for all "Search For" and "Recently Saved" bookmarks
-        // in case the user has not already created custom view-properties for a corresponding
-        // query yet.
-        const bool createDefaultViewProperties = item->isSearchOrTimelineUrl() && !GeneralSettings::self()->globalViewProps();
-        if (createDefaultViewProperties) {
-            const QUrl itemUrl = item->url();
-            ViewProperties props(KFilePlacesModel::convertedUrl(itemUrl));
-            if (!props.exist()) {
-                const QString path = itemUrl.path();
-                if (path == QLatin1String("/documents")) {
-                    props.setViewMode(DolphinView::DetailsView);
-                    props.setPreviewsShown(false);
-                    props.setVisibleRoles({"text", "path"});
-                } else if (path == QLatin1String("/images")) {
-                    props.setViewMode(DolphinView::IconsView);
-                    props.setPreviewsShown(true);
-                    props.setVisibleRoles({"text", "height", "width"});
-                } else if (path == QLatin1String("/audio")) {
-                    props.setViewMode(DolphinView::DetailsView);
-                    props.setPreviewsShown(false);
-                    props.setVisibleRoles({"text", "artist", "album"});
-                } else if (path == QLatin1String("/videos")) {
-                    props.setViewMode(DolphinView::IconsView);
-                    props.setPreviewsShown(true);
-                    props.setVisibleRoles({"text"});
-                } else if (itemUrl.scheme() == QLatin1String("timeline")) {
-                    props.setViewMode(DolphinView::DetailsView);
-                    props.setVisibleRoles({"text", "modificationtime"});
-                }
-                props.save();
-            }
-        }
-    }
-}
-
-void PlacesItemModel::updateItem(PlacesItem *item, const QModelIndex &index)
-{
-    item->setGroup(index.data(KFilePlacesModel::GroupRole).toString());
-    item->setIcon(index.data(KFilePlacesModel::IconNameRole).toString());
-    item->setGroupHidden(index.data(KFilePlacesModel::GroupHiddenRole).toBool());
-}
-
-void PlacesItemModel::slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData)
-{
-    if (error && errorData.isValid()) {
-        if (error == Solid::ErrorType::DeviceBusy) {
-            KListOpenFilesJob* listOpenFilesJob = new KListOpenFilesJob(m_deviceToTearDown->filePath());
-            connect(listOpenFilesJob, &KIO::Job::result, this, [this, listOpenFilesJob](KJob*) {
-                const KProcessList::KProcessInfoList blockingProcesses = listOpenFilesJob->processInfoList();
-                QString errorString;
-                if (blockingProcesses.isEmpty()) {
-                    errorString = i18n("One or more files on this device are open within an application.");
-                } else {
-                    QStringList blockingApps;
-                    for (const auto& process : blockingProcesses) {
-                        blockingApps << process.name();
-                    }
-                    blockingApps.removeDuplicates();
-                    errorString = xi18np("One or more files on this device are opened in application <application>\"%2\"</application>.",
-                            "One or more files on this device are opened in following applications: <application>%2</application>.",
-                            blockingApps.count(), blockingApps.join(i18nc("separator in list of apps blocking device unmount", ", ")));
-                }
-                Q_EMIT errorMessage(errorString);
-            });
-            listOpenFilesJob->start();
-        } else {
-            Q_EMIT errorMessage(errorData.toString());
-        }
-    } else {
-        // No error; it must have been unmounted successfully
-        Q_EMIT storageTearDownSuccessful();
-    }
-    disconnect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone,
-               this, &PlacesItemModel::slotStorageTearDownDone);
-    m_deviceToTearDown = nullptr;
-}
-
-void PlacesItemModel::slotStorageSetupDone(Solid::ErrorType error,
-                                           const QVariant& errorData,
-                                           const QString& udi)
-{
-    Q_UNUSED(udi)
-
-    const int index = m_storageSetupInProgress.take(sender());
-    const PlacesItem*  item = placesItem(index);
-    if (!item) {
-        return;
-    }
-
-    if (error != Solid::NoError) {
-        if (errorData.isValid()) {
-            Q_EMIT errorMessage(i18nc("@info", "An error occurred while accessing '%1', the system responded: %2",
-                                    item->text(),
-                                    errorData.toString()));
-        } else {
-            Q_EMIT errorMessage(i18nc("@info", "An error occurred while accessing '%1'",
-                                    item->text()));
-        }
-        Q_EMIT storageSetupDone(index, false);
-    } else {
-        Q_EMIT storageSetupDone(index, true);
-    }
-}
-
-void PlacesItemModel::onSourceModelRowsInserted(const QModelIndex &parent, int first, int last)
-{
-    for (int i = first; i <= last; i++) {
-        const QModelIndex index = m_sourceModel->index(i, 0, parent);
-        addItemFromSourceModel(index);
-    }
-}
-
-void PlacesItemModel::onSourceModelRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
-{
-    for(int r = first; r <= last; r++) {
-        const QModelIndex index = m_sourceModel->index(r, 0, parent);
-        int oldIndex = mapFromSource(index);
-        if (oldIndex != -1) {
-            removeItem(oldIndex);
-        }
-    }
-}
-
-void PlacesItemModel::onSourceModelRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
-{
-    Q_UNUSED(destination)
-    Q_UNUSED(row)
-
-    for(int r = start; r <= end; r++) {
-        const QModelIndex sourceIndex = m_sourceModel->index(r, 0, parent);
-        // remove moved item
-        removeItem(mapFromSource(sourceIndex));
-    }
-}
-
-void PlacesItemModel::onSourceModelRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
-{
-    Q_UNUSED(destination)
-    Q_UNUSED(parent)
-
-    const int blockSize = (end - start) + 1;
-
-    for (int r = start; r <= end; r++) {
-        // insert the moved item in the new position
-        const int targetRow = row + (start - r) - (r < row ? blockSize : 0);
-        const QModelIndex targetIndex = m_sourceModel->index(targetRow, 0, destination);
-
-        addItemFromSourceModel(targetIndex);
-    }
-}
-
-void PlacesItemModel::onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
-{
-    Q_UNUSED(roles)
-
-    for (int r = topLeft.row(); r <= bottomRight.row(); r++) {
-        const QModelIndex sourceIndex = m_sourceModel->index(r, 0);
-        const KBookmark bookmark = m_sourceModel->bookmarkForIndex(sourceIndex);
-        PlacesItem *placeItem = itemFromBookmark(bookmark);
-
-        if (placeItem && (!m_hiddenItemsShown && m_sourceModel->isHidden(sourceIndex))) {
-            //hide item if it became invisible
-            removeItem(index(placeItem));
-            return;
-        }
-
-        if (!placeItem && (m_hiddenItemsShown || !m_sourceModel->isHidden(sourceIndex))) {
-            //show item if it became visible
-            addItemFromSourceModel(sourceIndex);
-            return;
-        }
-
-        if (placeItem && !m_sourceModel->isDevice(sourceIndex)) {
-            // must update the bookmark object
-            placeItem->setBookmark(bookmark);
-        }
-    }
-}
-
-void PlacesItemModel::onSourceModelGroupHiddenChanged(KFilePlacesModel::GroupType group, bool hidden)
-{
-    const auto groupIndexes = m_sourceModel->groupIndexes(group);
-    for (const QModelIndex &sourceIndex : groupIndexes) {
-        PlacesItem *item = placesItem(mapFromSource(sourceIndex));
-        if (item) {
-            item->setGroupHidden(hidden);
-        }
-    }
-}
-
-void PlacesItemModel::cleanupBookmarks()
-{
-    // KIO model now provides support for baloo urls, and because of that we
-    // need to remove old URLs that were visible only in Dolphin to avoid duplication
-
-    static const QVector<QUrl> balooURLs = {
-        QUrl(QStringLiteral("timeline:/today")),
-        QUrl(QStringLiteral("timeline:/yesterday")),
-        QUrl(QStringLiteral("timeline:/thismonth")),
-        QUrl(QStringLiteral("timeline:/lastmonth")),
-        QUrl(QStringLiteral("search:/documents")),
-        QUrl(QStringLiteral("search:/images")),
-        QUrl(QStringLiteral("search:/audio")),
-        QUrl(QStringLiteral("search:/videos"))
-    };
-
-    int row = 0;
-    do {
-        const QModelIndex sourceIndex = m_sourceModel->index(row, 0);
-        const KBookmark bookmark = m_sourceModel->bookmarkForIndex(sourceIndex);
-        const QUrl url = bookmark.url();
-        const QString appName = bookmark.metaDataItem(QStringLiteral("OnlyInApp"));
-
-        if ((appName == KAboutData::applicationData().componentName() ||
-             appName == KAboutData::applicationData().componentName() + DolphinPlacesModelSingleton::applicationNameSuffix()) && balooURLs.contains(url)) {
-            qCDebug(DolphinDebug) << "Removing old baloo url:" << url;
-            m_sourceModel->removePlace(sourceIndex);
-        } else {
-            row++;
-        }
-    } while (row < m_sourceModel->rowCount());
-}
-
-void PlacesItemModel::loadBookmarks()
-{
-    for(int r = 0, rMax = m_sourceModel->rowCount(); r < rMax; r++) {
-        const QModelIndex sourceIndex = m_sourceModel->index(r, 0);
-        if (m_hiddenItemsShown || !m_sourceModel->isHidden(sourceIndex)) {
-            addItemFromSourceModel(sourceIndex);
-        }
-    }
-}
-
-void PlacesItemModel::clear() {
-    KStandardItemModel::clear();
-}
-
-void PlacesItemModel::proceedWithTearDown()
-{
-    Q_ASSERT(m_deviceToTearDown);
-
-    connect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone,
-            this, &PlacesItemModel::slotStorageTearDownDone);
-    m_deviceToTearDown->teardown();
-}
-
-void PlacesItemModel::deleteItem(int index)
-{
-    QModelIndex sourceIndex = mapToSource(index);
-    Q_ASSERT(sourceIndex.isValid());
-    m_sourceModel->removePlace(sourceIndex);
-}
-
-void PlacesItemModel::refresh()
-{
-    m_sourceModel->refresh();
-}
-
-void PlacesItemModel::hideItem(int index)
-{
-    PlacesItem* shownItem = placesItem(index);
-    if (!shownItem) {
-        return;
-    }
-
-    shownItem->setHidden(true);
-}
-
-QString PlacesItemModel::internalMimeType() const
-{
-    return "application/x-dolphinplacesmodel-" +
-            QString::number((qptrdiff)this);
-}
-
-int PlacesItemModel::groupedDropIndex(int index, const PlacesItem* item) const
-{
-    Q_ASSERT(item);
-
-    int dropIndex = index;
-    const QString group = item->group();
-
-    const int itemCount = count();
-    if (index < 0) {
-        dropIndex = itemCount;
-    }
-
-    // Search nearest previous item with the same group
-    int previousIndex = -1;
-    for (int i = dropIndex - 1; i >= 0; --i) {
-        if (placesItem(i)->group() == group) {
-            previousIndex = i;
-            break;
-        }
-    }
-
-    // Search nearest next item with the same group
-    int nextIndex = -1;
-    for (int i = dropIndex; i < count(); ++i) {
-        if (placesItem(i)->group() == group) {
-            nextIndex = i;
-            break;
-        }
-    }
-
-    // Adjust the drop-index to be inserted to the
-    // nearest item with the same group.
-    if (previousIndex >= 0 && nextIndex >= 0) {
-        dropIndex = (dropIndex - previousIndex < nextIndex - dropIndex) ?
-                    previousIndex + 1 : nextIndex;
-    } else if (previousIndex >= 0) {
-        dropIndex = previousIndex + 1;
-    } else if (nextIndex >= 0) {
-        dropIndex = nextIndex;
-    }
-
-    return dropIndex;
-}
-
-bool PlacesItemModel::equalBookmarkIdentifiers(const KBookmark& b1, const KBookmark& b2)
-{
-    const QString udi1 = b1.metaDataItem(QStringLiteral("UDI"));
-    const QString udi2 = b2.metaDataItem(QStringLiteral("UDI"));
-    if (!udi1.isEmpty() && !udi2.isEmpty()) {
-        return udi1 == udi2;
-    } else {
-        return b1.metaDataItem(QStringLiteral("ID")) == b2.metaDataItem(QStringLiteral("ID"));
-    }
-}
-
-int PlacesItemModel::mapFromSource(const QModelIndex &index) const
-{
-    if (!index.isValid()) {
-        return -1;
-    }
-
-    return m_indexMap.indexOf(index);
-}
-
-bool PlacesItemModel::isDir(int index) const
-{
-    Q_UNUSED(index)
-    return true;
-}
-
-KFilePlacesModel::GroupType PlacesItemModel::groupType(int row) const
-{
-    return m_sourceModel->groupType(mapToSource(row));
-}
-
-bool PlacesItemModel::isGroupHidden(KFilePlacesModel::GroupType type) const
-{
-    return m_sourceModel->isGroupHidden(type);
-}
-
-void PlacesItemModel::setGroupHidden(KFilePlacesModel::GroupType type, bool hidden)
-{
-    return m_sourceModel->setGroupHidden(type, hidden);
-}
-
-QModelIndex PlacesItemModel::mapToSource(int row) const
-{
-    return m_indexMap.value(row);
-}
-
-PlacesItem *PlacesItemModel::itemFromBookmark(const KBookmark &bookmark) const
-{
-    const QString id = bookmarkId(bookmark);
-    for (int i = 0, iMax = count(); i < iMax; i++) {
-        PlacesItem *item = placesItem(i);
-        const KBookmark itemBookmark = item->bookmark();
-        if (bookmarkId(itemBookmark) == id) {
-            return item;
-        }
-    }
-    return nullptr;
-}
-
diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h
deleted file mode 100644 (file)
index cd4079a..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESITEMMODEL_H
-#define PLACESITEMMODEL_H
-
-#include "kitemviews/kstandarditemmodel.h"
-
-#include <KFilePlacesModel>
-#include <Solid/Predicate>
-#include <Solid/StorageAccess>
-
-#include <QHash>
-#include <QList>
-#include <QSet>
-#include <QUrl>
-
-class KBookmark;
-class PlacesItem;
-class QAction;
-
-/**
- * @brief Model for maintaining the bookmarks of the places panel.
- *
- * It is based on KFilePlacesModel from KIO.
- */
-class PlacesItemModel: public KStandardItemModel
-{
-    Q_OBJECT
-
-public:
-    explicit PlacesItemModel(QObject* parent = nullptr);
-    ~PlacesItemModel() override;
-
-    /**
-     * @brief Create a new place entry in the bookmark file
-     * and add it to the model
-     */
-    void createPlacesItem(const QString& text, const QUrl& url, const QString& iconName = {}, const QString& appName = {});
-    void createPlacesItem(const QString& text, const QUrl& url, const QString& iconName, const QString& appName, int after);
-
-    PlacesItem* placesItem(int index) const;
-
-    /**
-     * @brief Mark an item as hidden
-     * @param index of the item to be hidden
-     */
-    void hideItem(int index);
-
-    /**
-     * If set to true, all items that are marked as hidden
-     * will be shown in the view. The items will
-     * stay marked as hidden, which is visually indicated
-     * by the view by desaturating the icon and the text.
-     */
-    void setHiddenItemsShown(bool show);
-    bool hiddenItemsShown() const;
-
-    /**
-     * @return Number of items that are marked as hidden.
-     *         Note that this does not mean that the items
-     *         are really hidden
-     *         (see PlacesItemModel::setHiddenItemsShown()).
-     */
-    int hiddenCount() const;
-
-    /**
-     * Search the item which is equal to the URL or at least
-     * is a parent URL. If there are more than one possible
-     * candidates, return the item which covers the biggest
-     * range of the URL. -1 is returned if no closest item
-     * could be found.
-     */
-    int closestItem(const QUrl& url) const;
-
-    QAction* ejectAction(int index) const;
-    QAction* teardownAction(int index) const;
-
-    void requestEject(int index);
-    void requestTearDown(int index);
-
-    bool storageSetupNeeded(int index) const;
-    void requestStorageSetup(int index);
-
-    QMimeData* createMimeData(const KItemSet& indexes) const override;
-
-    bool supportsDropping(int index) const override;
-
-    void dropMimeDataBefore(int index, const QMimeData* mimeData);
-
-    /**
-     * @return Converts the URL, which contains "virtual" URLs for system-items like
-     *         "search:/documents" into a Query-URL that will be handled by
-     *         the corresponding IO-slave. Virtual URLs for bookmarks are used to
-     *         be independent from internal format changes.
-     */
-    static QUrl convertedUrl(const QUrl& url);
-
-    void clear() override;
-
-    void proceedWithTearDown();
-
-    /**
-     * @brief Remove item from bookmark
-     *
-     * This function remove the index from bookmark file permanently
-     *
-     * @param index - the item to be removed
-     */
-    void deleteItem(int index);
-
-    /**
-    * Force a sync on the bookmarks and indicates to other applications that the
-    * state of the bookmarks has been changed.
-    */
-    void refresh();
-
-    bool isDir(int index) const override;
-
-
-    KFilePlacesModel::GroupType groupType(int row) const;
-    bool isGroupHidden(KFilePlacesModel::GroupType type) const;
-    void setGroupHidden(KFilePlacesModel::GroupType type, bool hidden);
-
-Q_SIGNALS:
-    void errorMessage(const QString& message);
-    void storageSetupDone(int index, bool success);
-    void storageTearDownRequested(const QString& mountPath);
-    void storageTearDownExternallyRequested(const QString& mountPath);
-    void storageTearDownSuccessful();
-
-protected:
-    void onItemInserted(int index) override;
-    void onItemRemoved(int index, KStandardItem* removedItem) override;
-    void onItemChanged(int index, const QSet<QByteArray>& changedRoles) override;
-
-private Q_SLOTS:
-    void slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData);
-    void slotStorageSetupDone(Solid::ErrorType error, const QVariant& errorData, const QString& udi);
-
-    // source model control
-    void onSourceModelRowsInserted(const QModelIndex &parent, int first, int last);
-    void onSourceModelRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
-    void onSourceModelRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
-    void onSourceModelRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
-    void onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
-    void onSourceModelGroupHiddenChanged(KFilePlacesModel::GroupType group, bool hidden);
-
-private:
-    /**
-     * Remove bookmarks created by the previous version of dolphin that are
-     * not valid anymore
-     */
-    void cleanupBookmarks();
-
-    /**
-     * Loads the bookmarks from the bookmark-manager and creates items for
-     * the model or moves hidden items to m_bookmarkedItems.
-     */
-    void loadBookmarks();
-
-    QString internalMimeType() const;
-
-    /**
-     * @return Adjusted drop index which assures that the item is aligned
-     *         into the same group as specified by PlacesItem::groupType().
-     */
-    int groupedDropIndex(int index, const PlacesItem* item) const;
-
-    /**
-     * @return True if the bookmarks have the same identifiers. The identifier
-     *         is the unique "ID"-property in case if no UDI is set, otherwise
-     *         the UDI is used as identifier.
-     */
-    static bool equalBookmarkIdentifiers(const KBookmark& b1, const KBookmark& b2);
-
-    /**
-     * Appends the item \a item as last element of the group
-     * the item belongs to. If no item with the same group is
-     * present, the item gets appended as last element of the
-     * model. PlacesItemModel takes the ownership
-     * of the item.
-     */
-    void insertSortedItem(PlacesItem* item);
-
-    PlacesItem *itemFromBookmark(const KBookmark &bookmark) const;
-
-    void addItemFromSourceModel(const QModelIndex &index);
-    void removeItemByIndex(const QModelIndex &mapToSource);
-
-    QString bookmarkId(const KBookmark &bookmark) const;
-    void initializeDefaultViewProperties() const;
-
-    int mapFromSource(const QModelIndex &index) const;
-    QModelIndex mapToSource(int row) const;
-
-    static void updateItem(PlacesItem *item, const QModelIndex &index);
-
-private:
-    bool m_hiddenItemsShown;
-
-    Solid::StorageAccess *m_deviceToTearDown;
-
-    QHash<QObject*, int> m_storageSetupInProgress;
-
-    KFilePlacesModel *m_sourceModel;
-
-    QVector<QPersistentModelIndex> m_indexMap;
-};
-
-#endif
-
-
diff --git a/src/panels/places/placesitemsignalhandler.cpp b/src/panels/places/placesitemsignalhandler.cpp
deleted file mode 100644 (file)
index 19f16c7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesitemsignalhandler.h"
-
-#include "placesitem.h"
-
-PlacesItemSignalHandler::PlacesItemSignalHandler(PlacesItem* item,
-                                                 QObject* parent) :
-    QObject(parent),
-    m_item(item)
-{
-}
-
-PlacesItemSignalHandler::~PlacesItemSignalHandler()
-{
-}
-
-void PlacesItemSignalHandler::onAccessibilityChanged()
-{
-    if (m_item) {
-        m_item->onAccessibilityChanged();
-    }
-}
-
-void PlacesItemSignalHandler::onTearDownRequested(const QString& udi)
-{
-    Q_UNUSED(udi)
-    if (m_item) {
-        Solid::StorageAccess *tmp = m_item->device().as<Solid::StorageAccess>();
-        if (tmp) {
-            Q_EMIT tearDownExternallyRequested(tmp->filePath());
-        }
-    }
-}
-
-void PlacesItemSignalHandler::onTrashEmptinessChanged(bool isTrashEmpty)
-{
-    if (m_item) {
-        m_item->setIcon(isTrashEmpty ? QStringLiteral("user-trash") : QStringLiteral("user-trash-full"));
-    }
-}
-
diff --git a/src/panels/places/placesitemsignalhandler.h b/src/panels/places/placesitemsignalhandler.h
deleted file mode 100644 (file)
index da47839..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESITEMSIGNALHANDLER_H
-#define PLACESITEMSIGNALHANDLER_H
-
-#include <QObject>
-
-class PlacesItem;
-
-/**
- * @brief Helper class for PlacesItem to be able to listen to signals
- *        and performing a corresponding action.
- *
- * PlacesItem is derived from KStandardItem, which is no QObject-class
- * on purpose. To be able to internally listen to signals and performing a
- * corresponding action, PlacesItemSignalHandler is used.
- *
- * E.g. if the PlacesItem wants to react on accessibility-changes of a storage-access,
- * the signal-handler can be used like this:
- * <code>
- *     QObject::connect(storageAccess, SIGNAL(accessibilityChanged(bool,QString)),
- *                      signalHandler, SLOT(onAccessibilityChanged()));
- * </code>
- *
- * The slot PlacesItemSignalHandler::onAccessibilityChanged() will call
- * the method PlacesItem::onAccessibilityChanged().
- */
-class PlacesItemSignalHandler: public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit PlacesItemSignalHandler(PlacesItem* item, QObject* parent = nullptr);
-    ~PlacesItemSignalHandler() override;
-
-public Q_SLOTS:
-    /**
-     * Calls PlacesItem::onAccessibilityChanged()
-     */
-    void onAccessibilityChanged();
-
-    void onTearDownRequested(const QString& udi);
-
-    void onTrashEmptinessChanged(bool isTrashEmpty);
-
-Q_SIGNALS:
-    void tearDownExternallyRequested(const QString& udi);
-
-private:
-    PlacesItem* m_item;
-};
-
-#endif
index 4d95c08eb32a94c5381ff20b97daf00657bbdc44..8fc81bb326a0bd49298384c41fa87644e2a0412a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * SPDX-FileCopyrightText: 2008-2012 Peter Penz <peter.penz19@gmail.com>
+ * SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
  *
  * Based on KFilePlacesView from kdelibs:
  * SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
 
 #include "placespanel.h"
 
+#include "dolphinplacesmodelsingleton.h"
 #include "dolphin_generalsettings.h"
+#include "dolphin_placespanelsettings.h"
 #include "global.h"
-#include "kitemviews/kitemlistcontainer.h"
-#include "kitemviews/kitemlistcontroller.h"
-#include "kitemviews/kitemlistselectionmanager.h"
-#include "kitemviews/kstandarditem.h"
-#include "placesitem.h"
-#include "placesitemlistgroupheader.h"
-#include "placesitemlistwidget.h"
-#include "placesitemmodel.h"
-#include "placesview.h"
-#include "trash/dolphintrash.h"
 #include "views/draganddrophelper.h"
 #include "settings/dolphinsettingsdialog.h"
 
-#include <KFilePlaceEditDialog>
 #include <KFilePlacesModel>
 #include <KIO/DropJob>
-#include <KIO/EmptyTrashJob>
 #include <KIO/Job>
-#include <KIconLoader>
+#include <KListOpenFilesJob>
 #include <KLocalizedString>
-#include <KMountPoint>
-#include <KPropertiesDialog>
 
-#include <QActionGroup>
-#include <QApplication>
-#include <QGraphicsSceneDragDropEvent>
 #include <QIcon>
 #include <QMenu>
-#include <QMimeData>
-#include <QVBoxLayout>
-#include <QToolTip>
-
-PlacesPanel::PlacesPanel(QWidget* parent) :
-        Panel(parent),
-        m_controller(nullptr),
-        m_model(nullptr),
-        m_view(nullptr),
-        m_storageSetupFailedUrl(),
-        m_triggerStorageSetupModifier(),
-        m_itemDropEventIndex(-1),
-        m_itemDropEventMimeData(nullptr),
-        m_itemDropEvent(nullptr),
-        m_tooltipTimer()
-{
-    m_tooltipTimer.setInterval(500);
-    m_tooltipTimer.setSingleShot(true);
-    connect(&m_tooltipTimer, &QTimer::timeout, this, &PlacesPanel::slotShowTooltip);
-}
+#include <QShowEvent>
+#include <QTimer>
 
-PlacesPanel::~PlacesPanel()
-{
-}
+#include <Solid/StorageAccess>
 
-void PlacesPanel::proceedWithTearDown()
+PlacesPanel::PlacesPanel(QWidget* parent)
+    : KFilePlacesView(parent)
 {
-    m_model->proceedWithTearDown();
-}
+    setDropOnPlaceEnabled(true);
+    connect(this, &PlacesPanel::urlsDropped,
+            this, &PlacesPanel::slotUrlsDropped);
 
-bool PlacesPanel::urlChanged()
-{
-    if (!url().isValid() || url().scheme().contains(QLatin1String("search"))) {
-        // Skip results shown by a search, as possible identical
-        // directory names are useless without parent-path information.
-        return false;
-    }
+    setAutoResizeItemsEnabled(false);
 
-    if (m_controller) {
-        selectItem();
-    }
+    setTeardownFunction([this](const QModelIndex &index) {
+        slotTearDownRequested(index);
+    });
+
+    m_configureTrashAction = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18nc("@action:inmenu", "Configure Trash…"));
+    m_configureTrashAction->setPriority(QAction::HighPriority);
+    connect(m_configureTrashAction, &QAction::triggered, this, &PlacesPanel::slotConfigureTrash);
+    addAction(m_configureTrashAction);
+
+    connect(this, &PlacesPanel::contextMenuAboutToShow, this, &PlacesPanel::slotContextMenuAboutToShow);
 
-    return true;
+    connect(this, &PlacesPanel::iconSizeChanged, this, [this](const QSize &newSize) {
+        int iconSize = qMin(newSize.width(), newSize.height());
+        if (iconSize == 0) {
+            // Don't store 0 size, let's keep -1 for default/small/automatic
+            iconSize = -1;
+        }
+        PlacesPanelSettings* settings = PlacesPanelSettings::self();
+        settings->setIconSize(iconSize);
+        settings->save();
+    });
 }
 
-void PlacesPanel::readSettings()
+PlacesPanel::~PlacesPanel() = default;
+
+void PlacesPanel::setUrl(const QUrl &url)
 {
-    if (m_controller) {
-        const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
-        m_controller->setAutoActivationDelay(delay);
-    }
+    // KFilePlacesView::setUrl no-ops when no model is set but we only set it in showEvent()
+    // Remember the URL and set it in showEvent
+    m_url = url;
+    KFilePlacesView::setUrl(url);
 }
 
-void PlacesPanel::showEvent(QShowEvent* event)
+QList<QAction*> PlacesPanel::customContextMenuActions() const
 {
-    if (event->spontaneous()) {
-        Panel::showEvent(event);
-        return;
-    }
-
-    if (!m_controller) {
-        // Postpone the creating of the controller to the first show event.
-        // This assures that no performance and memory overhead is given when the folders panel is not
-        // used at all and stays invisible.
-        m_model = new PlacesItemModel(this);
-        m_model->setGroupedSorting(true);
-        connect(m_model, &PlacesItemModel::errorMessage,
-                this, &PlacesPanel::errorMessage);
-        connect(m_model, &PlacesItemModel::storageTearDownRequested,
-                this, &PlacesPanel::storageTearDownRequested);
-        connect(m_model, &PlacesItemModel::storageTearDownExternallyRequested,
-                this, &PlacesPanel::storageTearDownExternallyRequested);
-        connect(m_model, &PlacesItemModel::storageTearDownSuccessful,
-                this, &PlacesPanel::storageTearDownSuccessful);
-
-        m_view = new PlacesView();
-        m_view->setWidgetCreator(new KItemListWidgetCreator<PlacesItemListWidget>());
-        m_view->setGroupHeaderCreator(new KItemListGroupHeaderCreator<PlacesItemListGroupHeader>());
-
-        installEventFilter(this);
-
-        m_controller = new KItemListController(m_model, m_view, this);
-        m_controller->setSelectionBehavior(KItemListController::SingleSelection);
-        m_controller->setSingleClickActivationEnforced(true);
-
-        readSettings();
-
-        connect(m_controller, &KItemListController::itemActivated, this, &PlacesPanel::slotItemActivated);
-        connect(m_controller, &KItemListController::itemMiddleClicked, this, &PlacesPanel::slotItemMiddleClicked);
-        connect(m_controller, &KItemListController::itemContextMenuRequested, this, &PlacesPanel::slotItemContextMenuRequested);
-        connect(m_controller, &KItemListController::viewContextMenuRequested, this, &PlacesPanel::slotViewContextMenuRequested);
-        connect(m_controller, &KItemListController::itemDropEvent, this, &PlacesPanel::slotItemDropEvent);
-        connect(m_controller, &KItemListController::aboveItemDropEvent, this, &PlacesPanel::slotAboveItemDropEvent);
-
-        KItemListContainer* container = new KItemListContainer(m_controller, this);
-        container->setEnabledFrame(false);
-
-        QVBoxLayout* layout = new QVBoxLayout(this);
-        layout->setContentsMargins(0, 0, 0, 0);
-        layout->addWidget(container);
-
-        selectItem();
-    }
-
-    Panel::showEvent(event);
+    return m_customContextMenuActions;
 }
 
-bool PlacesPanel::eventFilter(QObject * /* obj */, QEvent *event)
+void PlacesPanel::setCustomContextMenuActions(const QList<QAction *> &actions)
 {
-    if (event->type() == QEvent::ToolTip) {
-
-        QHelpEvent *hoverEvent = reinterpret_cast<QHelpEvent *>(event);
-
-        m_hoveredIndex = m_view->itemAt(hoverEvent->pos());
-        m_hoverPos = mapToGlobal(hoverEvent->pos());
-
-        m_tooltipTimer.start();
-        return true;
-    }
-    return false;
+    m_customContextMenuActions = actions;
 }
 
-void PlacesPanel::slotItemActivated(int index)
+void PlacesPanel::proceedWithTearDown()
 {
-    const auto modifiers = QGuiApplication::keyboardModifiers();
-    // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
-    if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) {
-        triggerItem(index, TriggerItemModifier::ToNewActiveTab);
-    } else if (modifiers & Qt::ControlModifier) {
-        triggerItem(index, TriggerItemModifier::ToNewTab);
-    } else if (modifiers & Qt::ShiftModifier) {
-        triggerItem(index, TriggerItemModifier::ToNewWindow);
-    } else {
-        triggerItem(index, TriggerItemModifier::None);
-    }
+    Q_ASSERT(m_deviceToTearDown);
+
+    connect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone,
+            this, &PlacesPanel::slotTearDownDone);
+    m_deviceToTearDown->teardown();
 }
 
-void PlacesPanel::slotItemMiddleClicked(int index)
+void PlacesPanel::readSettings()
 {
-    const auto modifiers = QGuiApplication::keyboardModifiers();
-    // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
-    if (modifiers & Qt::ShiftModifier) {
-        triggerItem(index, TriggerItemModifier::ToNewActiveTab);
+    if (GeneralSettings::autoExpandFolders()) {
+        if (!m_dragActivationTimer) {
+            m_dragActivationTimer = new QTimer(this);
+            m_dragActivationTimer->setInterval(750);
+            m_dragActivationTimer->setSingleShot(true);
+            connect(m_dragActivationTimer, &QTimer::timeout,
+                    this, &PlacesPanel::slotDragActivationTimeout);
+        }
     } else {
-        triggerItem(index, TriggerItemModifier::ToNewTab);
+        delete m_dragActivationTimer;
+        m_dragActivationTimer = nullptr;
+        m_pendingDragActivation = QPersistentModelIndex();
     }
+
+    const int iconSize = qMax(0, PlacesPanelSettings::iconSize());
+    setIconSize(QSize(iconSize, iconSize));
 }
 
-void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
+void PlacesPanel::showEvent(QShowEvent* event)
 {
-    PlacesItem* item = m_model->placesItem(index);
-    if (!item) {
-        return;
-    }
-
-    QMenu menu(this);
-
-    QAction* emptyTrashAction = nullptr;
-    QAction* configureTrashAction = nullptr;
-    QAction* editAction = nullptr;
-    QAction* teardownAction = nullptr;
-    QAction* ejectAction = nullptr;
-    QAction* mountAction = nullptr;
-
-    const bool isDevice = !item->udi().isEmpty();
-    const bool isTrash = (item->url().scheme() == QLatin1String("trash"));
-    if (isTrash) {
-        emptyTrashAction = menu.addAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18nc("@action:inmenu", "Empty Trash"));
-        emptyTrashAction->setEnabled(item->icon() == QLatin1String("user-trash-full"));
-        menu.addSeparator();
-    }
-
-    QAction* openInNewTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@item:inmenu", "Open in New Tab"));
-    QAction* openInNewWindowAction = menu.addAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("@item:inmenu", "Open in New Window"));
-    QAction* propertiesAction = nullptr;
-    if (item->url().isLocalFile()) {
-        propertiesAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action:inmenu", "Properties"));
-    }
-    if (!isDevice) {
-        menu.addSeparator();
-    }
-
-    if (isDevice) {
-        ejectAction = m_model->ejectAction(index);
-        if (ejectAction) {
-            ejectAction->setParent(&menu);
-            menu.addAction(ejectAction);
-        }
+    if (!event->spontaneous() && !model()) {
+        readSettings();
 
-        teardownAction = m_model->teardownAction(index);
-        if (teardownAction) {
-            // Disable teardown option for root and home partitions
-            bool teardownEnabled = item->url() != QUrl::fromLocalFile(QDir::rootPath());
-            if (teardownEnabled) {
-                KMountPoint::Ptr mountPoint = KMountPoint::currentMountPoints().findByPath(QDir::homePath());
-                if (mountPoint && item->url() == QUrl::fromLocalFile(mountPoint->mountPoint())) {
-                    teardownEnabled = false;
-                }
-            }
-            teardownAction->setEnabled(teardownEnabled);
+        auto *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
+        setModel(placesModel);
 
-            teardownAction->setParent(&menu);
-            menu.addAction(teardownAction);
-        }
+        connect(placesModel, &KFilePlacesModel::errorMessage, this, &PlacesPanel::errorMessage);
 
-        if (item->storageSetupNeeded()) {
-            mountAction = menu.addAction(QIcon::fromTheme(QStringLiteral("media-mount")), i18nc("@action:inmenu", "Mount"));
-        }
+        connect(placesModel, &QAbstractItemModel::rowsInserted, this, &PlacesPanel::slotRowsInserted);
+        connect(placesModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &PlacesPanel::slotRowsAboutToBeRemoved);
 
-        if (teardownAction || ejectAction || mountAction) {
-            menu.addSeparator();
+        for (int i = 0; i < model()->rowCount(); ++i) {
+            connectDeviceSignals(model()->index(i, 0, QModelIndex()));
         }
-    }
-
-    if (isTrash) {
-        configureTrashAction = menu.addAction(QIcon::fromTheme(QStringLiteral("configure")), i18nc("@action:inmenu", "Configure Trash..."));
-    }
-
-    if (!isDevice) {
-        editAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-entry")), i18nc("@item:inmenu", "Edit..."));
-    }
-
-    QAction* removeAction = nullptr;
-    if (!isDevice && !item->isSystemItem()) {
-        removeAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@item:inmenu", "Remove"));
-    }
-
-    QAction* hideAction = menu.addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide"));
-    hideAction->setCheckable(true);
-    hideAction->setChecked(item->isHidden());
-
-    buildGroupContextMenu(&menu, index);
-
-    QAction* action = menu.exec(pos.toPoint());
-    if (action) {
-        if (action == emptyTrashAction) {
-            Trash::empty(this);
-        } else if (action == configureTrashAction) {
-            DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(item->url(), this);
-            settingsDialog->setCurrentPage(settingsDialog->trashSettings);
-            settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
-            settingsDialog->show();
-        } else {
-            // The index might have changed if devices were added/removed while
-            // the context menu was open.
-            index = m_model->index(item);
-            if (index < 0) {
-                // The item is not in the model any more, probably because it was an
-                // external device that has been removed while the context menu was open.
-                return;
-            }
 
-            if (action == editAction) {
-                editEntry(index);
-            } else if (action == removeAction) {
-                m_model->deleteItem(index);
-            } else if (action == hideAction) {
-                item->setHidden(hideAction->isChecked());
-                if (!m_model->hiddenCount()) {
-                    showHiddenEntries(false);
-                }
-            } else if (action == openInNewWindowAction) {
-                Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(m_model->data(index).value("url").toUrl())}, this);
-            } else if (action == openInNewTabAction) {
-                triggerItem(index, TriggerItemModifier::ToNewTab);
-            } else if (action == mountAction) {
-                m_model->requestStorageSetup(index);
-            } else if (action == teardownAction) {
-                m_model->requestTearDown(index);
-            } else if (action == ejectAction) {
-                m_model->requestEject(index);
-            } else if (action == propertiesAction) {
-                KPropertiesDialog* dialog = new KPropertiesDialog(item->url(), this);
-                dialog->setAttribute(Qt::WA_DeleteOnClose);
-                dialog->show();
-            }
-        }
+        setUrl(m_url);
     }
 
-    selectItem();
+    KFilePlacesView::showEvent(event);
 }
 
-void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos)
+void PlacesPanel::dragMoveEvent(QDragMoveEvent *event)
 {
-    QMenu menu(this);
-
-    QAction* addAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-new")), i18nc("@item:inmenu", "Add Entry..."));
-
-    QAction* showAllAction = menu.addAction(i18nc("@item:inmenu", "Show Hidden Places"));
-    showAllAction->setCheckable(true);
-    showAllAction->setChecked(m_model->hiddenItemsShown());
-    showAllAction->setIcon(QIcon::fromTheme(m_model->hiddenItemsShown() ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
-    showAllAction->setEnabled(m_model->hiddenCount());
-
-    buildGroupContextMenu(&menu, m_controller->indexCloseToMousePressedPosition());
-
-    QMenu* iconSizeSubMenu = new QMenu(i18nc("@item:inmenu", "Icon Size"), &menu);
-
-    struct IconSizeInfo
-    {
-        int size;
-        const char* context;
-        const char* text;
-    };
-
-    const int iconSizeCount = 4;
-    static const IconSizeInfo iconSizes[iconSizeCount] = {
-        {KIconLoader::SizeSmall,        I18NC_NOOP("Small icon size", "Small (%1x%2)")},
-        {KIconLoader::SizeSmallMedium,  I18NC_NOOP("Medium icon size", "Medium (%1x%2)")},
-        {KIconLoader::SizeMedium,       I18NC_NOOP("Large icon size", "Large (%1x%2)")},
-        {KIconLoader::SizeLarge,        I18NC_NOOP("Huge icon size", "Huge (%1x%2)")}
-    };
-
-    QHash<QAction*, int> iconSizeActionMap;
-    QActionGroup* iconSizeGroup = new QActionGroup(iconSizeSubMenu);
-
-    for (int i = 0; i < iconSizeCount; ++i) {
-        const int size = iconSizes[i].size;
-        const QString text = i18nc(iconSizes[i].context, iconSizes[i].text,
-                                   size, size);
-
-        QAction* action = iconSizeSubMenu->addAction(text);
-        iconSizeActionMap.insert(action, size);
-        action->setActionGroup(iconSizeGroup);
-        action->setCheckable(true);
-        action->setChecked(m_view->iconSize() == size);
-    }
+    KFilePlacesView::dragMoveEvent(event);
 
-    menu.addMenu(iconSizeSubMenu);
-
-    menu.addSeparator();
-    const auto actions = customContextMenuActions();
-    for (QAction* action : actions) {
-        menu.addAction(action);
+    if (!m_dragActivationTimer) {
+        return;
     }
 
-    QAction* action = menu.exec(pos.toPoint());
-    if (action) {
-        if (action == addAction) {
-            addEntry();
-        } else if (action == showAllAction) {
-            showHiddenEntries(showAllAction->isChecked());
-        } else if (iconSizeActionMap.contains(action)) {
-            m_view->setIconSize(iconSizeActionMap.value(action));
-        }
+    const QModelIndex index = indexAt(event->pos());
+    if (!index.isValid()) {
+        return;
     }
 
-    selectItem();
-}
-
-QAction *PlacesPanel::buildGroupContextMenu(QMenu *menu, int index)
-{
-    if (index == -1) {
-        return nullptr;
+    QPersistentModelIndex persistentIndex(index);
+    if (!m_pendingDragActivation.isValid() || m_pendingDragActivation != persistentIndex) {
+        m_pendingDragActivation = persistentIndex;
+        m_dragActivationTimer->start();
     }
-
-    KFilePlacesModel::GroupType groupType = m_model->groupType(index);
-    QAction *hideGroupAction = menu->addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide Section '%1'", m_model->item(index)->group()));
-    hideGroupAction->setCheckable(true);
-    hideGroupAction->setChecked(m_model->isGroupHidden(groupType));
-
-    connect(hideGroupAction, &QAction::triggered, this, [this, groupType, hideGroupAction]{
-        m_model->setGroupHidden(groupType, hideGroupAction->isChecked());
-        if (!m_model->hiddenCount()) {
-            showHiddenEntries(false);
-        }
-    });
-
-    return hideGroupAction;
 }
 
-void PlacesPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
+void PlacesPanel::dragLeaveEvent(QDragLeaveEvent *event)
 {
-    if (index < 0) {
-        return;
-    }
-
-    const PlacesItem* destItem = m_model->placesItem(index);
-
-    if (destItem->isSearchOrTimelineUrl()) {
-        return;
-    }
+    KFilePlacesView::dragLeaveEvent(event);
 
-    if (m_model->storageSetupNeeded(index)) {
-        connect(m_model, &PlacesItemModel::storageSetupDone,
-                this, &PlacesPanel::slotItemDropEventStorageSetupDone);
-
-        m_itemDropEventIndex = index;
-
-        // Make a full copy of the Mime-Data
-        m_itemDropEventMimeData = new QMimeData;
-        m_itemDropEventMimeData->setText(event->mimeData()->text());
-        m_itemDropEventMimeData->setHtml(event->mimeData()->html());
-        m_itemDropEventMimeData->setUrls(event->mimeData()->urls());
-        m_itemDropEventMimeData->setImageData(event->mimeData()->imageData());
-        m_itemDropEventMimeData->setColorData(event->mimeData()->colorData());
-
-        m_itemDropEvent = new QDropEvent(event->pos().toPoint(),
-                                         event->possibleActions(),
-                                         m_itemDropEventMimeData,
-                                         event->buttons(),
-                                         event->modifiers());
-
-        m_model->requestStorageSetup(index);
-        return;
+    if (m_dragActivationTimer) {
+        m_dragActivationTimer->stop();
+        m_pendingDragActivation = QPersistentModelIndex();
     }
-
-    QUrl destUrl = destItem->url();
-    QDropEvent dropEvent(event->pos().toPoint(),
-                         event->possibleActions(),
-                         event->mimeData(),
-                         event->buttons(),
-                         event->modifiers());
-
-    slotUrlsDropped(destUrl, &dropEvent, this);
 }
 
-void PlacesPanel::slotItemDropEventStorageSetupDone(int index, bool success)
+void PlacesPanel::slotConfigureTrash()
 {
-    disconnect(m_model, &PlacesItemModel::storageSetupDone,
-               this, &PlacesPanel::slotItemDropEventStorageSetupDone);
+    const QUrl url = currentIndex().data(KFilePlacesModel::UrlRole).toUrl();
 
-    if ((index == m_itemDropEventIndex) && m_itemDropEvent && m_itemDropEventMimeData) {
-        if (success) {
-            QUrl destUrl = m_model->placesItem(index)->url();
-            slotUrlsDropped(destUrl, m_itemDropEvent, this);
-        }
-
-        delete m_itemDropEventMimeData;
-        delete m_itemDropEvent;
-
-        m_itemDropEventIndex = -1;
-        m_itemDropEventMimeData = nullptr;
-        m_itemDropEvent = nullptr;
-    }
+    DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this);
+    settingsDialog->setCurrentPage(settingsDialog->trashSettings);
+    settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
+    settingsDialog->show();
 }
 
-void PlacesPanel::slotAboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
+void PlacesPanel::slotDragActivationTimeout()
 {
-    m_model->dropMimeDataBefore(index, event->mimeData());
+    if (!m_pendingDragActivation.isValid()) {
+        return;
+    }
+
+    auto *placesModel = static_cast<KFilePlacesModel *>(model());
+    Q_EMIT placeActivated(KFilePlacesModel::convertedUrl(placesModel->url(m_pendingDragActivation)));
 }
 
 void PlacesPanel::slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget* parent)
@@ -490,132 +193,121 @@ void PlacesPanel::slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget*
     }
 }
 
-void PlacesPanel::slotStorageSetupDone(int index, bool success)
+void PlacesPanel::slotContextMenuAboutToShow(const QModelIndex &index, QMenu *menu)
 {
-    disconnect(m_model, &PlacesItemModel::storageSetupDone,
-               this, &PlacesPanel::slotStorageSetupDone);
+    Q_UNUSED(menu);
 
-    if (m_triggerStorageSetupModifier == TriggerItemModifier::None) {
-        return;
-    }
+    auto *placesModel = static_cast<KFilePlacesModel *>(model());
+    const QUrl url = placesModel->url(index);
+    const Solid::Device device = placesModel->deviceForIndex(index);
 
-    if (success) {
-        Q_ASSERT(!m_model->storageSetupNeeded(index));
-        triggerItem(index, m_triggerStorageSetupModifier);
-        m_triggerStorageSetupModifier = TriggerItemModifier::None;
+    m_configureTrashAction->setVisible(url.scheme() == QLatin1String("trash"));
+
+    // show customContextMenuActions only on the view's context menu
+    if (!url.isValid() && !device.isValid()) {
+        addActions(m_customContextMenuActions);
     } else {
-        setUrl(m_storageSetupFailedUrl);
-        m_storageSetupFailedUrl = QUrl();
+        const auto actions = this->actions();
+        for (QAction *action : actions) {
+            if (m_customContextMenuActions.contains(action)) {
+                removeAction(action);
+            }
+        }
     }
 }
 
-void PlacesPanel::slotShowTooltip()
+void PlacesPanel::slotTearDownRequested(const QModelIndex &index)
 {
-    const QUrl url = m_model->data(m_hoveredIndex.value_or(-1)).value("url").value<QUrl>();
-    const QString text = url.toDisplayString(QUrl::PreferLocalFile);
-    QToolTip::showText(m_hoverPos, text);
-}
+    auto *placesModel = static_cast<KFilePlacesModel *>(model());
 
-void PlacesPanel::addEntry()
-{
-    const int index = m_controller->selectionManager()->currentItem();
-    const QUrl url = m_model->data(index).value("url").toUrl();
-    const QString text = url.fileName().isEmpty() ? url.toDisplayString(QUrl::PreferLocalFile) : url.fileName();
-
-    QPointer<KFilePlaceEditDialog> dialog = new KFilePlaceEditDialog(true, url, text, QString(), true, false, KIconLoader::SizeMedium, this);
-    if (dialog->exec() == QDialog::Accepted) {
-        const QString appName = dialog->applicationLocal() ? QCoreApplication::applicationName() : QString();
-        m_model->createPlacesItem(dialog->label(), dialog->url(), dialog->icon(), appName);
+    Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as<Solid::StorageAccess>();
+    if (!storageAccess) {
+        return;
     }
 
-    delete dialog;
+    m_deviceToTearDown = storageAccess;
+
+    // disconnect the Solid::StorageAccess::teardownRequested
+    // to prevent emitting PlacesPanel::storageTearDownExternallyRequested
+    // after we have emitted PlacesPanel::storageTearDownRequested
+    disconnect(storageAccess, &Solid::StorageAccess::teardownRequested, this, &PlacesPanel::slotTearDownRequestedExternally);
+    Q_EMIT storageTearDownRequested(storageAccess->filePath());
 }
 
-void PlacesPanel::editEntry(int index)
+void PlacesPanel::slotTearDownRequestedExternally(const QString &udi)
 {
-    QHash<QByteArray, QVariant> data = m_model->data(index);
-    const QUrl url = data.value("url").toUrl();
-    const QString text = data.value("text").toString();
-    const QString iconName = data.value("iconName").toString();
-    const bool applicationLocal = !data.value("applicationName").toString().isEmpty();
-
-    QPointer<KFilePlaceEditDialog> dialog = new KFilePlaceEditDialog(true, url, text, iconName, true, applicationLocal, KIconLoader::SizeMedium, this);
-    if (dialog->exec() == QDialog::Accepted) {
-        PlacesItem* oldItem = m_model->placesItem(index);
-        if (oldItem) {
-            const QString appName = dialog->applicationLocal() ? QCoreApplication::applicationName() : QString();
-            oldItem->setApplicationName(appName);
-            oldItem->setText(dialog->label());
-            oldItem->setUrl(dialog->url());
-            oldItem->setIcon(dialog->icon());
-            m_model->refresh();
-        }
-    }
+    Q_UNUSED(udi);
+    auto *storageAccess = static_cast<Solid::StorageAccess*>(sender());
 
-    delete dialog;
+    Q_EMIT storageTearDownExternallyRequested(storageAccess->filePath());
 }
 
-void PlacesPanel::selectItem()
+void PlacesPanel::slotTearDownDone(Solid::ErrorType error, const QVariant& errorData)
 {
-    const int index = m_model->closestItem(url());
-    KItemListSelectionManager* selectionManager = m_controller->selectionManager();
-    selectionManager->setCurrentItem(index);
-    selectionManager->clearSelection();
-
-    const QUrl closestUrl = m_model->url(index);
-    if (!closestUrl.path().isEmpty() && url() == closestUrl) {
-        selectionManager->setSelected(index);
+    if (error && errorData.isValid()) {
+        if (error == Solid::ErrorType::DeviceBusy) {
+            KListOpenFilesJob* listOpenFilesJob = new KListOpenFilesJob(m_deviceToTearDown->filePath());
+            connect(listOpenFilesJob, &KIO::Job::result, this, [this, listOpenFilesJob](KJob*) {
+                const KProcessList::KProcessInfoList blockingProcesses = listOpenFilesJob->processInfoList();
+                QString errorString;
+                if (blockingProcesses.isEmpty()) {
+                    errorString = i18n("One or more files on this device are open within an application.");
+                } else {
+                    QStringList blockingApps;
+                    for (const auto& process : blockingProcesses) {
+                        blockingApps << process.name();
+                    }
+                    blockingApps.removeDuplicates();
+                    errorString = xi18np("One or more files on this device are opened in application <application>\"%2\"</application>.",
+                            "One or more files on this device are opened in following applications: <application>%2</application>.",
+                            blockingApps.count(), blockingApps.join(i18nc("separator in list of apps blocking device unmount", ", ")));
+                }
+                Q_EMIT errorMessage(errorString);
+            });
+            listOpenFilesJob->start();
+        } else {
+            Q_EMIT errorMessage(errorData.toString());
+        }
+    } else {
+        // No error; it must have been unmounted successfully
+        Q_EMIT storageTearDownSuccessful();
     }
+    disconnect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone,
+               this, &PlacesPanel::slotTearDownDone);
+    m_deviceToTearDown = nullptr;
 }
 
-void PlacesPanel::triggerItem(int index, TriggerItemModifier modifier)
+void PlacesPanel::slotRowsInserted(const QModelIndex &parent, int first, int last)
 {
-    const PlacesItem* item = m_model->placesItem(index);
-    if (!item) {
-        return;
+    for (int i = first; i <= last; ++i) {
+        connectDeviceSignals(model()->index(first, 0, parent));
     }
+}
 
-    if (m_model->storageSetupNeeded(index)) {
-        m_triggerStorageSetupModifier = modifier;
-        m_storageSetupFailedUrl = url();
+void PlacesPanel::slotRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
+{
+    auto *placesModel = static_cast<KFilePlacesModel *>(model());
 
-        connect(m_model, &PlacesItemModel::storageSetupDone,
-                this, &PlacesPanel::slotStorageSetupDone);
+    for (int i = first; i <= last; ++i) {
+        const QModelIndex index = placesModel->index(i, 0, parent);
 
-        m_model->requestStorageSetup(index);
-    } else {
-        m_triggerStorageSetupModifier = TriggerItemModifier::None;
-
-        const QUrl url = m_model->data(index).value("url").toUrl();
-        if (!url.isEmpty()) {
-            switch (modifier) {
-                case TriggerItemModifier::ToNewTab:
-                    Q_EMIT placeActivatedInNewTab(KFilePlacesModel::convertedUrl(url));
-                    break;
-                case TriggerItemModifier::ToNewActiveTab:
-                    Q_EMIT placeActivatedInNewActiveTab(KFilePlacesModel::convertedUrl(url));
-                    break;
-                case TriggerItemModifier::ToNewWindow:
-                    Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(url)}, this);
-                    break;
-                case TriggerItemModifier::None:
-                    Q_EMIT placeActivated(KFilePlacesModel::convertedUrl(url));
-                    break;
-            }
+        Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as<Solid::StorageAccess>();
+        if (!storageAccess) {
+            continue;
         }
+
+        disconnect(storageAccess, &Solid::StorageAccess::teardownRequested, this, nullptr);
     }
 }
 
-void PlacesPanel::showHiddenEntries(bool shown)
+void PlacesPanel::connectDeviceSignals(const QModelIndex &index)
 {
-    m_model->setHiddenItemsShown(shown);
-    Q_EMIT showHiddenEntriesChanged(shown);
-}
+    auto *placesModel = static_cast<KFilePlacesModel *>(model());
 
-int PlacesPanel::hiddenListCount()
-{
-    if(!m_model) {
-        return 0;
+    Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as<Solid::StorageAccess>();
+    if (!storageAccess) {
+        return;
     }
-    return m_model->hiddenCount();
+
+    connect(storageAccess, &Solid::StorageAccess::teardownRequested, this, &PlacesPanel::slotTearDownRequestedExternally);
 }
index e19447cbfeb785526529f2e58419e067be2391d9..fd6661c76fececbf67655000e3649aef9dd93042 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * SPDX-FileCopyrightText: 2008-2012 Peter Penz <peter.penz19@gmail.com>
  * SPDX-FileCopyrightText: 2010 Christian Muehlhaeuser <muesli@gmail.com>
+ * SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -8,95 +9,78 @@
 #ifndef PLACESPANEL_H
 #define PLACESPANEL_H
 
-#include <optional>
-
 #include "panels/panel.h"
 
 #include <QUrl>
-#include <QTimer>
-
-class KItemListController;
-class PlacesItemModel;
-class PlacesView;
-class QGraphicsSceneDragDropEvent;
-class QMenu;
-class QMimeData;
+#include <KFilePlacesView>
+
+#include <Solid/SolidNamespace> // Solid::ErrorType
+
+class QTimer;
+namespace Solid
+{
+class StorageAccess;
+}
+
 /**
  * @brief Combines bookmarks and mounted devices as list.
  */
-class PlacesPanel : public Panel
+class PlacesPanel : public KFilePlacesView
 {
     Q_OBJECT
 
 public:
     explicit PlacesPanel(QWidget* parent);
     ~PlacesPanel() override;
+
+    void setUrl(const QUrl &url); // override
+
+    // for compatibility with Panel, actions that are shown
+    // on the view's context menu
+    QList<QAction*> customContextMenuActions() const;
+    void setCustomContextMenuActions(const QList<QAction*>& actions);
+
+    void requestTearDown();
     void proceedWithTearDown();
 
-    bool eventFilter(QObject *obj, QEvent *event) override;
+public Q_SLOTS:
+    void readSettings();
 
 Q_SIGNALS:
-    void placeActivated(const QUrl& url);
-    void placeActivatedInNewTab(const QUrl &url);
-    void placeActivatedInNewActiveTab(const QUrl &url);
     void errorMessage(const QString& error);
     void storageTearDownRequested(const QString& mountPath);
     void storageTearDownExternallyRequested(const QString& mountPath);
-    void showHiddenEntriesChanged(bool shown);
     void storageTearDownSuccessful();
 
 protected:
-    bool urlChanged() override;
     void showEvent(QShowEvent* event) override;
-
-public Q_SLOTS:
-    void readSettings() override;
-    void showHiddenEntries(bool shown);
-    int hiddenListCount();
+    void dragMoveEvent(QDragMoveEvent *event) override;
+    void dragLeaveEvent(QDragLeaveEvent *event) override;
 
 private Q_SLOTS:
-    void slotItemActivated(int index);
-    void slotItemMiddleClicked(int index);
-    void slotItemContextMenuRequested(int index, const QPointF& pos);
-    void slotViewContextMenuRequested(const QPointF& pos);
-    void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
-    void slotItemDropEventStorageSetupDone(int index, bool success);
-    void slotAboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
+    void slotConfigureTrash();
+    void slotDragActivationTimeout();
     void slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget* parent);
-    void slotStorageSetupDone(int index, bool success);
-    void slotShowTooltip();
+    void slotContextMenuAboutToShow(const QModelIndex &index, QMenu *menu);
+    void slotTearDownRequested(const QModelIndex &index);
+    void slotTearDownRequestedExternally(const QString &udi);
+    void slotTearDownDone(Solid::ErrorType error, const QVariant& errorData);
+    void slotRowsInserted(const QModelIndex &parent, int first, int last);
+    void slotRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
 
 private:
-    enum class TriggerItemModifier { None, ToNewTab, ToNewActiveTab, ToNewWindow };
+    void connectDeviceSignals(const QModelIndex &idx);
 
-private:
-    void addEntry();
-    void editEntry(int index);
-
-    /**
-     * Selects the item that matches the URL set
-     * for the panel (see Panel::setUrl()).
-     */
-    void selectItem();
+    QUrl m_url; // only used for initial setUrl
+    QList<QAction*> m_customContextMenuActions;
 
-    void triggerItem(int index, TriggerItemModifier modifier);
+    QTimer *m_dragActivationTimer = nullptr;
+    QPersistentModelIndex m_pendingDragActivation;
 
-    QAction* buildGroupContextMenu(QMenu* menu, int index);
+    Solid::StorageAccess *m_deviceToTearDown = nullptr;
 
-private:
-    KItemListController* m_controller;
-    PlacesItemModel* m_model;
-    PlacesView* m_view;
-
-    QUrl m_storageSetupFailedUrl;
-    TriggerItemModifier m_triggerStorageSetupModifier;
-
-    int m_itemDropEventIndex;
-    QMimeData* m_itemDropEventMimeData;
-    QDropEvent* m_itemDropEvent;
-    QTimer m_tooltipTimer;
-    std::optional<int> m_hoveredIndex;
-    QPoint m_hoverPos;
+    QAction *m_configureTrashAction;
+    QAction *m_lockPanelsAction;
 };
 
 #endif // PLACESPANEL_H
diff --git a/src/panels/places/placesview.cpp b/src/panels/places/placesview.cpp
deleted file mode 100644 (file)
index dc264e4..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Frank Reininghaus <frank78ac@googlemail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "placesview.h"
-
-#include "dolphin_placespanelsettings.h"
-#include "kitemviews/kitemlistheader.h"
-
-#include <QGraphicsSceneResizeEvent>
-
-PlacesView::PlacesView(QGraphicsWidget* parent) :
-    KStandardItemListView(parent)
-{
-    header()->setAutomaticColumnResizing(false);
-
-    const int iconSize = PlacesPanelSettings::iconSize();
-    if (iconSize >= 0) {
-        setIconSize(iconSize);
-    }
-}
-
-void PlacesView::setIconSize(int size)
-{
-    if (size != iconSize()) {
-        PlacesPanelSettings* settings = PlacesPanelSettings::self();
-        settings->setIconSize(size);
-        settings->save();
-
-        KItemListStyleOption option = styleOption();
-        option.iconSize = size;
-        setStyleOption(option);
-    }
-}
-
-int PlacesView::iconSize() const
-{
-    const KItemListStyleOption option = styleOption();
-    return option.iconSize;
-}
-
-void PlacesView::resizeEvent(QGraphicsSceneResizeEvent *event)
-{
-    KStandardItemListView::resizeEvent(event);
-
-    header()->setColumnWidth(QByteArrayLiteral("text"), event->newSize().width());
-}
diff --git a/src/panels/places/placesview.h b/src/panels/places/placesview.h
deleted file mode 100644 (file)
index 86515f5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2012 Frank Reininghaus <frank78ac@googlemail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef PLACESVIEW_H
-#define PLACESVIEW_H
-
-#include "kitemviews/kstandarditemlistview.h"
-
-/**
- * @brief View class for the Places Panel.
- *
- * Reads the icon size from GeneralSettings::placesPanelIconSize().
- */
-class PlacesView : public KStandardItemListView
-{
-    Q_OBJECT
-
-public:
-    explicit PlacesView(QGraphicsWidget* parent = nullptr);
-
-    void setIconSize(int size);
-    int iconSize() const;
-
-protected:
-    void resizeEvent(QGraphicsSceneResizeEvent *event) override;
-};
-
-#endif
index 9143ddcb770023038ef245b2d61d05836216c7b6..860d9f6cd5d31b935e9073b5be77cc329b0217e0 100644 (file)
@@ -9,8 +9,8 @@
 
 #include "dolphin_searchsettings.h"
 #include "dolphinfacetswidget.h"
+#include "dolphinplacesmodelsingleton.h"
 #include "dolphinquery.h"
-#include "panels/places/placesitemmodel.h"
 
 #include <KLocalizedString>
 #include <KNS3/KMoreToolsMenuFactory>
@@ -288,11 +288,8 @@ void DolphinSearchBox::slotSearchSaved()
 {
     const QUrl searchURL = urlForSearching();
     if (searchURL.isValid()) {
-        PlacesItemModel model;
         const QString label = i18n("Search for %1 in %2", text(), searchPath().fileName());
-        model.createPlacesItem(label,
-                               searchURL,
-                               QStringLiteral("folder-saved-search-symbolic"));
+        DolphinPlacesModelSingleton::instance().placesModel()->addPlace(label, searchURL, QStringLiteral("folder-saved-search-symbolic"));
     }
 }
 
index e9a0e2dced946f274af4770d5ac4e792991a2935..95ba0186185208cb3236330e1e3a871842755c36 100644 (file)
@@ -69,11 +69,6 @@ LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
 # DragAndDropHelperTest
 ecm_add_test(draganddrophelpertest.cpp LINK_LIBRARIES dolphinprivate Qt5::Test)
 
-# PlacesItemModelTest
-ecm_add_test(placesitemmodeltest.cpp
-TEST_NAME placesitemmodeltest
-LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
-
 find_gem(test-unit)
 set_package_properties(Gem:test-unit PROPERTIES
     TYPE RECOMMENDED
diff --git a/src/tests/placesitemmodeltest.cpp b/src/tests/placesitemmodeltest.cpp
deleted file mode 100644 (file)
index 15a4946..0000000
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2017 Renato Araujo Oliveira <renato.araujo@kdab.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include <QTest>
-#include <QSignalSpy>
-#include <QStandardPaths>
-#include <QAction>
-#include <QDBusInterface>
-
-#include <KBookmarkManager>
-#include <KConfig>
-#include <KConfigGroup>
-#include <KAboutData>
-#include <KFilePlacesModel>
-#include <KProtocolInfo>
-
-#include "dolphin_generalsettings.h"
-#include "panels/places/placesitemmodel.h"
-#include "panels/places/placesitem.h"
-#include "views/viewproperties.h"
-
-Q_DECLARE_METATYPE(KItemRangeList)
-Q_DECLARE_METATYPE(KItemRange)
-
-static QString bookmarksFile()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/user-places.xbel";
-}
-
-class PlacesItemModelTest : public QObject
-{
-    Q_OBJECT
-
-private Q_SLOTS:
-    void init();
-    void cleanup();
-
-    void initTestCase();
-    void cleanupTestCase();
-
-    void testModelSort();
-    void testGroups();
-    void testDeletePlace();
-    void testPlaceItem_data();
-    void testPlaceItem();
-    void testTearDownDevice();
-    void testDefaultViewProperties_data();
-    void testDefaultViewProperties();
-    void testClear();
-    void testHideItem();
-    void testSystemItems();
-    void testEditBookmark();
-    void testEditAfterCreation();
-    void testEditMetadata();
-    void testRefresh();
-    void testIcons_data();
-    void testIcons();
-    void testDragAndDrop();
-    void testHideDevices();
-    void testDuplicatedEntries();
-    void renameAfterCreation();
-
-private:
-    PlacesItemModel* m_model;
-    QSet<int> m_tobeRemoved;
-    QMap<QString, QDBusInterface *> m_interfacesMap;
-    int m_expectedModelCount = 14;
-    bool m_hasDesktopFolder = false;
-    bool m_hasDocumentsFolder = false;
-    bool m_hasDownloadsFolder = false;
-    bool m_hasMusicFolder = false;
-    bool m_hasPicturesFolder = false;
-    bool m_hasVideosFolder = false;
-
-    void setBalooEnabled(bool enabled);
-    int indexOf(const QUrl &url);
-    QDBusInterface *fakeManager();
-    QDBusInterface *fakeDevice(const QString &udi);
-    QStringList placesUrls(PlacesItemModel *model = nullptr) const;
-    QStringList initialUrls() const;
-    void createPlaceItem(const QString &text, const QUrl &url, const QString &icon);
-    void schedulePlaceRemoval(int index);
-    void cancelPlaceRemoval(int index);
-    QMimeData *createMimeData(const QList<int> &indexes) const;
-    void increaseIndexIfNeeded(int &index) const;
-    QTemporaryDir m_tempHomeDir;
-};
-
-#define CHECK_PLACES_URLS(urls)                                             \
-    {                                                                       \
-        QStringList places = placesUrls();                                  \
-        if (places != urls) {                                               \
-            qWarning() << "Expected:" << urls;                              \
-            qWarning() << "Got:" << places;                                 \
-            QCOMPARE(places, urls);                                         \
-        }                                                                   \
-    }
-
-void PlacesItemModelTest::setBalooEnabled(bool enabled)
-{
-    KConfig config(QStringLiteral("baloofilerc"));
-    KConfigGroup basicSettings = config.group("Basic Settings");
-    basicSettings.writeEntry("Indexing-Enabled", enabled);
-    config.sync();
-}
-
-int PlacesItemModelTest::indexOf(const QUrl &url)
-{
-    for (int r = 0; r < m_model->count(); r++) {
-        if (m_model->placesItem(r)->url() == url) {
-            return r;
-        }
-    }
-    return -1;
-}
-
-QDBusInterface *PlacesItemModelTest::fakeManager()
-{
-    return fakeDevice(QStringLiteral("/org/kde/solid/fakehw"));
-}
-
-QDBusInterface *PlacesItemModelTest::fakeDevice(const QString &udi)
-{
-    if (m_interfacesMap.contains(udi)) {
-        return m_interfacesMap[udi];
-    }
-
-    QDBusInterface *iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), udi);
-    m_interfacesMap[udi] = iface;
-
-    return iface;
-}
-
-QStringList PlacesItemModelTest::placesUrls(PlacesItemModel *model) const
-{
-    QStringList urls;
-    if (!model) {
-        model = m_model;
-    }
-
-    for (int row = 0; row < model->count(); ++row) {
-        urls << model->placesItem(row)->url().toDisplayString(QUrl::PreferLocalFile);
-    }
-    return urls;
-}
-
-QStringList PlacesItemModelTest::initialUrls() const
-{
-    static QStringList urls;
-    if (urls.isEmpty()) {
-        urls << QDir::homePath();
-
-        if (m_hasDesktopFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Desktop");
-        }
-
-        if (m_hasDocumentsFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Documents");
-        }
-
-        if (m_hasDownloadsFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Downloads");
-        }
-
-        if (m_hasMusicFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Music");
-        }
-
-        if (m_hasPicturesFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Pictures");
-        }
-
-        if (m_hasVideosFolder) {
-            urls << QDir::homePath() + QStringLiteral("/Videos");
-        }
-
-        urls << QStringLiteral("trash:/")
-             << QStringLiteral("remote:/")
-             << QStringLiteral("/media/nfs");
-
-        if (qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) {
-            urls << QStringLiteral("recentlyused:/files");
-            urls << QStringLiteral("recentlyused:/locations");
-        } else {
-            urls << QStringLiteral("timeline:/today")
-                 << QStringLiteral("timeline:/yesterday");
-        }
-
-        urls << QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
-             << QStringLiteral("/foreign")
-             << QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom");
-    }
-    return urls;
-}
-
-void PlacesItemModelTest::createPlaceItem(const QString &text, const QUrl &url, const QString &icon)
-{
-    m_model->createPlacesItem(text, url, icon);
-}
-
-void PlacesItemModelTest::schedulePlaceRemoval(int index)
-{
-    m_tobeRemoved.insert(index);
-}
-
-void PlacesItemModelTest::cancelPlaceRemoval(int index)
-{
-    m_tobeRemoved.remove(index);
-}
-
-QMimeData *PlacesItemModelTest::createMimeData(const QList<int> &indexes) const
-{
-    QByteArray itemData;
-    QDataStream stream(&itemData, QIODevice::WriteOnly);
-    QList<QUrl> urls;
-
-    for (int index : indexes) {
-        const QUrl itemUrl = m_model->placesItem(index)->url();
-        if (itemUrl.isValid()) {
-            urls << itemUrl;
-        }
-        stream << index;
-    }
-
-    QMimeData* mimeData = new QMimeData();
-    mimeData->setUrls(urls);
-    // copied from PlacesItemModel::internalMimeType()
-    const QString internalMimeType = "application/x-dolphinplacesmodel-" +
-            QString::number((qptrdiff)m_model);
-    mimeData->setData(internalMimeType, itemData);
-    return mimeData;
-}
-
-void PlacesItemModelTest::increaseIndexIfNeeded(int &index) const
-{
-    if (m_hasDesktopFolder) {
-        index++;
-    }
-    if (m_hasDocumentsFolder) {
-        index++;
-    }
-    if (m_hasDownloadsFolder) {
-        index++;
-    }
-    if (m_hasMusicFolder) {
-        index++;
-    }
-    if (m_hasPicturesFolder) {
-        index++;
-    }
-    if (m_hasVideosFolder) {
-        index++;
-    }
-}
-
-void PlacesItemModelTest::init()
-{
-    m_model = new PlacesItemModel();
-    // WORKAROUND: need to wait for bookmark to load
-    QTest::qWait(300);
-    QCOMPARE(m_model->count(), m_expectedModelCount);
-}
-
-void PlacesItemModelTest::cleanup()
-{
-    const auto tobeRemoved = m_tobeRemoved;
-    for (const int i : tobeRemoved) {
-        int before = m_model->count();
-        m_model->deleteItem(i);
-        QTRY_COMPARE(m_model->count(), before - 1);
-    }
-    m_tobeRemoved.clear();
-    delete m_model;
-    m_model = nullptr;
-}
-
-void PlacesItemModelTest::initTestCase()
-{
-    QVERIFY(m_tempHomeDir.isValid());
-    QVERIFY(qputenv("HOME", m_tempHomeDir.path().toUtf8()));
-    QVERIFY(qputenv("KDE_FORK_SLAVES", "yes"));
-
-    QStandardPaths::setTestModeEnabled(true);
-
-    const QString fakeHw = QFINDTESTDATA("data/fakecomputer.xml");
-    QVERIFY(!fakeHw.isEmpty());
-    qputenv("SOLID_FAKEHW", QFile::encodeName(fakeHw));
-
-    setBalooEnabled(true);
-    const QString bookmarsFileName = bookmarksFile();
-    if (QFileInfo::exists(bookmarsFileName)) {
-        // Ensure we'll have a clean bookmark file to start
-        QVERIFY(QFile::remove(bookmarsFileName));
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).exists()) {
-        m_hasDesktopFolder = true;
-        m_expectedModelCount++;
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).exists()) {
-        m_hasDocumentsFolder = true;
-        m_expectedModelCount++;
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)).exists()) {
-        m_hasDownloadsFolder = true;
-        m_expectedModelCount++;
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::MusicLocation)).exists()) {
-        m_hasMusicFolder = true;
-        m_expectedModelCount++;
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)).exists()) {
-        m_hasPicturesFolder = true;
-        m_expectedModelCount++;
-    }
-
-    if (QDir(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).exists()) {
-        m_hasVideosFolder = true;
-        m_expectedModelCount++;
-    }
-
-    qRegisterMetaType<KItemRangeList>();
-    qRegisterMetaType<KItemRange>();
-}
-
-void PlacesItemModelTest::cleanupTestCase()
-{
-    qDeleteAll(m_interfacesMap);
-    QFile::remove(bookmarksFile());
-}
-
-void PlacesItemModelTest::testModelSort()
-{
-    CHECK_PLACES_URLS(initialUrls());
-}
-
-void PlacesItemModelTest::testGroups()
-{
-    const auto groups = m_model->groups();
-    int expectedRemoteIndex = 2;
-    increaseIndexIfNeeded(expectedRemoteIndex);
-
-    QCOMPARE(groups.size(), 6);
-
-    QCOMPARE(groups.at(0).first, 0);
-    QCOMPARE(groups.at(0).second.toString(), QStringLiteral("Places"));
-
-    QCOMPARE(groups.at(1).first, expectedRemoteIndex);
-    QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Remote"));
-
-    QCOMPARE(groups.at(2).first, expectedRemoteIndex + 2);
-    QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Recent"));
-
-    QCOMPARE(groups.at(3).first, expectedRemoteIndex + 4);
-    QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Search For"));
-
-    QCOMPARE(groups.at(4).first, expectedRemoteIndex + 8);
-    QCOMPARE(groups.at(4).second.toString(), QStringLiteral("Devices"));
-
-    QCOMPARE(groups.at(5).first, expectedRemoteIndex + 9);
-    QCOMPARE(groups.at(5).second.toString(), QStringLiteral("Removable Devices"));
-}
-
-void PlacesItemModelTest::testPlaceItem_data()
-{
-    QTest::addColumn<QUrl>("url");
-    QTest::addColumn<bool>("expectedIsHidden");
-    QTest::addColumn<bool>("expectedIsSystemItem");
-    QTest::addColumn<QString>("expectedGroup");
-    QTest::addColumn<bool>("expectedStorageSetupNeeded");
-
-    // places
-    QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << false << true << QStringLiteral("Places") << false;
-
-    // baloo -search
-    QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << QStringLiteral("Search For") << false;
-
-    // devices
-    QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << QStringLiteral("Removable Devices") << false;
-}
-
-void PlacesItemModelTest::testPlaceItem()
-{
-    QFETCH(QUrl, url);
-    QFETCH(bool, expectedIsHidden);
-    QFETCH(bool, expectedIsSystemItem);
-    QFETCH(QString, expectedGroup);
-    QFETCH(bool, expectedStorageSetupNeeded);
-
-    const int index = indexOf(url);
-    PlacesItem *item = m_model->placesItem(index);
-    QCOMPARE(item->url(), url);
-    QCOMPARE(item->isHidden(), expectedIsHidden);
-    QCOMPARE(item->isSystemItem(), expectedIsSystemItem);
-    QCOMPARE(item->group(), expectedGroup);
-    QCOMPARE(item->storageSetupNeeded(), expectedStorageSetupNeeded);
-}
-
-void PlacesItemModelTest::testDeletePlace()
-{
-    const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
-    QStringList urls = initialUrls();
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-    QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
-
-    PlacesItemModel *model = new PlacesItemModel();
-
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    // create a new place
-    createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
-    urls.insert(tempDirIndex, tempUrl.toLocalFile());
-
-    // check if the new entry was created
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-    CHECK_PLACES_URLS(urls);
-    QTRY_COMPARE(model->count(), m_model->count());
-
-    // delete item
-    m_model->deleteItem(tempDirIndex);
-
-    // make sure that the new item is removed
-    QTRY_COMPARE(itemsRemovedSpy.count(), 1);
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount);
-    CHECK_PLACES_URLS(initialUrls());
-    QTRY_COMPARE(model->count(), m_model->count());
-}
-
-void PlacesItemModelTest::testTearDownDevice()
-{
-    const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
-    int index = indexOf(mediaUrl);
-    QVERIFY(index != -1);
-
-    auto ejectAction = m_model->ejectAction(index);
-    QVERIFY(!ejectAction);
-
-    auto teardownAction = m_model->teardownAction(index);
-    QVERIFY(teardownAction);
-
-    QCOMPARE(m_model->count(), m_expectedModelCount);
-
-    QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
-    fakeManager()->call(QStringLiteral("unplug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount - 1);
-    QCOMPARE(spyItemsRemoved.count(), 1);
-    const QList<QVariant> spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
-    const KItemRangeList removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
-    QCOMPARE(removedRange.size(), 1);
-    QCOMPARE(removedRange.first().index, index);
-    QCOMPARE(removedRange.first().count, 1);
-
-    QCOMPARE(indexOf(mediaUrl), -1);
-
-    QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
-    fakeManager()->call(QStringLiteral("plug"), "/org/kde/solid/fakehw/volume_part1_size_993284096");
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount);
-    QCOMPARE(spyItemsInserted.count(), 1);
-    index = indexOf(mediaUrl);
-
-    const QList<QVariant> args = spyItemsInserted.takeFirst();
-    const KItemRangeList insertedRange = args.at(0).value<KItemRangeList>();
-    QCOMPARE(insertedRange.size(), 1);
-    QCOMPARE(insertedRange.first().index, index);
-    QCOMPARE(insertedRange.first().count, 1);
-}
-
-void PlacesItemModelTest::testDefaultViewProperties_data()
-{
-    QTest::addColumn<QUrl>("url");
-    QTest::addColumn<DolphinView::Mode>("expectedViewMode");
-    QTest::addColumn<bool>("expectedPreviewShow");
-    QTest::addColumn<QList<QByteArray> >("expectedVisibleRole");
-
-    // places
-    QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << DolphinView::IconsView << true << QList<QByteArray>({"text"});
-
-    // baloo -search
-    QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "path"});
-
-    // audio files
-    QTest::newRow("Places - Audio") << QUrl("search:/audio") << DolphinView::DetailsView << false << QList<QByteArray>({"text", "artist", "album"});
-
-    // devices
-    QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << DolphinView::IconsView << true << QList<QByteArray>({"text"});
-
-}
-
-void PlacesItemModelTest::testDefaultViewProperties()
-{
-    QFETCH(QUrl, url);
-    QFETCH(DolphinView::Mode, expectedViewMode);
-    QFETCH(bool, expectedPreviewShow);
-    QFETCH(QList<QByteArray>, expectedVisibleRole);
-
-    // In order to test the default view properties, turn off the global view properties and re-init the test to reload the model.
-    GeneralSettings* settings = GeneralSettings::self();
-    settings->setGlobalViewProps(false);
-    settings->save();
-    cleanup();
-    init();
-
-    ViewProperties properties(KFilePlacesModel::convertedUrl(url));
-    QCOMPARE(properties.viewMode(), expectedViewMode);
-    QCOMPARE(properties.previewsShown(), expectedPreviewShow);
-    QCOMPARE(properties.visibleRoles(), expectedVisibleRole);
-
-    settings->setGlobalViewProps(true);
-    settings->save();
-}
-
-void PlacesItemModelTest::testClear()
-{
-    QCOMPARE(m_model->count(), m_expectedModelCount);
-    m_model->clear();
-    QCOMPARE(m_model->count(), 0);
-    QCOMPARE(m_model->hiddenCount(), 0);
-    m_model->refresh();
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount);
-}
-
-void PlacesItemModelTest::testHideItem()
-{
-    const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
-    const int index = indexOf(mediaUrl);
-
-    PlacesItem *item = m_model->placesItem(index);
-
-    QSignalSpy spyItemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
-    QList<QVariant> spyItemsRemovedArgs;
-    KItemRangeList removedRange;
-
-    QSignalSpy spyItemsInserted(m_model, &PlacesItemModel::itemsInserted);
-    QList<QVariant> spyItemsInsertedArgs;
-    KItemRangeList insertedRange;
-    QVERIFY(item);
-
-    // hide an item
-    item->setHidden(true);
-
-    // check if items removed was fired
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount - 1);
-    QCOMPARE(spyItemsRemoved.count(), 1);
-    spyItemsRemovedArgs = spyItemsRemoved.takeFirst();
-    removedRange = spyItemsRemovedArgs.at(0).value<KItemRangeList>();
-    QCOMPARE(removedRange.size(), 1);
-    QCOMPARE(removedRange.first().index, index);
-    QCOMPARE(removedRange.first().count, 1);
-
-    // allow model to show hidden items
-    m_model->setHiddenItemsShown(true);
-
-    // check if the items inserted was fired
-    spyItemsInsertedArgs = spyItemsInserted.takeFirst();
-    insertedRange = spyItemsInsertedArgs.at(0).value<KItemRangeList>();
-    QCOMPARE(insertedRange.size(), 1);
-    QCOMPARE(insertedRange.first().index, index);
-    QCOMPARE(insertedRange.first().count, 1);
-
-    // mark item as visible
-    item = m_model->placesItem(index);
-    item->setHidden(false);
-
-     // mark model to hide invisible items
-    m_model->setHiddenItemsShown(true);
-
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount);
-}
-
-void PlacesItemModelTest::testSystemItems()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    QCOMPARE(m_model->count(), m_expectedModelCount);
-    for (int r = 0; r < m_model->count(); r++) {
-        QCOMPARE(m_model->placesItem(r)->isSystemItem(), !m_model->placesItem(r)->device().isValid());
-    }
-
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-
-    // create a new entry (non system item)
-    createPlaceItem(QStringLiteral("Temporary Dir"),  QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
-
-    // check if the new entry was created
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-
-    // make sure the new place get removed
-    schedulePlaceRemoval(tempDirIndex);
-
-    QList<QVariant> args = itemsInsertedSpy.takeFirst();
-    KItemRangeList range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.first().index, tempDirIndex);
-    QCOMPARE(range.first().count, 1);
-    QVERIFY(!m_model->placesItem(tempDirIndex)->isSystemItem());
-    QCOMPARE(m_model->count(), m_expectedModelCount + 1);
-
-    QTest::qWait(300);
-    // check if the removal signal is correct
-    QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
-    m_model->deleteItem(tempDirIndex);
-    QTRY_COMPARE(itemsRemovedSpy.count(), 1);
-    args = itemsRemovedSpy.takeFirst();
-    range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.first().index, tempDirIndex);
-    QCOMPARE(range.first().count, 1);
-    QTRY_COMPARE(m_model->count(), m_expectedModelCount);
-
-    //cancel removal (it was removed above)
-    cancelPlaceRemoval(tempDirIndex);
-}
-
-void PlacesItemModelTest::testEditBookmark()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    QScopedPointer<PlacesItemModel> other(new PlacesItemModel());
-
-    createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
-
-    // make sure that the new item will be removed later
-    schedulePlaceRemoval(tempDirIndex);
-
-    QSignalSpy itemsChangedSply(m_model, &PlacesItemModel::itemsChanged);
-
-    // modify place text
-    m_model->item(tempDirIndex)->setText(QStringLiteral("Renamed place"));
-    m_model->refresh();
-
-    // check if the correct signal was fired
-    QTRY_COMPARE(itemsChangedSply.count(), 1);
-    QList<QVariant> args = itemsChangedSply.takeFirst();
-    KItemRangeList range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.first().index, tempDirIndex);
-    QCOMPARE(range.first().count, 1);
-    QSet<QByteArray> roles = args.at(1).value<QSet<QByteArray> >();
-    QCOMPARE(roles.size(), 1);
-    QCOMPARE(*roles.begin(), QByteArrayLiteral("text"));
-    QCOMPARE(m_model->item(tempDirIndex)->text(), QStringLiteral("Renamed place"));
-
-    // check if the item was updated in the other model
-    QTRY_COMPARE(other->item(tempDirIndex)->text(), QStringLiteral("Renamed place"));
-}
-
-void PlacesItemModelTest::testEditAfterCreation()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-
-    // create a new place
-    createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-
-    PlacesItemModel *model = new PlacesItemModel();
-    QTRY_COMPARE(model->count(), m_model->count());
-
-    // make sure that the new item will be removed later
-    schedulePlaceRemoval(tempDirIndex);
-
-    // modify place text
-    PlacesItem *item = m_model->placesItem(tempDirIndex);
-    item->setText(QStringLiteral("Renamed place"));
-    m_model->refresh();
-
-    // check if the second model got the changes
-    QTRY_COMPARE(model->count(), m_model->count());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), m_model->placesItem(tempDirIndex)->text());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
-                 m_model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->icon(), m_model->placesItem(tempDirIndex)->icon());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->url(), m_model->placesItem(tempDirIndex)->url());
-}
-
-void PlacesItemModelTest::testEditMetadata()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-
-    // create a new place
-    createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-
-    // check if the new entry was created
-    PlacesItemModel *model = new PlacesItemModel();
-    QTRY_COMPARE(model->count(), m_model->count());
-
-    // make sure that the new item will be removed later
-    schedulePlaceRemoval(tempDirIndex);
-
-    // modify place metadata
-    auto bookmark = m_model->placesItem(tempDirIndex)->bookmark();
-    bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
-    m_model->refresh();
-
-    // check if the place was modified in both models
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
-                 KAboutData::applicationData().componentName());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), m_model->placesItem(tempDirIndex)->text());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
-                 m_model->placesItem(tempDirIndex)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->icon(), m_model->placesItem(tempDirIndex)->icon());
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->url(), m_model->placesItem(tempDirIndex)->url());
-}
-
-void PlacesItemModelTest::testRefresh()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-
-    // create a new place
-    createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-
-    PlacesItemModel *model = new PlacesItemModel();
-    QTRY_COMPARE(model->count(), m_model->count());
-
-    // make sure that the new item will be removed later
-    schedulePlaceRemoval(tempDirIndex);
-
-    PlacesItem *item = m_model->placesItem(tempDirIndex);
-    PlacesItem *sameItem = model->placesItem(tempDirIndex);
-    QCOMPARE(item->text(), sameItem->text());
-
-    // modify place text
-    item->setText(QStringLiteral("Renamed place"));
-
-    // item from another model is not affected at the moment
-    QVERIFY(item->text() != sameItem->text());
-
-    // propagate change
-    m_model->refresh();
-
-    // item must be equal
-    QTRY_COMPARE(item->text(), sameItem->text());
-}
-
-void PlacesItemModelTest::testIcons_data()
-{
-    QTest::addColumn<QUrl>("url");
-    QTest::addColumn<QString>("expectedIconName");
-
-    // places
-    QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << QStringLiteral("user-home");
-
-    // baloo -search
-    QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << QStringLiteral("folder-text");
-
-    // devices
-    QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << QStringLiteral("blockdevice");
-}
-
-void PlacesItemModelTest::testIcons()
-{
-    QFETCH(QUrl, url);
-    QFETCH(QString, expectedIconName);
-
-    PlacesItem *item = m_model->placesItem(indexOf(url));
-    QCOMPARE(item->icon(), expectedIconName);
-
-    for (int r = 0; r < m_model->count(); r++) {
-        QVERIFY(!m_model->placesItem(r)->icon().isEmpty());
-    }
-}
-
-void PlacesItemModelTest::testDragAndDrop()
-{
-    int lastIndex = 1; // last index of places group
-    increaseIndexIfNeeded(lastIndex);
-
-    QList<QVariant> args;
-    KItemRangeList range;
-    QStringList urls = initialUrls();
-
-    QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
-    QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
-
-    CHECK_PLACES_URLS(initialUrls());
-    // Move the home directory to the end of the places group
-    QMimeData *dropData = createMimeData(QList<int>() << 0);
-    m_model->dropMimeDataBefore(m_model->count() - 1, dropData);
-    urls.move(0, lastIndex);
-    delete dropData;
-
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-    QTRY_COMPARE(itemsRemovedSpy.count(), 1);
-
-    // remove item from actual position
-    args = itemsRemovedSpy.takeFirst();
-    range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.size(), 1);
-    QCOMPARE(range.at(0).count, 1);
-    QCOMPARE(range.at(0).index, 0);
-
-    // insert intem in his group
-    args = itemsInsertedSpy.takeFirst();
-    range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.size(), 1);
-    QCOMPARE(range.at(0).count, 1);
-    QCOMPARE(range.at(0).index, lastIndex);
-
-    CHECK_PLACES_URLS(urls);
-
-    itemsInsertedSpy.clear();
-    itemsRemovedSpy.clear();
-
-    // Move home directory item back to its original position
-    dropData = createMimeData(QList<int>() << lastIndex);
-    m_model->dropMimeDataBefore(0, dropData);
-    urls.move(lastIndex, 0);
-    delete dropData;
-
-    QTRY_COMPARE(itemsInsertedSpy.count(), 1);
-    QTRY_COMPARE(itemsRemovedSpy.count(), 1);
-
-    // remove item from actual position
-    args = itemsRemovedSpy.takeFirst();
-    range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.size(), 1);
-    QCOMPARE(range.at(0).count, 1);
-    QCOMPARE(range.at(0).index, lastIndex);
-
-    // insert intem in the requested position
-    args = itemsInsertedSpy.takeFirst();
-    range = args.at(0).value<KItemRangeList>();
-    QCOMPARE(range.size(), 1);
-    QCOMPARE(range.at(0).count, 1);
-    QCOMPARE(range.at(0).index, 0);
-
-    CHECK_PLACES_URLS(urls);
-}
-
-void PlacesItemModelTest::testHideDevices()
-{
-    QSignalSpy itemsRemoved(m_model, &PlacesItemModel::itemsRemoved);
-    QStringList urls = initialUrls();
-
-    m_model->setGroupHidden(KFilePlacesModel::RemovableDevicesType, true);
-    QTRY_VERIFY(m_model->isGroupHidden(KFilePlacesModel::RemovableDevicesType));
-    QTRY_COMPARE(itemsRemoved.count(), 3);
-
-    // remove removable-devices
-    urls.removeOne(QStringLiteral("/media/floppy0"));
-    urls.removeOne(QStringLiteral("/media/XO-Y4"));
-    urls.removeOne(QStringLiteral("/media/cdrom"));
-
-    // check if the correct urls was removed
-    CHECK_PLACES_URLS(urls);
-
-    delete m_model;
-    m_model = new PlacesItemModel();
-    QTRY_COMPARE(m_model->count(), urls.count());
-    CHECK_PLACES_URLS(urls);
-
-    // revert changes
-    m_model->setGroupHidden(KFilePlacesModel::RemovableDevicesType, false);
-    urls = initialUrls();
-    QTRY_COMPARE(m_model->count(), urls.count());
-    CHECK_PLACES_URLS(urls);
-}
-
-void PlacesItemModelTest::testDuplicatedEntries()
-{
-    QStringList urls = initialUrls();
-    // create a duplicated entry on bookmark
-    KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces"));
-    KBookmarkGroup root = bookmarkManager->root();
-    KBookmark bookmark = root.addBookmark(QStringLiteral("Duplicated Search Videos"), QUrl("search:/videos"), {});
-
-    const QString id = QUuid::createUuid().toString();
-    bookmark.setMetaDataItem(QStringLiteral("ID"), id);
-    bookmark.setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
-    bookmarkManager->emitChanged(bookmarkManager->root());
-
-    PlacesItemModel *newModel = new PlacesItemModel();
-    QTRY_COMPARE(placesUrls(newModel).count(QStringLiteral("search:/videos")), 1);
-    QTRY_COMPARE(urls, placesUrls(newModel));
-    delete newModel;
-}
-
-void PlacesItemModelTest::renameAfterCreation()
-{
-    int tempDirIndex = 2;
-    increaseIndexIfNeeded(tempDirIndex);
-
-    const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
-    QStringList urls = initialUrls();
-    PlacesItemModel *model = new PlacesItemModel();
-
-    CHECK_PLACES_URLS(urls);
-    QTRY_COMPARE(model->count(), m_model->count());
-
-    // create a new place
-    createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
-    urls.insert(tempDirIndex, tempUrl.toLocalFile());
-
-    // make sure that the new item will be removed later
-    schedulePlaceRemoval(tempDirIndex);
-
-    CHECK_PLACES_URLS(urls);
-    QCOMPARE(model->count(), m_model->count());
-
-
-    // modify place text
-    QSignalSpy changedSpy(m_model, &PlacesItemModel::itemsChanged);
-
-    PlacesItem *item = m_model->placesItem(tempDirIndex);
-    item->setText(QStringLiteral("New Temporary Dir"));
-    item->setUrl(item->url());
-    item->setIcon(item->icon());
-    m_model->refresh();
-
-    QTRY_COMPARE(changedSpy.count(), 1);
-
-    // check if the place was modified in both models
-    QTRY_COMPARE(m_model->placesItem(tempDirIndex)->text(), QStringLiteral("New Temporary Dir"));
-    QTRY_COMPARE(model->placesItem(tempDirIndex)->text(), QStringLiteral("New Temporary Dir"));
-}
-
-QTEST_MAIN(PlacesItemModelTest)
-
-#include "placesitemmodeltest.moc"