X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/b5df5f4d9581b314f1fc2d6c15b4f01de9f5204b..4cbeb81b2b8e2d37c93cda4d88787e08e0658291:/src/panels/places/placespanel.cpp diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp index c18c54d1d..8bdb18ba2 100644 --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -1,561 +1,289 @@ -/*************************************************************************** - * Copyright (C) 2008-2012 by Peter Penz * - * * - * Based on KFilePlacesView from kdelibs: * - * Copyright (C) 2007 Kevin Ottens * - * Copyright (C) 2007 David Faure * - * * - * 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: 2008-2012 Peter Penz + * SPDX-FileCopyrightText: 2021 Kai Uwe Broulik + * + * Based on KFilePlacesView from kdelibs: + * SPDX-FileCopyrightText: 2007 Kevin Ottens + * SPDX-FileCopyrightText: 2007 David Faure + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "placespanel.h" #include "dolphin_generalsettings.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 "dolphin_placespanelsettings.h" +#include "dolphinplacesmodelsingleton.h" +#include "settings/dolphinsettingsdialog.h" #include "views/draganddrophelper.h" -#include #include #include -#include #include -#include #include -#include -#include +#include -#include #include #include #include -#include - -PlacesPanel::PlacesPanel(QWidget* parent) : - Panel(parent), - m_controller(nullptr), - m_model(nullptr), - m_view(nullptr), - m_storageSetupFailedUrl(), - m_triggerStorageSetupButton(), - m_itemDropEventIndex(-1), - m_itemDropEventMimeData(nullptr), - m_itemDropEvent(nullptr) -{ -} +#include -PlacesPanel::~PlacesPanel() -{ -} +#include -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(QStringLiteral("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) { - selectClosestItem(); - } - - return true; -} - -void PlacesPanel::readSettings() -{ - if (m_controller) { - const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1; - m_controller->setAutoActivationDelay(delay); - } -} - -void PlacesPanel::showEvent(QShowEvent* event) -{ - if (event->spontaneous()) { - Panel::showEvent(event); - return; - } + setTeardownFunction([this](const QModelIndex &index) { + slotTearDownRequested(index); + }); - 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); - - m_view = new PlacesView(); - m_view->setWidgetCreator(new KItemListWidgetCreator()); - m_view->setGroupHeaderCreator(new KItemListGroupHeaderCreator()); - - m_controller = new KItemListController(m_model, m_view, this); - m_controller->setSelectionBehavior(KItemListController::SingleSelection); - m_controller->setSingleClickActivationEnforced(true); + 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); - readSettings(); + m_openInSplitView = new QAction(QIcon::fromTheme(QStringLiteral("view-right-new")), i18nc("@action:inmenu", "Open in Split View")); + m_openInSplitView->setPriority(QAction::HighPriority); + connect(m_openInSplitView, &QAction::triggered, this, [this]() { + const QUrl url = currentIndex().data(KFilePlacesModel::UrlRole).toUrl(); + Q_EMIT openInSplitViewRequested(url); + }); - 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); + addAction(m_openInSplitView); - KItemListContainer* container = new KItemListContainer(m_controller, this); - container->setEnabledFrame(false); + connect(this, &PlacesPanel::contextMenuAboutToShow, this, &PlacesPanel::slotContextMenuAboutToShow); - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setMargin(0); - layout->addWidget(container); + connect(this, &PlacesPanel::iconSizeChanged, 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(); + }); +} - selectClosestItem(); - } +PlacesPanel::~PlacesPanel() = default; - Panel::showEvent(event); +void PlacesPanel::setUrl(const QUrl &url) +{ + // 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::slotItemActivated(int index) +QList PlacesPanel::customContextMenuActions() const { - triggerItem(index, Qt::LeftButton); + return m_customContextMenuActions; } -void PlacesPanel::slotItemMiddleClicked(int index) +void PlacesPanel::setCustomContextMenuActions(const QList &actions) { - triggerItem(index, Qt::MiddleButton); + m_customContextMenuActions = actions; } -void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) +void PlacesPanel::proceedWithTearDown() { - PlacesItem* item = m_model->placesItem(index); - if (!item) { - return; - } - - QMenu menu(this); - - QAction* emptyTrashAction = 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 (isDevice) { - ejectAction = m_model->ejectAction(index); - if (ejectAction) { - ejectAction->setParent(&menu); - menu.addAction(ejectAction); - } - - 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); - - teardownAction->setParent(&menu); - menu.addAction(teardownAction); - } - - if (item->storageSetupNeeded()) { - mountAction = menu.addAction(QIcon::fromTheme(QStringLiteral("media-mount")), i18nc("@action:inmenu", "Mount")); - } - - if (teardownAction || ejectAction || mountAction) { - menu.addSeparator(); - } + if (m_indexToTearDown.isValid()) { + auto *placesModel = static_cast(model()); + placesModel->requestTeardown(m_indexToTearDown); } else { - 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* openInNewWindowAction = menu.addAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("@item:inmenu", "Open in New Window")); - QAction* openInNewTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@item:inmenu", "Open in New Tab")); - QAction* propertiesAction = nullptr; - if (item->url().isLocalFile()) { - propertiesAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action:inmenu", "Properties")); - } - if (!isDevice && !isTrash) { - menu.addSeparator(); - } - - 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("hint")), 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 { - // 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 does set up the storage first and then it will - // emit the slotItemMiddleClicked signal, because of Qt::MiddleButton. - triggerItem(index, Qt::MiddleButton); - } 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(); - } - } + qWarning() << "Places entry to tear down is no longer valid"; } - - selectClosestItem(); } -void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos) +void PlacesPanel::readSettings() { - 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("visibility") : QStringLiteral("hint"))); - 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, I18N_NOOP2_NOSTRIP("Small icon size", "Small (%1x%2)")}, - {KIconLoader::SizeSmallMedium, I18N_NOOP2_NOSTRIP("Medium icon size", "Medium (%1x%2)")}, - {KIconLoader::SizeMedium, I18N_NOOP2_NOSTRIP("Large icon size", "Large (%1x%2)")}, - {KIconLoader::SizeLarge, I18N_NOOP2_NOSTRIP("Huge icon size", "Huge (%1x%2)")} - }; - - QHash 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); - } - - menu.addMenu(iconSizeSubMenu); - - menu.addSeparator(); - foreach (QAction* action, customContextMenuActions()) { - menu.addAction(action); - } - - 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)); - } + if (GeneralSettings::autoExpandFolders()) { + setDragAutoActivationDelay(750); + } else { + setDragAutoActivationDelay(0); } - selectClosestItem(); + const int iconSize = qMax(0, PlacesPanelSettings::iconSize()); + setIconSize(QSize(iconSize, iconSize)); } -QAction *PlacesPanel::buildGroupContextMenu(QMenu *menu, int index) +void PlacesPanel::showEvent(QShowEvent *event) { - if (index == -1) { - return nullptr; - } + if (!event->spontaneous() && !model()) { + readSettings(); - KFilePlacesModel::GroupType groupType = m_model->groupType(index); - QAction *hideGroupAction = menu->addAction(QIcon::fromTheme(QStringLiteral("hint")), i18nc("@item:inmenu", "Hide Section '%1'", m_model->item(index)->group())); - hideGroupAction->setCheckable(true); - hideGroupAction->setChecked(m_model->isGroupHidden(groupType)); + auto *placesModel = DolphinPlacesModelSingleton::instance().placesModel(); + setModel(placesModel); - connect(hideGroupAction, &QAction::triggered, this, [this, groupType, hideGroupAction]{ - m_model->setGroupHidden(groupType, hideGroupAction->isChecked()); - if (!m_model->hiddenCount()) { - showHiddenEntries(false); - } - }); + connect(placesModel, &KFilePlacesModel::errorMessage, this, &PlacesPanel::errorMessage); + connect(placesModel, &KFilePlacesModel::teardownDone, this, &PlacesPanel::slotTearDownDone); - return hideGroupAction; -} + connect(placesModel, &QAbstractItemModel::rowsInserted, this, &PlacesPanel::slotRowsInserted); + connect(placesModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &PlacesPanel::slotRowsAboutToBeRemoved); -void PlacesPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event) -{ - if (index < 0) { - return; - } - - const PlacesItem* destItem = m_model->placesItem(index); + for (int i = 0; i < model()->rowCount(); ++i) { + connectDeviceSignals(model()->index(i, 0, QModelIndex())); + } - if (destItem->isSearchOrTimelineUrl()) { - return; + setUrl(m_url); } - 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()); + KFilePlacesView::showEvent(event); +} - m_model->requestStorageSetup(index); - return; +static bool isInternalDrag(const QMimeData *mimeData) +{ + const auto formats = mimeData->formats(); + for (const auto &format : formats) { + // from KFilePlacesModel::_k_internalMimetype + if (format.startsWith(QLatin1String("application/x-kfileplacesmodel-"))) { + return true; + } } - - QUrl destUrl = destItem->url(); - QDropEvent dropEvent(event->pos().toPoint(), - event->possibleActions(), - event->mimeData(), - event->buttons(), - event->modifiers()); - - slotUrlsDropped(destUrl, &dropEvent, this); + return false; } -void PlacesPanel::slotItemDropEventStorageSetupDone(int index, bool success) +void PlacesPanel::dragMoveEvent(QDragMoveEvent *event) { - disconnect(m_model, &PlacesItemModel::storageSetupDone, - this, &PlacesPanel::slotItemDropEventStorageSetupDone); - - if ((index == m_itemDropEventIndex) && m_itemDropEvent && m_itemDropEventMimeData) { - if (success) { - QUrl destUrl = m_model->placesItem(index)->url(); - slotUrlsDropped(destUrl, m_itemDropEvent, this); + const QModelIndex index = indexAt(event->position().toPoint()); + if (index.isValid()) { + auto *placesModel = static_cast(model()); + + // Reject drag ontop of a non-writable protocol + // We don't know whether we're dropping inbetween or ontop of a place + // so still allow internal drag events so that re-arranging still works. + const QUrl url = placesModel->url(index); + if (url.isValid() && !isInternalDrag(event->mimeData()) && !KProtocolManager::supportsWriting(url)) { + event->setDropAction(Qt::IgnoreAction); } - - delete m_itemDropEventMimeData; - delete m_itemDropEvent; - - m_itemDropEventIndex = -1; - m_itemDropEventMimeData = nullptr; - m_itemDropEvent = nullptr; } + + KFilePlacesView::dragMoveEvent(event); } -void PlacesPanel::slotAboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event) +void PlacesPanel::slotConfigureTrash() { - m_model->dropMimeDataBefore(index, event->mimeData()); + const QUrl url = currentIndex().data(KFilePlacesModel::UrlRole).toUrl(); + + DolphinSettingsDialog *settingsDialog = new DolphinSettingsDialog(url, this); + settingsDialog->setCurrentPage(settingsDialog->trashSettings); + settingsDialog->setAttribute(Qt::WA_DeleteOnClose); + settingsDialog->show(); } -void PlacesPanel::slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget* parent) +void PlacesPanel::slotUrlsDropped(const QUrl &dest, QDropEvent *event, QWidget *parent) { KIO::DropJob *job = DragAndDropHelper::dropUrls(dest, event, parent); if (job) { - connect(job, &KIO::DropJob::result, this, [this](KJob *job) { if (job->error()) emit errorMessage(job->errorString()); }); + connect(job, &KIO::DropJob::result, this, [this](KJob *job) { + if (job->error() && job->error() != KIO::ERR_USER_CANCELED) { + Q_EMIT errorMessage(job->errorString()); + } + }); } } -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_triggerStorageSetupButton == Qt::NoButton) { - return; - } + auto *placesModel = static_cast(model()); + const QUrl url = placesModel->url(index); + const Solid::Device device = placesModel->deviceForIndex(index); + + m_configureTrashAction->setVisible(url.scheme() == QLatin1String("trash")); + m_openInSplitView->setVisible(url.isValid()); - if (success) { - Q_ASSERT(!m_model->storageSetupNeeded(index)); - triggerItem(index, m_triggerStorageSetupButton); - m_triggerStorageSetupButton = Qt::NoButton; + // 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::addEntry() +void PlacesPanel::slotTearDownRequested(const QModelIndex &index) { - 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 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); + auto *placesModel = static_cast(model()); + + Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as(); + if (!storageAccess) { + return; } - delete dialog; + m_indexToTearDown = QPersistentModelIndex(index); + + // 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 data = m_model->data(index); - const QUrl url = m_model->data(index).value("url").toUrl(); - const QString text = m_model->data(index).value("text").toString(); - const bool applicationLocal = !m_model->data(index).value("applicationName").toString().isEmpty(); - - QPointer dialog = new KFilePlaceEditDialog(true, url, text, QString(), 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(sender()); - delete dialog; + Q_EMIT storageTearDownExternallyRequested(storageAccess->filePath()); } -void PlacesPanel::selectClosestItem() +void PlacesPanel::slotTearDownDone(const QModelIndex &index, Solid::ErrorType error, const QVariant &errorData) { - const int index = m_model->closestItem(url()); - KItemListSelectionManager* selectionManager = m_controller->selectionManager(); - selectionManager->setCurrentItem(index); - selectionManager->clearSelection(); - selectionManager->setSelected(index); + Q_UNUSED(errorData); // All error handling is currently done in frameworks. + + if (index == m_indexToTearDown) { + if (error == Solid::ErrorType::NoError) { + // No error; it must have been unmounted successfully + Q_EMIT storageTearDownSuccessful(); + } + m_indexToTearDown = QPersistentModelIndex(); + } } -void PlacesPanel::triggerItem(int index, Qt::MouseButton button) +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_triggerStorageSetupButton = button; - m_storageSetupFailedUrl = url(); +void PlacesPanel::slotRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) +{ + auto *placesModel = static_cast(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_triggerStorageSetupButton = Qt::NoButton; - - const QUrl url = m_model->data(index).value("url").toUrl(); - if (!url.isEmpty()) { - if (button == Qt::MiddleButton) { - emit placeMiddleClicked(KFilePlacesModel::convertedUrl(url)); - } else { - emit placeActivated(KFilePlacesModel::convertedUrl(url)); - } + Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as(); + 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); - emit showHiddenEntriesChanged(shown); -} + auto *placesModel = static_cast(model()); -int PlacesPanel::hiddenListCount() -{ - if(!m_model) { - return 0; + Solid::StorageAccess *storageAccess = placesModel->deviceForIndex(index).as(); + if (!storageAccess) { + return; } - return m_model->hiddenCount(); + + connect(storageAccess, &Solid::StorageAccess::teardownRequested, this, &PlacesPanel::slotTearDownRequestedExternally); } + +#include "moc_placespanel.cpp"