From 28daa45a44bc172747bad6d948de2a58c8586845 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Fri, 11 May 2012 23:00:26 +0200 Subject: [PATCH] Places Panel: Implement eject and teardown actions Further fixes: - Add/remove item when device has been added/removed - Update emblem if the accessibility-state has been changed --- src/CMakeLists.txt | 1 + src/panels/places/placesitem.cpp | 41 ++++++- src/panels/places/placesitem.h | 13 +++ src/panels/places/placesitemmodel.cpp | 110 +++++++++++++++--- src/panels/places/placesitemmodel.h | 10 +- .../placesitemstorageaccesslistener.cpp | 45 +++++++ .../places/placesitemstorageaccesslistener.h | 50 ++++++++ src/panels/places/placespanel.cpp | 18 +-- 8 files changed, 258 insertions(+), 30 deletions(-) create mode 100644 src/panels/places/placesitemstorageaccesslistener.cpp create mode 100644 src/panels/places/placesitemstorageaccesslistener.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c00d29c20..dfdde9ba0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -162,6 +162,7 @@ set(dolphin_SRCS panels/places/placesitemlistgroupheader.cpp panels/places/placesitemlistwidget.cpp panels/places/placesitemmodel.cpp + panels/places/placesitemstorageaccesslistener.cpp panels/panel.cpp panels/folders/treeviewcontextmenu.cpp panels/folders/folderspanel.cpp diff --git a/src/panels/places/placesitem.cpp b/src/panels/places/placesitem.cpp index 33af8a820..c865aa11d 100644 --- a/src/panels/places/placesitem.cpp +++ b/src/panels/places/placesitem.cpp @@ -25,10 +25,16 @@ #include #include #include +#include "placesitemstorageaccesslistener.h" #include PlacesItem::PlacesItem(PlacesItem* parent) : - KStandardItem(parent) + KStandardItem(parent), + m_device(), + m_access(), + m_volume(), + m_disc(), + m_accessListener(0) { } @@ -37,7 +43,8 @@ PlacesItem::PlacesItem(const KBookmark& bookmark, PlacesItem* parent) : m_device(), m_access(), m_volume(), - m_disc() + m_disc(), + m_accessListener(0) { setHidden(bookmark.metaDataItem("IsHidden") == QLatin1String("true")); @@ -58,7 +65,8 @@ PlacesItem::PlacesItem(const QString& udi, PlacesItem* parent) : m_device(), m_access(), m_volume(), - m_disc() + m_disc(), + m_accessListener(0) { initializeDevice(udi); } @@ -68,12 +76,15 @@ PlacesItem::PlacesItem(const PlacesItem& item) : m_device(), m_access(), m_volume(), - m_disc() + m_disc(), + m_accessListener(0) { } PlacesItem::~PlacesItem() { + delete m_accessListener; + m_accessListener = 0; } void PlacesItem::setUrl(const KUrl& url) @@ -86,6 +97,16 @@ KUrl PlacesItem::url() const return dataValue("url").value(); } +void PlacesItem::setUdi(const QString& udi) +{ + setDataValue("udi", udi); +} + +QString PlacesItem::udi() const +{ + return dataValue("udi").toString(); +} + void PlacesItem::setHidden(bool hidden) { setDataValue("isHidden", hidden); @@ -115,14 +136,24 @@ void PlacesItem::initializeDevice(const QString& udi) setText(m_device.description()); setIcon(m_device.icon()); setIconOverlays(m_device.emblems()); - setDataValue("udi", udi); + setUdi(udi); setGroup(i18nc("@item", "Devices")); if (m_access) { setUrl(m_access->filePath()); + + // The access listener takes care to call PlacesItem::onAccessibilityChanged() + // in case if the accessibility of m_access has been changed. + Q_ASSERT(!m_accessListener); + m_accessListener = new PlacesItemStorageAccessListener(this); } else if (m_disc && (m_disc->availableContent() & Solid::OpticalDisc::Audio) != 0) { const QString device = m_device.as()->device(); setUrl(QString("audiocd:/?device=%1").arg(device)); } } +void PlacesItem::onAccessibilityChanged() +{ + setIconOverlays(m_device.emblems()); +} + diff --git a/src/panels/places/placesitem.h b/src/panels/places/placesitem.h index 5c6988424..878d14a7d 100644 --- a/src/panels/places/placesitem.h +++ b/src/panels/places/placesitem.h @@ -29,6 +29,7 @@ #include class KBookmark; +class PlacesItemStorageAccessListener; /** * @brief Extends KStandardItem by places-specific properties. @@ -46,6 +47,9 @@ public: void setUrl(const KUrl& url); KUrl url() const; + void setUdi(const QString& udi); + QString udi() const; + void setHidden(bool hidden); bool isHidden() const; @@ -54,11 +58,20 @@ public: private: void initializeDevice(const QString& udi); + /** + * Is invoked by m_accessListener if the accessibility + * of the storage access m_access has been changed. + */ + void onAccessibilityChanged(); + private: Solid::Device m_device; QPointer m_access; QPointer m_volume; QPointer m_disc; + PlacesItemStorageAccessListener* m_accessListener; + + friend class PlacesItemStorageAccessListener; // Calls onAccessibilityChanged() }; #endif diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index 48f54b276..815338763 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -48,6 +48,10 @@ #include #include +#include +#include +#include +#include PlacesItemModel::PlacesItemModel(QObject* parent) : KStandardItemModel(parent), @@ -221,31 +225,82 @@ QAction* PlacesItemModel::ejectAction(int index) const return 0; } -QAction* PlacesItemModel::tearDownAction(int index) const +QAction* PlacesItemModel::teardownAction(int index) const { - // TODO: This is a dummy-implementation to have at least all - // translation-strings as part of the code before the freeze + const PlacesItem* item = placesItem(index); + if (!item) { + return 0; + } + + Solid::Device device = item->device(); + const bool providesTearDown = device.is() && + device.as()->isAccessible(); + if (!providesTearDown) { + return 0; + } + + Solid::StorageDrive* drive = device.as(); + if (!drive) { + drive = device.parent().as(); + } + + bool hotPluggable = false; + bool removable = false; + if (drive) { + hotPluggable = drive->isHotpluggable(); + removable = drive->isRemovable(); + } + QString iconName; QString text; - QString label; - switch (index) { - case 0: + const QString label = item->text(); + if (device.is()) { text = i18nc("@item", "Release '%1'", label); - break; - case 1: + } else if (removable || hotPluggable) { text = i18nc("@item", "Safely Remove '%1'", label); iconName = "media-eject"; - break; - case 2: + } else { text = i18nc("@item", "Unmount '%1'", label); iconName = "media-eject"; - break; - default: - break; } - //return new QAction(KIcon(iconName), text, 0); - return 0; + if (iconName.isEmpty()) { + return new QAction(text, 0); + } + + return new QAction(KIcon(iconName), text, 0); +} + +void PlacesItemModel::requestEject(int index) +{ + const PlacesItem* item = placesItem(index); + if (item) { + Solid::OpticalDrive* drive = item->device().parent().as(); + if (drive) { + connect(drive, SIGNAL(ejectDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant))); + drive->eject(); + } else { + + } + } +} + +void PlacesItemModel::requestTeardown(int index) +{ + const PlacesItem* item = placesItem(index); + if (item) { + Solid::StorageAccess* access = item->device().as(); + if (access) { + connect(access, SIGNAL(teardownDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(slotStorageTeardownDone(Solid::ErrorType,QVariant))); + access->teardown(); + } else { + const QString label = item->text(); + const QString message = i18nc("@info", "The device '%1' is not a disk and cannot be ejected.", label); + emit errorMessage(message); + } + } } void PlacesItemModel::onItemInserted(int index) @@ -283,12 +338,33 @@ void PlacesItemModel::onItemRemoved(int index) void PlacesItemModel::slotDeviceAdded(const QString& udi) { - Q_UNUSED(udi); + appendItem(new PlacesItem(udi)); } void PlacesItemModel::slotDeviceRemoved(const QString& udi) { - Q_UNUSED(udi); + for (int i = 0; i < m_hiddenItems.count(); ++i) { + PlacesItem* item = m_hiddenItems[i]; + if (item && item->udi() == udi) { + m_hiddenItems.removeAt(i); + delete item; + return; + } + } + + for (int i = 0; i < count(); ++i) { + if (placesItem(i)->udi() == udi) { + removeItem(i); + return; + } + } +} + +void PlacesItemModel::slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData) +{ + if (error && errorData.isValid()) { + emit errorMessage(errorData.toString()); + } } void PlacesItemModel::loadBookmarks() diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h index a50375a69..ae111a58d 100644 --- a/src/panels/places/placesitemmodel.h +++ b/src/panels/places/placesitemmodel.h @@ -29,6 +29,7 @@ #include #include #include +#include class KBookmarkManager; class PlacesItem; @@ -92,7 +93,13 @@ public: QString groupName(const KUrl& url) const; QAction* ejectAction(int index) const; - QAction* tearDownAction(int index) const; + QAction* teardownAction(int index) const; + + void requestEject(int index); + void requestTeardown(int index); + +signals: + void errorMessage(const QString& message); protected: virtual void onItemInserted(int index); @@ -101,6 +108,7 @@ protected: private slots: void slotDeviceAdded(const QString& udi); void slotDeviceRemoved(const QString& udi); + void slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData); private: void loadBookmarks(); diff --git a/src/panels/places/placesitemstorageaccesslistener.cpp b/src/panels/places/placesitemstorageaccesslistener.cpp new file mode 100644 index 000000000..26981f031 --- /dev/null +++ b/src/panels/places/placesitemstorageaccesslistener.cpp @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * 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 * + ***************************************************************************/ + +#include "placesitemstorageaccesslistener.h" + +#include "placesitem.h" +#include + +PlacesItemStorageAccessListener::PlacesItemStorageAccessListener(PlacesItem* item, + QObject* parent) : + QObject(parent), + m_item(item) +{ + if (item) { + connect(item->m_access, SIGNAL(accessibilityChanged(bool,QString)), + this, SLOT(onAccessibilityChanged())); + } +} + +PlacesItemStorageAccessListener::~PlacesItemStorageAccessListener() +{ +} + +void PlacesItemStorageAccessListener::slotOnAccessibilityChanged() +{ + m_item->onAccessibilityChanged(); +} + +#include "placesitemstorageaccesslistener.moc" diff --git a/src/panels/places/placesitemstorageaccesslistener.h b/src/panels/places/placesitemstorageaccesslistener.h new file mode 100644 index 000000000..46b943d67 --- /dev/null +++ b/src/panels/places/placesitemstorageaccesslistener.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * 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 * + ***************************************************************************/ + +#ifndef PLACESITEMSTORAGEACCESSLISTENER_H +#define PLACESITEMSTORAGEACCESSLISTENER_H + +#include + +class PlacesItem; + +/** + * @brief Helper class for PlacesItem to listen to accessibility changes + * of the storage access. + * + * Connects to the storage access from the given places item and + * calls PlacesItem::onAccessibilityChanged() in case if the accessibility + * has been changed. + */ +class PlacesItemStorageAccessListener: public QObject +{ + Q_OBJECT + +public: + explicit PlacesItemStorageAccessListener(PlacesItem* item, QObject* parent = 0); + virtual ~PlacesItemStorageAccessListener(); + +private slots: + void slotOnAccessibilityChanged(); + +private: + PlacesItem* m_item; +}; + +#endif diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp index 4fa1fa852..979ef25a6 100644 --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -76,6 +76,8 @@ void PlacesPanel::showEvent(QShowEvent* event) m_model = new PlacesItemModel(this); m_model->setGroupedSorting(true); m_model->setSortRole("group"); + connect(m_model, SIGNAL(errorMessage(QString)), + this, SIGNAL(errorMessage(QString))); KStandardItemListView* view = new KStandardItemListView(); view->setWidgetCreator(new KItemListWidgetCreator()); @@ -128,7 +130,7 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) QAction* addAction = 0; QAction* mainSeparator = 0; QAction* editAction = 0; - QAction* tearDownAction = 0; + QAction* teardownAction = 0; QAction* ejectAction = 0; const bool isSystemItem = m_model->isSystemItem(index); @@ -140,13 +142,13 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) menu.addAction(ejectAction); } - tearDownAction = m_model->tearDownAction(index); - if (tearDownAction) { - tearDownAction->setParent(&menu); - menu.addAction(tearDownAction); + teardownAction = m_model->teardownAction(index); + if (teardownAction) { + teardownAction->setParent(&menu); + menu.addAction(teardownAction); } - if (tearDownAction || ejectAction) { + if (teardownAction || ejectAction) { mainSeparator = menu.addSeparator(); } } else { @@ -209,8 +211,10 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) emit placeMiddleClicked(url); } else if (action == showAllAction) { m_model->setHiddenItemsShown(showAllAction->isChecked()); - } else if (action == tearDownAction) { + } else if (action == teardownAction) { + m_model->requestTeardown(index); } else if (action == ejectAction) { + m_model->requestEject(index); } } -- 2.47.3