From 058a5da2dd76ae4dfdbb68cb2a4fdac3708ff0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 12 Dec 2013 11:13:11 +0100 Subject: [PATCH] [kcm-kwintabbox] Adjust Preview to the new Switcher API Needs to implement a dummy switcher item. As the root item of the switchers are no longer QQuickItem derived it cannot use a QQuickView. Instead a component gets created and the switcher is just shown on the primary screen. It's a more appropriate preview now which is not put into a dialog window. To make it more realistic (and to be able to dismiss it) the preview grabs keyboard and mouse and closes itself if escape, return, enter or space is pressed. As well clicking outside the preview window closes the preview. --- kcmkwin/kwintabbox/CMakeLists.txt | 11 -- kcmkwin/kwintabbox/layoutpreview.cpp | 169 +++++++++++++++++++-------- kcmkwin/kwintabbox/layoutpreview.h | 92 +++++++++++++-- kcmkwin/kwintabbox/main.cpp | 16 +-- kcmkwin/kwintabbox/main.h | 2 - kcmkwin/kwintabbox/qml/main.qml | 59 ---------- 6 files changed, 201 insertions(+), 148 deletions(-) delete mode 100644 kcmkwin/kwintabbox/qml/main.qml diff --git a/kcmkwin/kwintabbox/CMakeLists.txt b/kcmkwin/kwintabbox/CMakeLists.txt index 4f7245acc7..6aa6c6a0f0 100644 --- a/kcmkwin/kwintabbox/CMakeLists.txt +++ b/kcmkwin/kwintabbox/CMakeLists.txt @@ -8,11 +8,7 @@ set(kcm_kwintabbox_PART_SRCS main.cpp layoutpreview.cpp thumbnailitem.cpp - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/clientmodel.cpp - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/declarative.cpp - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/desktopmodel.cpp ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/tabboxconfig.cpp - ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/tabbox/tabboxhandler.cpp ) kde4_add_ui_files( kcm_kwintabbox_PART_SRCS main.ui ) @@ -21,17 +17,11 @@ add_library(kcm_kwintabbox MODULE ${kcm_kwintabbox_PART_SRCS}) target_link_libraries(kcm_kwintabbox Qt5::Quick - Qt5::X11Extras KF5::KCMUtils KF5::Completion - KF5::Declarative KF5::GlobalAccel KF5::I18n - KF5::IconThemes KF5::Service - KF5::WindowSystem - KF5::Plasma - KF5::XmlGui KF5::NewStuff ${XCB_XCB_LIBRARY}) @@ -40,6 +30,5 @@ 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) install( FILES thumbnails/konqueror.png thumbnails/kmail.png thumbnails/systemsettings.png thumbnails/dolphin.png DESTINATION ${DATA_INSTALL_DIR}/kwin/kcm_kwintabbox) install( FILES kwinswitcher.knsrc DESTINATION ${CONFIG_INSTALL_DIR} ) diff --git a/kcmkwin/kwintabbox/layoutpreview.cpp b/kcmkwin/kwintabbox/layoutpreview.cpp index 4cff8734dd..0e100b0e89 100644 --- a/kcmkwin/kwintabbox/layoutpreview.cpp +++ b/kcmkwin/kwintabbox/layoutpreview.cpp @@ -20,12 +20,13 @@ along with this program. If not, see . // own #include "layoutpreview.h" #include "thumbnailitem.h" +#include +#include +#include #include #include #include #include -#include -#include #include #include @@ -34,65 +35,77 @@ namespace KWin namespace TabBox { -LayoutPreview::LayoutPreview(QWindow *parent) - : QQuickView(parent) +LayoutPreview::LayoutPreview(const QString &path, QObject *parent) + : QObject(parent) + , m_item(nullptr) { - setColor(Qt::white); - setMinimumSize(QSize(480, 300)); - setResizeMode(QQuickView::SizeRootObjectToView); - foreach (const QString &importPath, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kwin/tabbox", QStandardPaths::LocateDirectory)) { - engine()->addImportPath(importPath); + QQmlEngine *engine = new QQmlEngine(this); + QQmlComponent *component = new QQmlComponent(engine, this); + qmlRegisterType("org.kde.kwin", 2, 0, "ThumbnailItem"); + qmlRegisterType("org.kde.kwin", 2, 0, "Switcher"); + component->loadUrl(QUrl::fromLocalFile(path)); + QObject *item = component->create(); + auto findSwitcher = [item]() -> SwitcherItem* { + if (!item) { + return nullptr; + } + if (SwitcherItem *i = qobject_cast(item)) { + return i; + } else if (QQuickWindow *w = qobject_cast(item)) { + return w->contentItem()->findChild(); + } + return item->findChild(); + }; + if (SwitcherItem *switcher = findSwitcher()) { + m_item = switcher; + switcher->setVisible(true); + } + auto findWindow = [item]() -> QQuickWindow* { + if (!item) { + return nullptr; + } + if (QQuickWindow *w = qobject_cast(item)) { + return w; + } + return item->findChild(); + }; + if (QQuickWindow *w = findWindow()) { + w->setKeyboardGrabEnabled(true); + w->setMouseGrabEnabled(true); + w->installEventFilter(this); } - ExampleClientModel *model = new ExampleClientModel(this); - engine()->addImageProvider(QLatin1String("client"), new TabBoxImageProvider(model)); - qmlRegisterType("org.kde.kwin", 0, 1, "ThumbnailItem"); - rootContext()->setContextProperty("clientModel", model); - rootContext()->setContextProperty("sourcePath", QString()); - rootContext()->setContextProperty("name", QString()); - setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kwin/kcm_kwintabbox/main.qml"))); } LayoutPreview::~LayoutPreview() { } -void LayoutPreview::setLayout(const QString &path, const QString &name) -{ - rootContext()->setContextProperty("sourcePath", path); - rootContext()->setContextProperty("name", name); -} - -TabBoxImageProvider::TabBoxImageProvider(QAbstractListModel* model) - : QQuickImageProvider(QQuickImageProvider::Pixmap) - , m_model(model) -{ -} - -QPixmap TabBoxImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +bool LayoutPreview::eventFilter(QObject *object, QEvent *event) { - bool ok = false; - QStringList parts = id.split('/'); - const int index = parts.first().toInt(&ok); - if (!ok) { - return QQuickImageProvider::requestPixmap(id, size, requestedSize); - } - QSize s(32, 32); - if (requestedSize.isValid()) { - s = requestedSize; - } - *size = s; - QPixmap icon(QIcon::fromTheme(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; + if (event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = dynamic_cast(event); + if (keyEvent->key() == Qt::Key_Escape || + keyEvent->key() == Qt::Key_Return || + keyEvent->key() == Qt::Key_Enter || + keyEvent->key() == Qt::Key_Space) { + object->deleteLater(); + deleteLater(); + } + if (m_item && keyEvent->key() == Qt::Key_Tab) { + m_item->incrementIndex(); + } + if (m_item && keyEvent->key() == Qt::Key_Backtab) { + m_item->decrementIndex(); + } + } else if (event->type() == QEvent::MouseButtonPress) { + if (QWindow *w = qobject_cast(object)) { + if (!w->geometry().contains(static_cast(event)->globalPos())) { + object->deleteLater(); + deleteLater(); + } } - icon = effect->apply(icon, KIconLoader::Desktop, state); } - return icon; + return QObject::eventFilter(object, event); } ExampleClientModel::ExampleClientModel (QObject* parent) @@ -161,6 +174,62 @@ int ExampleClientModel::rowCount(const QModelIndex &parent) const return m_nameList.size(); } +SwitcherItem::SwitcherItem(QObject *parent) + : QObject(parent) + , m_model(new ExampleClientModel(this)) + , m_item(nullptr) + , m_currentIndex(0) + , m_visible(false) +{ +} + +SwitcherItem::~SwitcherItem() +{ +} + +void SwitcherItem::setVisible(bool visible) +{ + if (m_visible == visible) { + return; + } + m_visible = visible; + emit visibleChanged(); +} + +void SwitcherItem::setItem(QObject *item) +{ + m_item = item; + emit itemChanged(); +} + +void SwitcherItem::setCurrentIndex(int index) +{ + if (m_currentIndex == index) { + return; + } + m_currentIndex = index; + emit currentIndexChanged(m_currentIndex); +} + +QRect SwitcherItem::screenGeometry() const +{ + return qApp->desktop()->screenGeometry(qApp->desktop()->primaryScreen()); +} + +void SwitcherItem::incrementIndex() +{ + setCurrentIndex((m_currentIndex + 1) % m_model->rowCount()); +} + +void SwitcherItem::decrementIndex() +{ + int index = m_currentIndex -1; + if (index < 0) { + index = m_model->rowCount() -1; + } + setCurrentIndex(index); +} + } // namespace KWin } // namespace TabBox diff --git a/kcmkwin/kwintabbox/layoutpreview.h b/kcmkwin/kwintabbox/layoutpreview.h index 6839b94aa0..7db9a07e9f 100644 --- a/kcmkwin/kwintabbox/layoutpreview.h +++ b/kcmkwin/kwintabbox/layoutpreview.h @@ -22,7 +22,7 @@ along with this program. If not, see . #include #include -#include +#include namespace KWin { @@ -30,23 +30,18 @@ namespace KWin namespace TabBox { -class LayoutPreview : public QQuickView +class SwitcherItem; + +class LayoutPreview : public QObject { Q_OBJECT public: - explicit LayoutPreview(QWindow *parent = nullptr); + explicit LayoutPreview(const QString &path, QObject *parent = nullptr); virtual ~LayoutPreview(); - void setLayout(const QString &path, const QString &name); -}; - -class TabBoxImageProvider : public QQuickImageProvider -{ -public: - explicit TabBoxImageProvider(QAbstractListModel *model); - virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); + virtual bool eventFilter(QObject *object, QEvent *event) override; private: - QAbstractListModel *m_model; + SwitcherItem *m_item; }; class ExampleClientModel : public QAbstractListModel @@ -64,6 +59,79 @@ private: QStringList m_nameList; }; + +class SwitcherItem : public QObject +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged) + Q_PROPERTY(QRect screenGeometry READ screenGeometry NOTIFY screenGeometryChanged) + Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged) + Q_PROPERTY(bool allDesktops READ isAllDesktops NOTIFY allDesktopsChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + + /** + * The main QML item that will be displayed in the Dialog + */ + Q_PROPERTY(QObject *item READ item WRITE setItem NOTIFY itemChanged) + + Q_CLASSINFO("DefaultProperty", "item") +public: + SwitcherItem(QObject *parent = nullptr); + virtual ~SwitcherItem(); + + QAbstractItemModel *model() const; + QRect screenGeometry() const; + bool isVisible() const; + bool isAllDesktops() const; + int currentIndex() const; + void setCurrentIndex(int index); + QObject *item() const; + void setItem(QObject *item); + + void setVisible(bool visible); + void incrementIndex(); + void decrementIndex(); + +Q_SIGNALS: + void visibleChanged(); + void currentIndexChanged(int index); + void modelChanged(); + void allDesktopsChanged(); + void screenGeometryChanged(); + void itemChanged(); + +private: + QAbstractItemModel *m_model; + QObject *m_item; + int m_currentIndex; + bool m_visible; +}; + +inline QAbstractItemModel *SwitcherItem::model() const +{ + return m_model; +} + +inline bool SwitcherItem::isVisible() const +{ + return m_visible; +} + +inline bool SwitcherItem::isAllDesktops() const +{ + return true; +} + +inline int SwitcherItem::currentIndex() const +{ + return m_currentIndex; +} + +inline QObject *SwitcherItem::item() const +{ + return m_item; +} + } // namespace TabBox } // namespace KWin diff --git a/kcmkwin/kwintabbox/main.cpp b/kcmkwin/kwintabbox/main.cpp index 819c4dac70..5bda6887e0 100644 --- a/kcmkwin/kwintabbox/main.cpp +++ b/kcmkwin/kwintabbox/main.cpp @@ -61,7 +61,6 @@ KWinTabBoxConfigForm::KWinTabBoxConfigForm(QWidget* parent) KWinTabBoxConfig::KWinTabBoxConfig(QWidget* parent, const QVariantList& args) : KCModule(parent, args) , m_config(KSharedConfig::openConfig("kwinrc")) - , m_layoutPreview(NULL) { QTabWidget* tabWidget = new QTabWidget(this); m_primaryTabBoxUi = new KWinTabBoxConfigForm(tabWidget); @@ -475,12 +474,6 @@ void KWinTabBoxConfig::effectSelectionChanged(int index) if (!ui->showTabBox->isChecked()) return; ui->highlightWindowCheck->setEnabled(index >= Layout); - if (m_layoutPreview && m_layoutPreview->isVisible()) { - if (index < Layout) - m_layoutPreview->hide(); - else - m_layoutPreview->setLayout(ui->effectCombo->itemData(index, Qt::UserRole+1).toString(), ui->effectCombo->itemText(index)); - } } void KWinTabBoxConfig::tabBoxToggled(bool on) { @@ -496,13 +489,8 @@ void KWinTabBoxConfig::configureEffectClicked() const int effect = ui->effectCombo->currentIndex(); if (effect >= Layout) { - if (!m_layoutPreview) { - m_layoutPreview = new LayoutPreview(); - m_layoutPreview->setTitle(i18n("Tabbox layout preview")); - m_layoutPreview->setFlags(Qt::Dialog); - } - m_layoutPreview->setLayout(ui->effectCombo->itemData(effect, Qt::UserRole+1).toString(), ui->effectCombo->itemText(effect)); - m_layoutPreview->show(); + // TODO: here we need to show the preview + new LayoutPreview(ui->effectCombo->itemData(effect, Qt::UserRole+1).toString(), this); } else { QPointer configDialog = new QDialog(this); configDialog->setLayout(new QVBoxLayout); diff --git a/kcmkwin/kwintabbox/main.h b/kcmkwin/kwintabbox/main.h index 3344d00e0b..f8b5ac257d 100644 --- a/kcmkwin/kwintabbox/main.h +++ b/kcmkwin/kwintabbox/main.h @@ -35,7 +35,6 @@ namespace KWin namespace TabBox { -class LayoutPreview; } @@ -87,7 +86,6 @@ private: KShortcutsEditor* m_editor; TabBox::TabBoxConfig m_tabBoxConfig; TabBox::TabBoxConfig m_tabBoxAlternativeConfig; - TabBox::LayoutPreview *m_layoutPreview; bool effectEnabled(const QString& effect, const KConfigGroup& cfg) const; }; diff --git a/kcmkwin/kwintabbox/qml/main.qml b/kcmkwin/kwintabbox/qml/main.qml deleted file mode 100644 index 911e81a749..0000000000 --- a/kcmkwin/kwintabbox/qml/main.qml +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************** - 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 2.0 - -Item { - id : preview - Loader { - property int screenWidth : preview.width - property int screenHeight : preview.height - property bool allDesktops: true - width: preview.width - height: preview.height - textElement.height - source: sourcePath - anchors.centerIn: parent - onLoaded: { - if (item.allDesktops != undefined) { - item.allDesktops = allDesktops; - } - if (item.setModel) { - item.setModel(clientModel); - } - if (item.screenWidth != undefined) { - item.screenWidth = screenWidth; - } - if (item.screenHeight != undefined) { - item.screenHeight = screenHeight; - } - item.width = preview.width; - item.height = preview.height - textElement.height; - } - } - Text { - id: textElement - font.bold: true - text: name - anchors { - horizontalCenter: parent.horizontalCenter - bottom: parent.bottom - } - visible: true - } -}