]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Allow to configure thumbnail-plugins
authorPeter Penz <peter.penz19@gmail.com>
Fri, 25 Feb 2011 19:39:18 +0000 (20:39 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Sun, 27 Feb 2011 19:38:35 +0000 (20:38 +0100)
Adjust the preview-settings to allow users to configure thumbnail-plugins. For consistency also the service-settings have been adjusted to use the ServiceModel and ServiceItemDelegate.

src/CMakeLists.txt
src/settings/general/configurepreviewplugindialog.cpp [new file with mode: 0644]
src/settings/general/configurepreviewplugindialog.h [new file with mode: 0644]
src/settings/general/previewssettingspage.cpp
src/settings/general/previewssettingspage.h
src/settings/serviceitemdelegate.cpp [new file with mode: 0644]
src/settings/serviceitemdelegate.h [new file with mode: 0644]
src/settings/servicemodel.cpp [new file with mode: 0644]
src/settings/servicemodel.h [new file with mode: 0644]
src/settings/services/servicessettingspage.cpp
src/settings/services/servicessettingspage.h

index 61caec60d081f953320f2e914f2f4e458d552ab3..a06549593039bdb0e62ddf2d7fff9eb22e860a96 100644 (file)
@@ -116,6 +116,7 @@ set(dolphin_SRCS
     search/dolphinsearchbox.cpp
     search/dolphinsearchinformation.cpp
     settings/general/behaviorsettingspage.cpp
+    settings/general/configurepreviewplugindialog.cpp
     settings/general/contextmenusettingspage.cpp
     settings/general/generalsettingspage.cpp
     settings/general/previewssettingspage.cpp
@@ -124,6 +125,8 @@ set(dolphin_SRCS
     settings/navigation/navigationsettingspage.cpp
     settings/services/servicessettingspage.cpp
     settings/settingspagebase.cpp
+    settings/serviceitemdelegate.cpp
+    settings/servicemodel.cpp
     settings/startup/startupsettingspage.cpp
     settings/trash/trashsettingspage.cpp
     settings/viewmodes/columnviewsettingspage.cpp
@@ -210,14 +213,19 @@ set(kcm_dolphinnavigation_PART_SRCS
 set(kcm_dolphinservices_PART_SRCS
     settings/kcm/kcmdolphinservices.cpp
     settings/services/servicessettingspage.cpp
-    settings/settingspagebase.cpp)
+    settings/settingspagebase.cpp
+    settings/serviceitemdelegate.cpp
+    settings/servicemodel.cpp)
 
 set(kcm_dolphingeneral_PART_SRCS
     settings/kcm/kcmdolphingeneral.cpp
     settings/general/behaviorsettingspage.cpp
     settings/general/previewssettingspage.cpp
+    settings/general/configurepreviewplugindialog.cpp
     settings/general/contextmenusettingspage.cpp
-    settings/settingspagebase.cpp)
+    settings/settingspagebase.cpp
+    settings/serviceitemdelegate.cpp
+    settings/servicemodel.cpp)
 
 kde4_add_kcfg_files(kcm_dolphinviewmodes_PART_SRCS
     settings/dolphin_columnmodesettings.kcfgc
diff --git a/src/settings/general/configurepreviewplugindialog.cpp b/src/settings/general/configurepreviewplugindialog.cpp
new file mode 100644 (file)
index 0000000..c1a507a
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 "configurepreviewplugindialog.h"
+
+#include <KLibrary>
+#include <KLocale>
+#include <KIO/NetAccess>
+#include <kio/thumbcreator.h>
+
+#include <QApplication>
+#include <QDir>
+#include <QVBoxLayout>
+
+ConfigurePreviewPluginDialog::ConfigurePreviewPluginDialog(const QString& pluginName,
+                                                           const QString& desktopEntryName,
+                                                           QWidget* parent) :
+    KDialog(parent),
+    m_configurationWidget(0),
+    m_previewPlugin(0)
+{
+    KLibrary library(desktopEntryName);
+    if (library.load()) {
+        newCreator create = (newCreator)library.resolveFunction("new_creator");
+        if (create) {
+            m_previewPlugin = dynamic_cast<ThumbCreatorV2*>(create());
+        }
+    }
+
+    setCaption(i18nc("@title:window", "Configure Preview for %1", pluginName));
+    setMinimumWidth(400);
+    setButtons(Ok | Cancel);
+    setDefaultButton(Ok);
+
+    QWidget* mainWidget = new QWidget(this);
+    mainWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+    QVBoxLayout* layout = new QVBoxLayout(mainWidget);
+    if (m_previewPlugin) {
+        m_configurationWidget = m_previewPlugin->createConfigurationWidget();
+        layout->addWidget(m_configurationWidget);
+    }
+    layout->addStretch(1);
+
+    setMainWidget(mainWidget);
+
+    connect(this, SIGNAL(okClicked()), this, SLOT(slotOk()));
+}
+
+ConfigurePreviewPluginDialog::~ConfigurePreviewPluginDialog()
+{
+}
+
+void ConfigurePreviewPluginDialog::slotOk()
+{
+    m_previewPlugin->writeConfiguration(m_configurationWidget);
+    // TODO: It would be great having a mechanism to tell PreviewJob that only previews
+    // for a specific MIME-type should be regenerated. As this is not available yet we
+    // delete the whole thumbnails directory.
+    QApplication::changeOverrideCursor(Qt::BusyCursor);
+    KIO::NetAccess::del(QDir::homePath() + "/.thumbnails/", this);
+    QApplication::restoreOverrideCursor();
+
+}
+
+#include "configurepreviewplugindialog.moc"
diff --git a/src/settings/general/configurepreviewplugindialog.h b/src/settings/general/configurepreviewplugindialog.h
new file mode 100644 (file)
index 0000000..5a3f535
--- /dev/null
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 CONFIGUREPREVIEWPLUGINDIALOG_H
+#define CONFIGUREPREVIEWPLUGINDIALOG_H
+
+#include <KDialog>
+
+class ThumbCreatorV2;
+
+/**
+ * @brief Dialog for configuring preview-plugins.
+ */
+class ConfigurePreviewPluginDialog : public KDialog
+{
+    Q_OBJECT
+
+public:
+    /**
+     * @param pluginName       User visible name of the plugin
+     * @param desktopEntryName The name of the plugin that is noted in the desktopentry.
+     *                         Is used to instantiate the plugin to get the configuration
+     *                         widget.
+     * @param parent           Parent widget.
+     */
+    explicit ConfigurePreviewPluginDialog(const QString& pluginName,
+                                          const QString& desktopEntryName,
+                                          QWidget* parent = 0);
+    virtual ~ConfigurePreviewPluginDialog();
+
+private slots:
+    void slotOk();
+
+private:
+    QWidget* m_configurationWidget;
+    ThumbCreatorV2* m_previewPlugin;
+};
+
+#endif
index 0836aef33bc42d2f9d0f4d1f8b5b395359e39870..679494c67c1678a5b68c1c90c35f1c418a41bb92 100644 (file)
@@ -20,6 +20,7 @@
 #include "previewssettingspage.h"
 
 #include "dolphin_generalsettings.h"
+#include "configurepreviewplugindialog.h"
 
 #include <KConfigGroup>
 #include <KDialog>
 #include <KService>
 
 #include <settings/dolphinsettings.h>
+#include <settings/serviceitemdelegate.h>
+#include <settings/servicemodel.h>
 
 #include <QCheckBox>
 #include <QGroupBox>
 #include <QLabel>
-#include <QListWidget>
-#include <QRadioButton>
+#include <QListView>
+#include <QPainter>
+#include <QScrollBar>
 #include <QShowEvent>
 #include <QSlider>
+#include <QSortFilterProxyModel>
 #include <QGridLayout>
+#include <QVBoxLayout>
 
 // default settings
 namespace {
@@ -50,7 +56,7 @@ namespace {
 PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) :
     SettingsPageBase(parent),
     m_initialized(false),
-    m_previewPluginsList(0),
+    m_listView(0),
     m_enabledPreviewPlugins(),
     m_localFileSizeBox(0),
     m_remoteFileSizeBox(0)
@@ -62,12 +68,23 @@ PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) :
     // Create group box "Show previews for:"
     QGroupBox* listBox = new QGroupBox(i18nc("@title:group", "Show previews for"), this);
 
-    m_previewPluginsList = new QListWidget(this);
-    m_previewPluginsList->setSortingEnabled(true);
-    m_previewPluginsList->setSelectionMode(QAbstractItemView::NoSelection);
+    m_listView = new QListView(this);
+
+    ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView);
+    connect(delegate, SIGNAL(requestServiceConfiguration(QModelIndex)),
+            this, SLOT(configureService(QModelIndex)));
+
+    ServiceModel* serviceModel = new ServiceModel(this);
+    QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(this);
+    proxyModel->setSourceModel(serviceModel);
+    proxyModel->setSortRole(Qt::DisplayRole);
+
+    m_listView->setModel(proxyModel);
+    m_listView->setItemDelegate(delegate);
+    m_listView->setVerticalScrollMode(QListView::ScrollPerPixel);
 
     QVBoxLayout* listBoxLayout = new QVBoxLayout(listBox);
-    listBoxLayout->addWidget(m_previewPluginsList);
+    listBoxLayout->addWidget(m_listView);
 
     // Create group box "Don't create previews for"
     QGroupBox* fileSizeBox = new QGroupBox(i18nc("@title:group", "Do not create previews for"), this);
@@ -99,25 +116,26 @@ PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) :
 
     loadSettings();
 
-    connect(m_previewPluginsList, SIGNAL(itemClicked(QListWidgetItem*)), this, SIGNAL(changed()));
+    connect(m_listView, SIGNAL(clicked(QModelIndex)), this, SIGNAL(changed()));
     connect(m_localFileSizeBox, SIGNAL(valueChanged(int)), this, SIGNAL(changed()));
     connect(m_remoteFileSizeBox, SIGNAL(valueChanged(int)), this, SIGNAL(changed()));
 }
 
