[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.
remotes/origin/Plasma/5.0
Martin Gräßlin 12 years ago
parent 2e78144a14
commit 058a5da2dd
  1. 11
      kcmkwin/kwintabbox/CMakeLists.txt
  2. 169
      kcmkwin/kwintabbox/layoutpreview.cpp
  3. 92
      kcmkwin/kwintabbox/layoutpreview.h
  4. 16
      kcmkwin/kwintabbox/main.cpp
  5. 2
      kcmkwin/kwintabbox/main.h
  6. 59
      kcmkwin/kwintabbox/qml/main.qml

@ -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} )

@ -20,12 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// own
#include "layoutpreview.h"
#include "thumbnailitem.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QQmlEngine>
#include <QQmlContext>
#include <QtCore/QStandardPaths>
#include <KDE/KConfigGroup>
#include <KDE/KDesktopFile>
#include <KDE/KIconEffect>
#include <KDE/KIconLoader>
#include <KDE/KLocalizedString>
#include <KDE/KService>
@ -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<WindowThumbnailItem>("org.kde.kwin", 2, 0, "ThumbnailItem");
qmlRegisterType<SwitcherItem>("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<SwitcherItem*>(item)) {
return i;
} else if (QQuickWindow *w = qobject_cast<QQuickWindow*>(item)) {
return w->contentItem()->findChild<SwitcherItem*>();
}
return item->findChild<SwitcherItem*>();
};
if (SwitcherItem *switcher = findSwitcher()) {
m_item = switcher;
switcher->setVisible(true);
}
auto findWindow = [item]() -> QQuickWindow* {
if (!item) {
return nullptr;
}
if (QQuickWindow *w = qobject_cast<QQuickWindow*>(item)) {
return w;
}
return item->findChild<QQuickWindow*>();
};
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<WindowThumbnailItem>("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<QKeyEvent*>(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<QWindow*>(object)) {
if (!w->geometry().contains(static_cast<QMouseEvent*>(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

@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QAbstractListModel>
#include <QQuickView>
#include <QQuickImageProvider>
#include <QRect>
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

@ -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<QDialog> configDialog = new QDialog(this);
configDialog->setLayout(new QVBoxLayout);

@ -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;
};

@ -1,59 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
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
}
}
Loading…
Cancel
Save