From 08d6f62ae74c0a32a32e12a62d33bed0750274d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 31 Oct 2011 08:41:07 +0100 Subject: [PATCH] New TabBox Layout configuration dialog This dialog shows all available layouts with a preview. --- kcmkwin/kwintabbox/CMakeLists.txt | 2 +- kcmkwin/kwintabbox/layoutconfig.cpp | 270 ++++++++++++++++++++-------- kcmkwin/kwintabbox/layoutconfig.h | 64 +++++-- kcmkwin/kwintabbox/main.cpp | 8 +- kcmkwin/kwintabbox/qml/main.qml | 91 ++++++++++ tabbox/qml/big_icons.qml | 2 + tabbox/qml/compact.qml | 2 + tabbox/qml/informative.qml | 2 + tabbox/qml/small_icons.qml | 2 + tabbox/qml/text.qml | 2 + 10 files changed, 357 insertions(+), 88 deletions(-) create mode 100644 kcmkwin/kwintabbox/qml/main.qml diff --git a/kcmkwin/kwintabbox/CMakeLists.txt b/kcmkwin/kwintabbox/CMakeLists.txt index 826092f361..e113d1db8d 100644 --- a/kcmkwin/kwintabbox/CMakeLists.txt +++ b/kcmkwin/kwintabbox/CMakeLists.txt @@ -28,4 +28,4 @@ install(TARGETS kcm_kwintabbox DESTINATION ${PLUGIN_INSTALL_DIR} ) ########### install files ############### install( FILES kwintabbox.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) - +install( FILES qml/main.qml DESTINATION ${DATA_INSTALL_DIR}/kwin/kcm_kwintabbox) diff --git a/kcmkwin/kwintabbox/layoutconfig.cpp b/kcmkwin/kwintabbox/layoutconfig.cpp index 6c758f7df3..6fb0b47134 100644 --- a/kcmkwin/kwintabbox/layoutconfig.cpp +++ b/kcmkwin/kwintabbox/layoutconfig.cpp @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. -Copyright (C) 2009 Martin Gräßlin +Copyright (C) 2009, 2011 Martin Gräßlin 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 @@ -19,106 +19,234 @@ along with this program. If not, see . *********************************************************************/ // own #include "layoutconfig.h" -#include "ui_layoutconfig.h" -// tabbox -#include "tabboxconfig.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace KWin { namespace TabBox { -/*************************************************** -* LayoutConfigPrivate -***************************************************/ -class LayoutConfigPrivate +LayoutConfig::LayoutConfig(QWidget* parent) + : QDeclarativeView(parent) + , m_layoutsModels(new LayoutModel(this)) { -public: - LayoutConfigPrivate(); - ~LayoutConfigPrivate() { } + setAttribute(Qt::WA_TranslucentBackground); + QPalette pal = palette(); + pal.setColor(backgroundRole(), Qt::transparent); + setPalette(pal); + setMinimumSize(QSize(500, 500)); + setResizeMode(QDeclarativeView::SizeRootObjectToView); + foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) { + engine()->addImportPath(importPath); + } + foreach (const QString &importPath, KGlobal::dirs()->findDirs("data", "kwin/tabbox")) { + engine()->addImportPath(importPath); + } + ExampleClientModel *model = new ExampleClientModel(this); + engine()->addImageProvider(QLatin1String("client"), new TabBoxImageProvider(model)); + KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(engine()); + kdeclarative.initialize(); + kdeclarative.setupBindings(); + rootContext()->setContextProperty("clientModel", model); + rootContext()->setContextProperty("layoutModel", m_layoutsModels); + setSource(KStandardDirs::locate("data", "kwin/kcm_kwintabbox/main.qml")); +} - TabBoxConfig config; - Ui::LayoutConfigForm ui; -}; +LayoutConfig::~LayoutConfig() +{ +} -LayoutConfigPrivate::LayoutConfigPrivate() +void LayoutConfig::setLayout(const QString &layoutName) { + const QModelIndex index = m_layoutsModels->indexForLayoutName(layoutName); + const int row = (index.isValid()) ? index.row() : -1; + if (QObject *item = rootObject()->findChild("view")) { + item->setProperty("currentIndex", row); + } } -/*************************************************** -* LayoutConfig -***************************************************/ -LayoutConfig::LayoutConfig(QWidget* parent) - : QWidget(parent) +QString LayoutConfig::selectedLayout() const { - d = new LayoutConfigPrivate; - d->ui.setupUi(this); + int row = 0; + if (QObject *item = rootObject()->findChild("view")) { + row = item->property("currentIndex").toInt(); + } + const QModelIndex index = m_layoutsModels->index(row); + if (!index.isValid()) { + return QString(); + } + return m_layoutsModels->data(index, Qt::UserRole+2).toString(); +} - // init the item layout combo box - d->ui.itemLayoutCombo->addItem(i18n("Informative")); - d->ui.itemLayoutCombo->addItem(i18n("Compact")); - d->ui.itemLayoutCombo->addItem(i18n("Small Icons")); - d->ui.itemLayoutCombo->addItem(i18n("Large Icons")); - d->ui.itemLayoutCombo->addItem(i18n("Text Only")); - // TODO: user defined layouts +TabBoxImageProvider::TabBoxImageProvider(QAbstractListModel* model) + : QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap) + , m_model(model) +{ +} - connect(d->ui.itemLayoutCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); +QPixmap TabBoxImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + bool ok = false; + QStringList parts = id.split('/'); + const int index = parts.first().toInt(&ok); + if (!ok) { + return QDeclarativeImageProvider::requestPixmap(id, size, requestedSize); + } + QSize s(32, 32); + if (requestedSize.isValid()) { + s = requestedSize; + } + *size = s; + QPixmap icon(KIcon(m_model->data(m_model->index(index), Qt::UserRole+3).toString()).pixmap(s)); + if (parts.size() > 2) { + KIconEffect *effect = KIconLoader::global()->iconEffect(); + KIconLoader::States state = KIconLoader::DefaultState; + if (parts.at(2) == QLatin1String("selected")) { + state = KIconLoader::ActiveState; + } else if (parts.at(2) == QLatin1String("disabled")) { + state = KIconLoader::DisabledState; + } + icon = effect->apply(icon, KIconLoader::Desktop, state); + } + return icon; } -LayoutConfig::~LayoutConfig() +ExampleClientModel::ExampleClientModel (QObject* parent) + : QAbstractListModel (parent) { - delete d; + QHash roles; + roles[Qt::UserRole] = "caption"; + roles[Qt::UserRole+1] = "minimized"; + roles[Qt::UserRole+2] = "desktopName"; + setRoleNames(roles); + init(); } -TabBoxConfig& LayoutConfig::config() const +ExampleClientModel::~ExampleClientModel() { - return d->config; } -void LayoutConfig::setConfig(const KWin::TabBox::TabBoxConfig& config) +void ExampleClientModel::init() { - d->config = config; - // item layouts - if (config.layoutName().compare("Default", Qt::CaseInsensitive) == 0) { - d->ui.itemLayoutCombo->setCurrentIndex(0); - } else if (config.layoutName().compare("Compact", Qt::CaseInsensitive) == 0) { - d->ui.itemLayoutCombo->setCurrentIndex(1); - } else if (config.layoutName().compare("Small Icons", Qt::CaseInsensitive) == 0) { - d->ui.itemLayoutCombo->setCurrentIndex(2); - } else if (config.layoutName().compare("Big Icons", Qt::CaseInsensitive) == 0) { - d->ui.itemLayoutCombo->setCurrentIndex(3); - } else if (config.layoutName().compare("Text", Qt::CaseInsensitive) == 0) { - d->ui.itemLayoutCombo->setCurrentIndex(4); - } else { - // TODO: user defined layouts + QList applications; + applications << "konqbrowser" << "KMail2" << "systemsettings" << "dolphin"; + + foreach (const QString& application, applications) { + KService::Ptr service = KService::serviceByStorageId("kde4-" + application + ".desktop"); + if (service) { + m_nameList << service->entryPath(); + } } +} +QVariant ExampleClientModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + switch (role) { + case Qt::DisplayRole: + case Qt::UserRole: + return KDesktopFile(m_nameList.at(index.row())).readName(); + case Qt::UserRole+1: + return false; + case Qt::UserRole+2: + return i18nc("An example Desktop Name", "Desktop 1"); + case Qt::UserRole+3: + return KDesktopFile(m_nameList.at(index.row())).readIcon(); + } + return QVariant(); } -void LayoutConfig::changed() +int ExampleClientModel::rowCount(const QModelIndex &parent) const { - QString layout; - switch(d->ui.itemLayoutCombo->currentIndex()) { - case 0: - layout = "Default"; - break; - case 1: - layout = "Compact"; - break; - case 2: - layout = "Small Icons"; - break; - case 3: - layout = "Big Icons"; - break; - case 4: - layout = "Text"; - break; - default: - // TODO: user defined layouts - break; + Q_UNUSED(parent) + return m_nameList.size(); +} + +LayoutModel::LayoutModel(QObject *parent) + : QAbstractListModel(parent) +{ + QHash roles; + roles[Qt::UserRole] = "name"; + roles[Qt::UserRole+1] = "sourcePath"; + setRoleNames(roles); + init(); +} + +LayoutModel::~LayoutModel() +{ +} + +void LayoutModel::init() +{ + QStringList layouts; + layouts << "informative" << "compact" << "text" << "big_icons" << "small_icons"; + QStringList descriptions; + descriptions << i18nc("Name for a window switcher layout showing icon, name and desktop", "Informative"); + descriptions << i18nc("Name for a window switcher layout showing only icon and name", "Compact"); + descriptions << i18nc("Name for a window switcher layout showing only the name", "Text"); + descriptions << i18nc("Name for a window switcher layout showing large icons", "Large Icons"); + descriptions << i18nc("Name for a window switcher layout showing small icons", "Small Icons"); + + for (int i=0; iconfig.setLayoutName(layout); + return QModelIndex(); } } // namespace KWin diff --git a/kcmkwin/kwintabbox/layoutconfig.h b/kcmkwin/kwintabbox/layoutconfig.h index 3ee887bac2..a83574ad17 100644 --- a/kcmkwin/kwintabbox/layoutconfig.h +++ b/kcmkwin/kwintabbox/layoutconfig.h @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. -Copyright (C) 2009 Martin Gräßlin +Copyright (C) 2009, 2011 Martin Gräßlin 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 @@ -20,33 +20,73 @@ along with this program. If not, see . #ifndef KWIN_TABBOX_LAYOUTCONFIG_H #define KWIN_TABBOX_LAYOUTCONFIG_H -#include +#include +#include +#include namespace KWin { namespace TabBox { -class TabBoxConfig; -class LayoutConfigPrivate; +class LayoutModel; -class LayoutConfig : public QWidget +class LayoutConfig : public QDeclarativeView { Q_OBJECT +public: + LayoutConfig(QWidget *parent = NULL); + virtual ~LayoutConfig(); + + void setLayout(const QString &layoutName); + QString selectedLayout() const; + +private: + LayoutModel *m_layoutsModels; +}; + +class TabBoxImageProvider : public QDeclarativeImageProvider +{ +public: + TabBoxImageProvider(QAbstractListModel *model); + virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); +private: + QAbstractListModel *m_model; +}; +class ExampleClientModel : public QAbstractListModel +{ + Q_OBJECT +public: + ExampleClientModel(QObject *parent = NULL); + virtual ~ExampleClientModel(); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + +private: + void init(); + QStringList m_nameList; +}; + +class LayoutModel : public QAbstractListModel +{ + Q_OBJECT public: - LayoutConfig(QWidget* parent = NULL); - ~LayoutConfig(); + LayoutModel(QObject *parent = NULL); + virtual ~LayoutModel(); - void setConfig(const TabBoxConfig& config); - TabBoxConfig& config() const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; -private slots: - void changed(); + QModelIndex indexForLayoutName(const QString &name) const; private: - LayoutConfigPrivate* d; + void init(); + QStringList m_nameList; + QStringList m_pathList; + QStringList m_layoutList; }; } // namespace TabBox diff --git a/kcmkwin/kwintabbox/main.cpp b/kcmkwin/kwintabbox/main.cpp index 51b9b4fb9c..4e3ec6331f 100644 --- a/kcmkwin/kwintabbox/main.cpp +++ b/kcmkwin/kwintabbox/main.cpp @@ -584,7 +584,7 @@ void KWinTabBoxConfig::slotConfigureLayoutClicked() connect(dialog, SIGNAL(okClicked()), this, SLOT(slotLayoutChanged())); m_configForm = new TabBox::LayoutConfig(dialog); - m_configForm->setConfig(m_tabBoxConfig); + m_configForm->setLayout(m_tabBoxConfig.layoutName()); dialog->setMainWidget(m_configForm); dialog->exec(); @@ -593,7 +593,7 @@ void KWinTabBoxConfig::slotConfigureLayoutClicked() void KWinTabBoxConfig::slotLayoutChanged() { - m_tabBoxConfig = m_configForm->config(); + m_tabBoxConfig.setLayoutName(m_configForm->selectedLayout()); emit changed(true); } @@ -605,7 +605,7 @@ void KWinTabBoxConfig::slotConfigureLayoutClickedAlternative() connect(dialog, SIGNAL(okClicked()), this, SLOT(slotLayoutChangedAlternative())); m_configForm = new TabBox::LayoutConfig(dialog); - m_configForm->setConfig(m_tabBoxAlternativeConfig); + m_configForm->setLayout(m_tabBoxAlternativeConfig.layoutName()); dialog->setMainWidget(m_configForm); dialog->exec(); @@ -614,7 +614,7 @@ void KWinTabBoxConfig::slotConfigureLayoutClickedAlternative() void KWinTabBoxConfig::slotLayoutChangedAlternative() { - m_tabBoxAlternativeConfig = m_configForm->config(); + m_tabBoxAlternativeConfig.setLayoutName(m_configForm->selectedLayout()); emit changed(true); } diff --git a/kcmkwin/kwintabbox/qml/main.qml b/kcmkwin/kwintabbox/qml/main.qml new file mode 100644 index 0000000000..8858e208c9 --- /dev/null +++ b/kcmkwin/kwintabbox/qml/main.qml @@ -0,0 +1,91 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2011 Martin Gräßlin + +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, see . +*********************************************************************/ +import QtQuick 1.0 +import org.kde.plasma.components 0.1 as PlasmaComponents +Item { + id: container + GridView { + property int lastMousePosX + property int lastMousePosY + id: view + objectName: "view" + model: layoutModel + cellWidth: Math.max(100, (container.width % 2 == 0 ? container.width : (container.width - 1)) / 2.0) + cellHeight: Math.max(100, container.height / (count % 2 == 0 ? count : (count+1)) * 2) + anchors.fill: parent + delegate: itemDelegate + highlight: PlasmaComponents.Highlight { + width: view.cellWidth + height: view.cellHeight + hover: true + } + MouseArea { + hoverEnabled: true + anchors.fill: parent + onPositionChanged: { + view.lastMousePosX = mouse.x; + view.lastMousePosY = mouse.y; + } + onClicked: { + view.currentIndex = view.indexAt(mouse.x, mouse.y); + } + } + } + Component { + id: itemDelegate + Item { + width: view.cellWidth + height: view.cellHeight + Loader { + property int screenWidth : container.width + property int screenHeight : container.height + property bool allDesktops: true + width: { + if (item.canStretchX) { + return Math.min(Math.max(item.optimalWidth, view.cellWidth), view.cellWidth) + } else { + return Math.min(item.optimalWidth, view.cellWidth); + } + } + height: Math.min(item.optimalHeight, view.cellHeight) + source: sourcePath + anchors.centerIn: parent + onLoaded: { + if (item.allDesktops != undefined) { + item.allDesktops = allDesktops; + } + if (item.setModel) { + item.setModel(clientModel); + } + } + } + Text { + id: textElement + font.bold: true + text: name + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + } + visible: view.indexAt(view.lastMousePosX, view.lastMousePosY) == index + } + } + } +} diff --git a/tabbox/qml/big_icons.qml b/tabbox/qml/big_icons.qml index fa39827be2..c70620b117 100644 --- a/tabbox/qml/big_icons.qml +++ b/tabbox/qml/big_icons.qml @@ -28,6 +28,8 @@ Item { property int imagePathPrefix: (new Date()).getTime() property int optimalWidth: (icons.iconSize + icons.margins.left + icons.margins.right) * icons.count + background.margins.left + background.margins.bottom property int optimalHeight: icons.iconSize + icons.margins.top + icons.margins.bottom + background.margins.top + background.margins.bottom + property bool canStretchX: false + property bool canStretchY: false width: Math.min(Math.max(screenWidth * 0.3, optimalWidth), screenWidth * 0.9) height: Math.min(Math.max(screenHeight * 0.05, optimalHeight), screenHeight * 0.5) diff --git a/tabbox/qml/compact.qml b/tabbox/qml/compact.qml index 0e9f4dd8c0..f0f42f9e6a 100644 --- a/tabbox/qml/compact.qml +++ b/tabbox/qml/compact.qml @@ -29,6 +29,8 @@ Item { property int imagePathPrefix: (new Date()).getTime() property int optimalWidth: compactListView.maxRowWidth property int optimalHeight: compactListView.rowHeight * compactListView.count + background.margins.top + background.margins.bottom + property bool canStretchX: true + property bool canStretchY: false width: Math.min(Math.max(screenWidth * 0.2, optimalWidth), screenWidth * 0.8) height: Math.min(Math.max(screenHeight * 0.2, optimalHeight), screenHeight * 0.8) diff --git a/tabbox/qml/informative.qml b/tabbox/qml/informative.qml index 5b165af3fc..e9e893dc14 100644 --- a/tabbox/qml/informative.qml +++ b/tabbox/qml/informative.qml @@ -30,6 +30,8 @@ Item { property int imagePathPrefix: (new Date()).getTime() property int optimalWidth: listView.maxRowWidth property int optimalHeight: listView.rowHeight * listView.count + background.margins.top + background.margins.bottom + property bool canStretchX: true + property bool canStretchY: false width: Math.min(Math.max(screenWidth * 0.2, optimalWidth), screenWidth * 0.8) height: Math.min(Math.max(screenHeight * 0.2, optimalHeight), screenHeight * 0.8) diff --git a/tabbox/qml/small_icons.qml b/tabbox/qml/small_icons.qml index 8bab5ba0af..93acf5c24e 100644 --- a/tabbox/qml/small_icons.qml +++ b/tabbox/qml/small_icons.qml @@ -28,6 +28,8 @@ Item { property int imagePathPrefix: (new Date()).getTime() property int optimalWidth: (icons.iconSize + icons.margins.left + icons.margins.right) * icons.count + background.margins.left + background.margins.bottom property int optimalHeight: icons.iconSize + icons.margins.top + icons.margins.bottom + background.margins.top + background.margins.bottom + property bool canStretchX: false + property bool canStretchY: false width: Math.min(Math.max(screenWidth * 0.1, optimalWidth), screenWidth * 0.9) height: Math.min(Math.max(screenHeight * 0.05, optimalHeight), screenHeight * 0.5) diff --git a/tabbox/qml/text.qml b/tabbox/qml/text.qml index 9cdc7ef6b9..7c5ed64342 100644 --- a/tabbox/qml/text.qml +++ b/tabbox/qml/text.qml @@ -28,6 +28,8 @@ Item { property string longestCaption: "" property int optimalWidth: textListView.maxRowWidth property int optimalHeight: textListView.rowHeight * textListView.count + background.margins.top + background.margins.bottom + property bool canStretchX: true + property bool canStretchY: false width: Math.min(Math.max(screenWidth * 0.2, optimalWidth), screenWidth * 0.8) height: Math.min(Math.max(screenHeight * 0.2, optimalHeight), screenHeight * 0.8)