-
 PreviewsSettingsPage::~PreviewsSettingsPage()
 {
 }
 
 void PreviewsSettingsPage::applySettings()
 {
-    const int count = m_previewPluginsList->count();
-    if (count > 0) {
+    const QAbstractItemModel* model = m_listView->model();
+    const int rowCount = model->rowCount();
+    if (rowCount > 0) {
         m_enabledPreviewPlugins.clear();
-        for (int i = 0; i < count; ++i) {
-            const QListWidgetItem* item = m_previewPluginsList->item(i);
-            if (item->checkState() == Qt::Checked) {
-                const QString enabledPlugin = item->data(Qt::UserRole).toString();
+        for (int i = 0; i < rowCount; ++i) {
+            const QModelIndex index = model->index(i, 0);
+            const bool checked = model->data(index, Qt::CheckStateRole).toBool();
+            if (checked) {
+                const QString enabledPlugin = model->data(index, Qt::UserRole).toString();
                 m_enabledPreviewPlugins.append(enabledPlugin);
             }
         }
@@ -144,22 +162,53 @@ void PreviewsSettingsPage::restoreDefaults()
 void PreviewsSettingsPage::showEvent(QShowEvent* event)
 {
     if (!event->spontaneous() && !m_initialized) {
-        QMetaObject::invokeMethod(this, "loadPreviewPlugins", Qt::QueuedConnection);
+        loadPreviewPlugins();
         m_initialized = true;
     }
     SettingsPageBase::showEvent(event);
 }
 
+void PreviewsSettingsPage::configureService(const QModelIndex& index)
+{
+    const QAbstractItemModel* model = index.model();
+    const QString pluginName = model->data(index).toString();
+    const QString desktopEntryName = model->data(index, ServiceModel::DesktopEntryNameRole).toString();
+
+    ConfigurePreviewPluginDialog* dialog = new ConfigurePreviewPluginDialog(pluginName, desktopEntryName, this);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+}
+
 void PreviewsSettingsPage::loadPreviewPlugins()
 {
+    QAbstractItemModel* model = m_listView->model();
+
     const KService::List plugins = KServiceTypeTrader::self()->query(QLatin1String("ThumbCreator"));
     foreach (const KSharedPtr<KService>& service, plugins) {
-        QListWidgetItem* item = new QListWidgetItem(service->name(),
-                                                    m_previewPluginsList);
-        item->setData(Qt::UserRole, service->desktopEntryName());
+        const bool configurable = service->property("Configurable", QVariant::Bool).toBool();
         const bool show = m_enabledPreviewPlugins.contains(service->desktopEntryName());
-        item->setCheckState(show ? Qt::Checked : Qt::Unchecked);
+        if (service->desktopEntryName() == QLatin1String("jpegrotatedthumbnail")) {
+            // Before KDE SC 4.7 thumbnail plugins where not configurable and in addition to
+            // the jpegthumbnail-plugin a jpegrotatedthumbnail-plugin was offered. Make this
+            // plugin obsolete for users that updated from a previous KDE SC version:
+            if (show) {
+                m_enabledPreviewPlugins.removeOne(service->desktopEntryName());
+                KConfigGroup globalConfig(KGlobal::config(), QLatin1String("PreviewSettings"));
+                globalConfig.writeEntry("Plugins", m_enabledPreviewPlugins);
+                globalConfig.sync();
+            }
+            continue;
+        }
+
+        model->insertRow(0);
+        const QModelIndex index = model->index(0, 0);
+        model->setData(index, show, Qt::CheckStateRole);
+        model->setData(index, configurable, ServiceModel::ConfigurableRole);
+        model->setData(index, service->name(), Qt::DisplayRole);
+        model->setData(index, service->desktopEntryName(), ServiceModel::DesktopEntryNameRole);
     }
+
+    model->sort(Qt::DisplayRole);
 }
 
 void PreviewsSettingsPage::loadSettings()
@@ -168,7 +217,7 @@ void PreviewsSettingsPage::loadSettings()
     m_enabledPreviewPlugins = globalConfig.readEntry("Plugins", QStringList()
                                                      << QLatin1String("directorythumbnail")
                                                      << QLatin1String("imagethumbnail")
-                                                     << QLatin1String("jpegrotatedthumbnail"));
+                                                     << QLatin1String("jpegthumbnail"));
 
     const int maxLocalByteSize = globalConfig.readEntry("MaximumSize", MaxLocalPreviewSize * 1024 * 1024);
     const int maxLocalMByteSize = maxLocalByteSize / (1024 * 1024);
index b14aa7ab458cc8d47e1daabf86d4c4702771d0f3..ef3ad267ecd8e44874263e49a9969d7d80300893 100644 (file)
@@ -22,8 +22,9 @@
 
 #include <settings/settingspagebase.h>
 
-class QListWidget;
 class KIntSpinBox;
+class QListView;
+class QModelIndex;
 
 /**
  * @brief Allows the configuration of file previews.
@@ -50,14 +51,15 @@ protected:
     virtual void showEvent(QShowEvent* event);
 
 private slots:
-    void loadPreviewPlugins();
+    void configureService(const QModelIndex& index);
 
 private:
+    void loadPreviewPlugins();
     void loadSettings();
 
 private:
     bool m_initialized;
-    QListWidget* m_previewPluginsList;
+    QListView *m_listView;
     QStringList m_enabledPreviewPlugins;
     KIntSpinBox* m_localFileSizeBox;
     KIntSpinBox* m_remoteFileSizeBox;
diff --git a/src/settings/serviceitemdelegate.cpp b/src/settings/serviceitemdelegate.cpp
new file mode 100644 (file)
index 0000000..3dc3146
--- /dev/null
@@ -0,0 +1,128 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 "serviceitemdelegate.h"
+
+#include <KDebug>
+#include <KPushButton>
+
+#include "servicemodel.h"
+
+#include <QAbstractItemView>
+#include <QCheckBox>
+#include <QModelIndex>
+#include <QPainter>
+
+ServiceItemDelegate::ServiceItemDelegate(QAbstractItemView* itemView, QObject* parent) :
+    KWidgetItemDelegate(itemView, parent)
+{
+}
+
+ServiceItemDelegate::~ServiceItemDelegate()
+{
+}
+
+QSize ServiceItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+                                    const QModelIndex &index) const
+{
+    Q_UNUSED(index);
+
+    const QStyle *style = itemView()->style();
+    const int buttonHeight = style->pixelMetric(QStyle::PM_ButtonMargin) * 2 +
+                             style->pixelMetric(QStyle::PM_ButtonIconSize);
+    const int fontHeight = option.fontMetrics.height();
+    return QSize(100, qMax(buttonHeight, fontHeight));
+}
+
+void ServiceItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
+                                  const QModelIndex& index) const
+{
+    Q_UNUSED(index);
+    painter->save();
+
+    itemView()->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
+
+    if (option.state & QStyle::State_Selected) {
+        painter->setPen(option.palette.highlightedText().color());
+    }
+
+    painter->restore();
+}
+
+QList<QWidget*> ServiceItemDelegate::createItemWidgets() const
+{
+    QCheckBox* checkBox = new QCheckBox();
+    connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(slotCheckBoxClicked(bool)));
+
+    KPushButton* configureButton = new KPushButton();
+    connect(configureButton, SIGNAL(clicked()), this, SLOT(slotConfigureButtonClicked()));
+
+    return QList<QWidget*>() << checkBox << configureButton;
+}
+
+void ServiceItemDelegate::updateItemWidgets(const QList<QWidget*> widgets,
+                                              const QStyleOptionViewItem& option,
+                                              const QPersistentModelIndex& index) const
+{
+    QCheckBox* checkBox = static_cast<QCheckBox*>(widgets[0]);
+    KPushButton *configureButton = static_cast<KPushButton*>(widgets[1]);
+
+    const int itemHeight = sizeHint(option, index).height();
+
+    // Update the checkbox showing the service name and icon
+    const QAbstractItemModel* model = index.model();
+    checkBox->setText(model->data(index).toString());
+    const QString iconName = model->data(index, Qt::DecorationRole).toString();
+    if (!iconName.isEmpty()) {
+        checkBox->setIcon(KIcon(iconName));
+    }
+    checkBox->setChecked(model->data(index, Qt::CheckStateRole).toBool());
+
+    const bool configurable = model->data(index, ServiceModel::ConfigurableRole).toBool();
+
+    int checkBoxWidth = option.rect.width();
+    if (configurable) {
+        checkBoxWidth -= configureButton->sizeHint().width();
+    }
+    checkBox->resize(checkBoxWidth, checkBox->sizeHint().height());
+    checkBox->move(0, (itemHeight - checkBox->height()) / 2);
+
+    // Update the configuration button
+    if (configurable) {
+        configureButton->setEnabled(checkBox->isChecked());
+        configureButton->setIcon(KIcon("configure"));
+        configureButton->resize(configureButton->sizeHint());
+        configureButton->move(option.rect.right() - configureButton->width(),
+                              (itemHeight - configureButton->height()) / 2);
+    }
+    configureButton->setVisible(configurable);
+}
+
+void ServiceItemDelegate::slotCheckBoxClicked(bool checked)
+{
+    QAbstractItemModel* model = const_cast<QAbstractItemModel*>(focusedIndex().model());
+    model->setData(focusedIndex(), checked, Qt::CheckStateRole);
+}
+
+void ServiceItemDelegate::slotConfigureButtonClicked()
+{
+    emit requestServiceConfiguration(focusedIndex());
+}
+
+#include "serviceitemdelegate.moc"
diff --git a/src/settings/serviceitemdelegate.h b/src/settings/serviceitemdelegate.h
new file mode 100644 (file)
index 0000000..ea9681a
--- /dev/null
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 SERVICEITEMDELEGATE_H
+#define SERVICEITEMDELEGATE_H
+
+#include <KWidgetItemDelegate>
+
+/**
+ * @brief Widget item delegate for a service that can be enabled or disabled.
+ *
+ * Additionally it is possible to configure a service.
+ * @see ServiceModel
+ */
+class ServiceItemDelegate : public KWidgetItemDelegate
+{
+    Q_OBJECT
+
+public:
+    explicit ServiceItemDelegate(QAbstractItemView* itemView, QObject* parent = 0);
+    virtual ~ServiceItemDelegate();
+
+    virtual QSize sizeHint(const QStyleOptionViewItem &option,
+                           const QModelIndex &index) const;
+
+    virtual void paint(QPainter* painter, const QStyleOptionViewItem& option,
+                       const QModelIndex& index) const;
+
+    virtual QList<QWidget*> createItemWidgets() const;
+
+    virtual void updateItemWidgets(const QList<QWidget*> widgets,
+                                   const QStyleOptionViewItem& option,
+                                   const QPersistentModelIndex& index) const;
+
+signals:
+    void requestServiceConfiguration(const QModelIndex& index);
+
+private slots:
+    void slotCheckBoxClicked(bool checked);
+    void slotConfigureButtonClicked();
+};
+
+#endif
diff --git a/src/settings/servicemodel.cpp b/src/settings/servicemodel.cpp
new file mode 100644 (file)
index 0000000..315b90d
--- /dev/null
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 "servicemodel.h"
+
+ServiceModel::ServiceModel(QObject* parent) :
+    QAbstractListModel(parent),
+    m_items()
+{
+}
+
+ServiceModel::~ServiceModel()
+{
+}
+
+bool ServiceModel::insertRows(int row, int count, const QModelIndex& parent)
+{
+    if (row > rowCount()) {
+        return false;
+    }
+
+    if (count <= 0) {
+        count = 1;
+    }
+
+    beginInsertRows(parent, row, row + count - 1);
+    for (int i = 0; i < count; ++i) {
+        ServiceItem item;
+        item.checked = false;
+        item.configurable = false;
+        m_items.insert(row, item);
+    }
+    endInsertRows();
+
+    return true;
+}
+
+bool ServiceModel::setData(const QModelIndex& index, const QVariant& value, int role)
+{
+    const int row = index.row();
+    if (row >= rowCount()) {
+        return false;
+    }
+
+    switch (role) {
+    case Qt::CheckStateRole:
+        m_items[row].checked = value.toBool();
+        break;
+    case ConfigurableRole:
+        m_items[row].configurable = value.toBool();
+        break;
+    case Qt::DecorationRole:
+        m_items[row].icon = value.toString();
+        break;
+    case Qt::DisplayRole:
+        m_items[row].text = value.toString();
+        break;
+    case DesktopEntryNameRole:
+        m_items[row].desktopEntryName = value.toString();
+        break;
+    default:
+        return false;
+    }
+
+    emit dataChanged(index, index);
+    return true;
+}
+
+QVariant ServiceModel::data(const QModelIndex& index, int role) const
+{
+    const int row = index.row();
+    if (row < rowCount()) {
+        switch (role) {
+        case ConfigurableRole:     return m_items[row].configurable;
+        case Qt::CheckStateRole:   return m_items[row].checked;
+        case Qt::DecorationRole:   return m_items[row].icon;
+        case Qt::DisplayRole:      return m_items[row].text;
+        case DesktopEntryNameRole: return m_items[row].desktopEntryName;
+        default: break;
+        }
+    }
+
+    return QVariant();
+}
+
+int ServiceModel::rowCount(const QModelIndex& parent) const
+{
+    Q_UNUSED(parent);
+    return m_items.count();
+}
+
+#include "servicemodel.moc"
diff --git a/src/settings/servicemodel.h b/src/settings/servicemodel.h
new file mode 100644 (file)
index 0000000..b8c2d52
--- /dev/null
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   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 SERVICEMODEL_H
+#define SERVICEMODEL_H
+
+#include <QAbstractListModel>
+#include <QList>
+
+/**
+ * @brief Provides a simple model for enabling/disabling services
+ *
+ * The following roles are supported:
+ * - Qt::DisplayRole: Name of the service
+ * - Qt::DecorationRole: Icon name of the service
+ * - Qt::CheckStateRole: Specifies whether the service is enabled
+ * - ServiceModel::DesktopEntryNameRole: Name of the desktop-entry of the service
+ * - ServiceModel::Configurable: Specifies whether the service is configurable by the user
+ */
+class ServiceModel : public QAbstractListModel
+{
+    Q_OBJECT
+
+public:
+    enum Role
+    {
+        DesktopEntryNameRole = Qt::UserRole,
+        ConfigurableRole
+    };
+
+    explicit ServiceModel(QObject* parent = 0);
+    virtual ~ServiceModel();
+
+    virtual bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex());
+    virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+    virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
+
+ private:
+    struct ServiceItem
+    {
+        bool checked;
+        bool configurable;
+        QString icon;
+        QString text;
+        QString desktopEntryName;
+    };
+
+    QList<ServiceItem> m_items;
+};
+
+#endif
index 21eba8d866e3aa80f2bfc70eb2fc0ef835bc48b1..fbddbbfa7d3916f307c18c81ba796a5a43a68f6c 100644 (file)
 #include <KServiceTypeTrader>
 #include <KStandardDirs>
 
+#include <settings/serviceitemdelegate.h>
+#include <settings/servicemodel.h>
+
 #include <QCheckBox>
 #include <QGridLayout>
 #include <QGroupBox>
 #include <QLabel>
 #include <QListWidget>
 #include <QPushButton>
+#include <QSortFilterProxyModel>
 #include <QShowEvent>
 
 ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
     SettingsPageBase(parent),
     m_initialized(false),
-    m_servicesList(0),
+    m_listView(0),
     m_vcsGroupBox(0),
     m_vcsPluginsMap(),
     m_enabledVcsPlugins()
@@ -56,11 +60,16 @@ ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
                                      "be shown in the context menu:"), this);
     label->setWordWrap(true);
 
-    m_servicesList = new QListWidget(this);
-    m_servicesList->setSortingEnabled(true);
-    m_servicesList->setSelectionMode(QAbstractItemView::NoSelection);
-    connect(m_servicesList, SIGNAL(itemClicked(QListWidgetItem*)),
-            this, SIGNAL(changed()));
+    m_listView = new QListView(this);
+    ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView);
+    ServiceModel* serviceModel = new ServiceModel(this);
+    QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(this);
+    proxyModel->setSourceModel(serviceModel);
+    proxyModel->setSortRole(Qt::DisplayRole);
+    m_listView->setModel(proxyModel);
+    m_listView->setItemDelegate(delegate);
+    m_listView->setVerticalScrollMode(QListView::ScrollPerPixel);
+    connect(m_listView, SIGNAL(clicked(QModelIndex)), this, SIGNAL(changed()));
 
     KNS3::Button* downloadButton = new KNS3::Button(i18nc("@action:button", "Download New Services..."),
                                                     "servicemenu.knsrc",
@@ -73,7 +82,7 @@ ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
     m_vcsGroupBox->hide();
 
     topLayout->addWidget(label);
-    topLayout->addWidget(m_servicesList);
+    topLayout->addWidget(m_listView);
     topLayout->addWidget(downloadButton);
     topLayout->addWidget(m_vcsGroupBox);
 
@@ -94,11 +103,11 @@ void ServicesSettingsPage::applySettings()
     KConfig config("kservicemenurc", KConfig::NoGlobals);
     KConfigGroup showGroup = config.group("Show");
 
-    const int count = m_servicesList->count();
-    for (int i = 0; i < count; ++i) {
-        QListWidgetItem* item = m_servicesList->item(i);
-        const bool show = (item->checkState() == Qt::Checked);
-        const QString service = item->data(Qt::UserRole).toString();
+    const QAbstractItemModel* model = m_listView->model();
+    for (int i = 0; i < model->rowCount(); ++i) {
+        const QModelIndex index = model->index(i, 0);
+        const bool show = model->data(index, Qt::CheckStateRole).toBool();
+        const QString service = model->data(index, ServiceModel::DesktopEntryNameRole).toString();
         showGroup.writeEntry(service, show);
     }
 
@@ -128,18 +137,18 @@ void ServicesSettingsPage::applySettings()
 
 void ServicesSettingsPage::restoreDefaults()
 {
-    const int count = m_servicesList->count();
-    for (int i = 0; i < count; ++i) {
-        QListWidgetItem* item = m_servicesList->item(i);
-        item->setCheckState(Qt::Checked);
+    QAbstractItemModel* model = m_listView->model();
+    for (int i = 0; i < model->rowCount(); ++i) {
+        const QModelIndex index = model->index(i, 0);
+        model->setData(index, true, Qt::CheckStateRole);
     }
 }
 
 void ServicesSettingsPage::showEvent(QShowEvent* event)
 {
     if (!event->spontaneous() && !m_initialized) {
-        QMetaObject::invokeMethod(this, "loadServices", Qt::QueuedConnection);
-        QMetaObject::invokeMethod(this, "loadVersionControlSystems", Qt::QueuedConnection);
+        loadServices();
+        loadVersionControlSystems();
         m_initialized = true;
     }
     SettingsPageBase::showEvent(event);
@@ -147,6 +156,8 @@ void ServicesSettingsPage::showEvent(QShowEvent* event)
 
 void ServicesSettingsPage::loadServices()
 {
+    QAbstractItemModel* model = m_listView->model();
+
     const KConfig config("kservicemenurc", KConfig::NoGlobals);
     const KConfigGroup showGroup = config.group("Show");
 
@@ -170,12 +181,14 @@ void ServicesSettingsPage::loadServices()
                 const QString itemName = subMenuName.isEmpty()
                                          ? action.text()
                                          : i18nc("@item:inmenu", "%1: %2", subMenuName, action.text());
-                QListWidgetItem* item = new QListWidgetItem(KIcon(action.icon()),
-                                                            itemName,
-                                                            m_servicesList);
-                item->setData(Qt::UserRole, serviceName);
                 const bool show = showGroup.readEntry(serviceName, true);
-                item->setCheckState(show ? Qt::Checked : Qt::Unchecked);
+
+                model->insertRow(0);
+                const QModelIndex index = model->index(0, 0);
+                model->setData(index, action.icon(), Qt::DecorationRole);
+                model->setData(index, show, Qt::CheckStateRole);
+                model->setData(index, itemName, Qt::DisplayRole);
+                model->setData(index, serviceName, ServiceModel::DesktopEntryNameRole);
             }
         }
     }
@@ -183,16 +196,20 @@ void ServicesSettingsPage::loadServices()
     // Load service plugins that implement the KFileItemActionPlugin interface
     const KService::List pluginServices = KServiceTypeTrader::self()->query("KFileItemAction/Plugin");
     foreach (const KSharedPtr<KService>& service, pluginServices) {
-        const QString serviceName = service->desktopEntryName();
-        if (!isInServicesList(serviceName)) {
-            QListWidgetItem* item = new QListWidgetItem(KIcon(service->icon()),
-                                                        service->name(),
-                                                        m_servicesList);
-            item->setData(Qt::UserRole, serviceName);
-            const bool show = showGroup.readEntry(serviceName, true);
-            item->setCheckState(show ? Qt::Checked : Qt::Unchecked);
+        const QString desktopEntryName = service->desktopEntryName();
+        if (!isInServicesList(desktopEntryName)) {
+            const bool show = showGroup.readEntry(desktopEntryName, true);
+
+            model->insertRow(0);
+            const QModelIndex index = model->index(0, 0);
+            model->setData(index, service->icon(), Qt::DecorationRole);
+            model->setData(index, show, Qt::CheckStateRole);
+            model->setData(index, service->name(), Qt::DisplayRole);
+            model->setData(index, desktopEntryName, ServiceModel::DesktopEntryNameRole);
         }
     }
+
+    model->sort(Qt::DisplayRole);
 }
 
 void ServicesSettingsPage::loadVersionControlSystems()
@@ -228,10 +245,10 @@ void ServicesSettingsPage::loadVersionControlSystems()
 
 bool ServicesSettingsPage::isInServicesList(const QString& service) const
 {
-    const int count = m_servicesList->count();
-    for (int i = 0; i < count; ++i) {
-        QListWidgetItem* item = m_servicesList->item(i);
-        if (item->data(Qt::UserRole).toString() == service) {
+    QAbstractItemModel* model = m_listView->model();
+    for (int i = 0; i < model->rowCount(); ++i) {
+        const QModelIndex index = model->index(i, 0);
+        if (model->data(index, ServiceModel::DesktopEntryNameRole).toString() == service) {
             return true;
         }
     }
index be5953c64d7abd7f069680e893f0a62727bceca6..d2eecaefebc61df1fdfa4d5486965b959ddb2a36 100644 (file)
@@ -26,7 +26,7 @@
 
 class QCheckBox;
 class QGroupBox;
-class QListWidget;
+class QListView;
 
 /**
  * @brief Page for the 'Services' settings of the Dolphin settings dialog.
@@ -54,6 +54,7 @@ private slots:
      */
     void loadServices();
 
+private:
     /**
      * Loads installed version control systems.
      */
@@ -63,7 +64,7 @@ private slots:
 
 private:
     bool m_initialized;
-    QListWidget* m_servicesList;
+    QListView *m_listView;
     QGroupBox* m_vcsGroupBox;
     QMap<QString, QCheckBox*> m_vcsPluginsMap;
     QStringList m_enabledVcsPlugins;