-/***************************************************************************
- * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * Based on KFilePlacesModel from kdelibs: *
- * Copyright (C) 2007 Kevin Ottens <ervin@kde.org> *
- * Copyright (C) 2007 David Faure <faure@kde.org> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
- ***************************************************************************/
+/*
+ * 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 "placesitemsignalhandler.h"
#include "dolphin_generalsettings.h"
-
-#include <KBookmark>
-#include <KBookmarkManager>
#include "dolphindebug.h"
-#include <QIcon>
-#include <KProtocolInfo>
-#include <KLocalizedString>
-#include <QStandardPaths>
-#include <KAboutData>
+#include "dolphinplacesmodelsingleton.h"
#include "placesitem.h"
-#include <QAction>
-#include <QDate>
-#include <QMimeData>
-#include <QTimer>
-#include <KUrlMimeData>
-#include <KFilePlacesModel>
+#include "placesitemsignalhandler.h"
+#include "views/dolphinview.h"
+#include "views/viewproperties.h"
-#include <Solid/Device>
+#include <KAboutData>
+#include <KLocalizedString>
+#include <KUrlMimeData>
#include <Solid/DeviceNotifier>
-#include <Solid/OpticalDisc>
#include <Solid/OpticalDrive>
-#include <Solid/StorageAccess>
-#include <Solid/StorageDrive>
-
-#include <views/dolphinview.h>
-#include <views/viewproperties.h>
+#include <KCoreAddons/KProcessList>
+#include <KCoreAddons/KListOpenFilesJob>
-namespace {
- // A suffix to the application-name of the stored bookmarks is
- // added, which is only read by PlacesItemModel.
- const QString AppNameSuffix = QStringLiteral("-places-panel");
- static QList<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"))
- };
-}
+#include <QAction>
+#include <QIcon>
+#include <QMimeData>
+#include <QTimer>
PlacesItemModel::PlacesItemModel(QObject* parent) :
KStandardItemModel(parent),
m_hiddenItemsShown(false),
m_deviceToTearDown(nullptr),
m_storageSetupInProgress(),
- m_sourceModel(new KFilePlacesModel(KAboutData::applicationData().componentName() + AppNameSuffix, this))
+ m_sourceModel(DolphinPlacesModelSingleton::instance().placesModel())
{
cleanupBookmarks();
loadBookmarks();
initializeDefaultViewProperties();
- connect(m_sourceModel.data(), &KFilePlacesModel::rowsInserted, this, &PlacesItemModel::onSourceModelRowsInserted);
- connect(m_sourceModel.data(), &KFilePlacesModel::rowsAboutToBeRemoved, this, &PlacesItemModel::onSourceModelRowsAboutToBeRemoved);
- connect(m_sourceModel.data(), &KFilePlacesModel::dataChanged, this, &PlacesItemModel::onSourceModelDataChanged);
- connect(m_sourceModel.data(), &KFilePlacesModel::rowsAboutToBeMoved, this, &PlacesItemModel::onSourceModelRowsAboutToBeMoved);
- connect(m_sourceModel.data(), &KFilePlacesModel::rowsMoved, this, &PlacesItemModel::onSourceModelRowsMoved);
- connect(m_sourceModel.data(), &KFilePlacesModel::groupHiddenChanged, this, &PlacesItemModel::onSourceModelGroupHiddenChanged);
+ 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,
- int after)
+void PlacesItemModel::createPlacesItem(const QString &text, const QUrl &url, const QString &iconName, const QString &appName)
{
- m_sourceModel->addPlace(text, url, iconName, {}, mapToSource(after));
+ 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
}
}
}
-
-#ifdef PLACESITEMMODEL_DEBUG
- qCDebug(DolphinDebug) << "Changed visibility of hidden items";
- showModelState();
-#endif
}
bool PlacesItemModel::hiddenItemsShown() const
void PlacesItemModel::onItemInserted(int index)
{
KStandardItemModel::onItemInserted(index);
-#ifdef PLACESITEMMODEL_DEBUG
- qCDebug(DolphinDebug) << "Inserted item" << index;
- showModelState();
-#endif
}
void PlacesItemModel::onItemRemoved(int index, KStandardItem* removedItem)
m_indexMap.removeAt(index);
KStandardItemModel::onItemRemoved(index, removedItem);
-#ifdef PLACESITEMMODEL_DEBUG
- qCDebug(DolphinDebug) << "Removed item" << index;
- showModelState();
-#endif
}
void PlacesItemModel::onItemChanged(int index, const QSet<QByteArray>& changedRoles)
int oldIndex;
stream >> oldIndex;
- m_sourceModel->movePlace(oldIndex, index);
+ 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);
continue;
}
- createPlacesItem(text, url, KIO::iconNameForUrl(url), qMax(0, index - 1));
+ 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
const KBookmark bookmark = m_sourceModel->bookmarkForIndex(index);
Q_ASSERT(!bookmark.isNull());
- PlacesItem *item = itemFromBookmark(bookmark);
- if (!item) {
- item = new PlacesItem(bookmark);
- }
+ PlacesItem *item = new PlacesItem(bookmark);
updateItem(item, index);
insertSortedItem(item);
} else if (path == QLatin1String("/images")) {
props.setViewMode(DolphinView::IconsView);
props.setPreviewsShown(true);
- props.setVisibleRoles({"text", "imageSize"});
+ props.setVisibleRoles({"text", "height", "width"});
} else if (path == QLatin1String("/audio")) {
props.setViewMode(DolphinView::DetailsView);
props.setPreviewsShown(false);
void PlacesItemModel::slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData)
{
if (error && errorData.isValid()) {
- emit errorMessage(errorData.toString());
+ 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", ", ")));
+ }
+ emit errorMessage(errorString);
+ });
+ listOpenFilesJob->start();
+ } else {
+ emit errorMessage(errorData.toString());
+ }
}
- m_deviceToTearDown->disconnect();
+ disconnect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone,
+ this, &PlacesItemModel::slotStorageTearDownDone);
m_deviceToTearDown = nullptr;
}
const QVariant& errorData,
const QString& udi)
{
- Q_UNUSED(udi);
+ Q_UNUSED(udi)
const int index = m_storageSetupInProgress.take(sender());
const PlacesItem* item = placesItem(index);
void PlacesItemModel::onSourceModelRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
{
- Q_UNUSED(destination);
- Q_UNUSED(row);
+ Q_UNUSED(destination)
+ Q_UNUSED(row)
for(int r = start; r <= end; r++) {
const QModelIndex sourceIndex = m_sourceModel->index(r, 0, parent);
void PlacesItemModel::onSourceModelRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
{
- Q_UNUSED(destination);
- Q_UNUSED(parent);
+ Q_UNUSED(destination)
+ Q_UNUSED(parent)
const int blockSize = (end - start) + 1;
void PlacesItemModel::onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
- Q_UNUSED(roles);
+ Q_UNUSED(roles)
for (int r = topLeft.row(); r <= bottomRight.row(); r++) {
const QModelIndex sourceIndex = m_sourceModel->index(r, 0);
}
if (placeItem && !m_sourceModel->isDevice(sourceIndex)) {
- placeItem->setText(bookmark.text());
- placeItem->setIcon(sourceIndex.data(KFilePlacesModel::IconNameRole).toString());
- placeItem->setUrl(m_sourceModel->url(sourceIndex));
- placeItem->bookmark().setMetaDataItem(QStringLiteral("OnlyInApp"),
- bookmark.metaDataItem(QStringLiteral("OnlyInApp")));
// must update the bookmark object
placeItem->setBookmark(bookmark);
}
void PlacesItemModel::onSourceModelGroupHiddenChanged(KFilePlacesModel::GroupType group, bool hidden)
{
- for(const QModelIndex &sourceIndex : m_sourceModel->groupIndexes(group)) {
+ const auto groupIndexes = m_sourceModel->groupIndexes(group);
+ for (const QModelIndex &sourceIndex : groupIndexes) {
PlacesItem *item = placesItem(mapFromSource(sourceIndex));
if (item) {
item->setGroupHidden(hidden);
{
// 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 QString appName = bookmark.metaDataItem(QStringLiteral("OnlyInApp"));
if ((appName == KAboutData::applicationData().componentName() ||
- appName == KAboutData::applicationData().componentName() + AppNameSuffix) && balooURLs.contains(url)) {
+ appName == KAboutData::applicationData().componentName() + DolphinPlacesModelSingleton::applicationNameSuffix()) && balooURLs.contains(url)) {
qCDebug(DolphinDebug) << "Removing old baloo url:" << url;
m_sourceModel->removePlace(sourceIndex);
} else {
addItemFromSourceModel(sourceIndex);
}
}
-
-#ifdef PLACESITEMMODEL_DEBUG
- qCDebug(DolphinDebug) << "Loaded bookmarks";
- showModelState();
-#endif
}
void PlacesItemModel::clear() {
bool PlacesItemModel::isDir(int index) const
{
- Q_UNUSED(index);
+ Q_UNUSED(index)
return true;
}
return nullptr;
}
-#ifdef PLACESITEMMODEL_DEBUG
-void PlacesItemModel::showModelState()
-{
- qCDebug(DolphinDebug) << "=================================";
- qCDebug(DolphinDebug) << "Model:";
- qCDebug(DolphinDebug) << "hidden-index model-index text";
- int modelIndex = 0;
- for (int i = 0; i < m_bookmarkedItems.count(); ++i) {
- if (m_bookmarkedItems[i]) {
- qCDebug(DolphinDebug) << i << "(Hidden) " << " " << m_bookmarkedItems[i]->dataValue("text").toString();
- } else {
- if (item(modelIndex)) {
- qCDebug(DolphinDebug) << i << " " << modelIndex << " " << item(modelIndex)->dataValue("text").toString();
- } else {
- qCDebug(DolphinDebug) << i << " " << modelIndex << " " << "(not available yet)";
- }
- ++modelIndex;
- }
- }
-
- qCDebug(DolphinDebug);
- qCDebug(DolphinDebug) << "Bookmarks:";
-
- int bookmarkIndex = 0;
- KBookmarkGroup root = m_bookmarkManager->root();
- KBookmark bookmark = root.first();
- while (!bookmark.isNull()) {
- const QString udi = bookmark.metaDataItem("UDI");
- const QString text = udi.isEmpty() ? bookmark.text() : udi;
- if (bookmark.metaDataItem("IsHidden") == QLatin1String("true")) {
- qCDebug(DolphinDebug) << bookmarkIndex << "(Hidden)" << text;
- } else {
- qCDebug(DolphinDebug) << bookmarkIndex << " " << text;
- }
-
- bookmark = root.next(bookmark);
- ++bookmarkIndex;
- }
-}
-#endif
-