Decoration KCM uses QML and loads QML based Aurorae themes

This allows to have the Aurorae themes interactive.
This commit is contained in:
Martin Gräßlin 2012-01-12 11:28:02 +01:00
parent a0efa6453e
commit 5ce7381f15
10 changed files with 180 additions and 192 deletions

View file

@ -11,11 +11,7 @@ set(kcm_kwindecoration_PART_SRCS
buttonsconfigdialog.cpp
configdialog.cpp
preview.cpp
decorationdelegate.cpp
decorationmodel.cpp
${AURORAE_SOURCE_DIR}/auroraebutton.cpp
${AURORAE_SOURCE_DIR}/auroraescene.cpp
${AURORAE_SOURCE_DIR}/auroraetab.cpp
${AURORAE_SOURCE_DIR}/auroraetheme.cpp
${AURORAE_SOURCE_DIR}/themeconfig.cpp
)
@ -28,9 +24,10 @@ kde4_add_ui_files(kcm_kwindecoration_PART_SRCS
)
kde4_add_plugin(kcm_kwindecoration ${kcm_kwindecoration_PART_SRCS})
target_link_libraries(kcm_kwindecoration ${KDE4_PLASMA_LIBS} ${KDE4_KNEWSTUFF3_LIBS} kdecorations ${X11_LIBRARIES})
target_link_libraries(kcm_kwindecoration ${KDE4_PLASMA_LIBS} ${KDE4_KNEWSTUFF3_LIBS} kdecorations ${QT_QTDECLARATIVE_LIBRARY} ${X11_LIBRARIES})
install(TARGETS kcm_kwindecoration DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES kwindecoration.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
install( FILES qml/main.qml qml/AuroraeDecoration.qml DESTINATION ${DATA_INSTALL_DIR}/kwin/kcm_kwindecoration)

View file

@ -22,13 +22,10 @@
</widget>
</item>
<item>
<widget class="QListView" name="decorationList">
<widget class="QDeclarativeView" name="decorationList">
<property name="whatsThis">
<string>Select the window decoration. This is the look and feel of both the window borders and the window handle.</string>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
<item>

View file

@ -1,62 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decorationdelegate.h"
#include "decorationmodel.h"
#include <QPainter>
#include <QSortFilterProxyModel>
#include <QApplication>
namespace KWin
{
const int margin = 5;
DecorationDelegate::DecorationDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}
DecorationDelegate::~DecorationDelegate()
{
}
void DecorationDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
// highlight selected item
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &option, painter);
QPixmap pixmap = index.model()->data(index, DecorationModel::PixmapRole).value<QPixmap>();
const QSize previewArea = option.rect.size() - QSize(2 * margin, 2 * margin);
if (pixmap.isNull() || pixmap.size() != previewArea) {
emit regeneratePreview(static_cast< const QSortFilterProxyModel* >(index.model())->mapToSource(index),
previewArea);
} else
painter->drawPixmap(option.rect.topLeft() + QPoint(margin, margin), pixmap);
}
QSize DecorationDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
Q_UNUSED(option)
Q_UNUSED(index)
return QSize(450, 150);
}
} // namespace KWin

View file

@ -1,45 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.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, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DECORATIONDELEGATE_H
#define KWIN_DECORATIONDELEGATE_H
#include <QtGui/QStyledItemDelegate>
class KPushButton;
namespace KWin
{
class DecorationDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
DecorationDelegate(QObject* parent = 0);
~DecorationDelegate();
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
signals:
void regeneratePreview(const QModelIndex& index, const QSize& size) const;
};
} // namespace KWin
#endif // KWIN_DECORATIONDELEGATE_H

View file

@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decorationmodel.h"
#include "preview.h"
#include "auroraetheme.h"
#include "auroraescene.h"
// kwin
#include <kdecorationfactory.h>
// Qt
@ -37,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KIcon>
#include <KLocale>
#include <KStandardDirs>
#include "kwindecoration.h"
namespace KWin
{
@ -48,12 +47,15 @@ DecorationModel::DecorationModel(KSharedConfigPtr config, QObject* parent)
, m_customButtons(false)
, m_leftButtons(QString())
, m_rightButtons(QString())
, m_theme(new Aurorae::AuroraeTheme(this))
, m_scene(new Aurorae::AuroraeScene(m_theme, QString(), QString(), true, this))
, m_renderWidget(new QWidget(0))
{
QHash<int, QByteArray> roleNames;
roleNames[Qt::DisplayRole] = "display";
roleNames[DecorationModel::PixmapRole] = "preview";
roleNames[TypeRole] = "type";
roleNames[AuroraeNameRole] = "auroraeThemeName";
setRoleNames(roleNames);
m_config = KSharedConfig::openConfig("auroraerc");
m_scene->setIcon(KIcon("xorg"));
findDecorations();
}
@ -258,7 +260,7 @@ void DecorationModel::regeneratePreviews()
QList<DecorationModelData>::iterator it = m_decorations.begin();
for (int i = 0; i < m_decorations.count(); i++) {
regeneratePreview(index(i), m_decorations.at(i).preview.size());
regeneratePreview(index(i), QSize(qobject_cast<KWinDecorationModule*>(QObject::parent())->itemWidth(), 150));
}
}
@ -299,52 +301,6 @@ void DecorationModel::regeneratePreview(const QModelIndex& index, const QSize& s
m_preview->setTempBorderSize(m_plugins, data.borderSize);
data.preview = m_preview->preview(&document, m_renderWidget);
break;
case DecorationModelData::AuroraeDecoration: {
QPixmap pix(size);
pix.fill(Qt::transparent);
KConfig conf("aurorae/themes/" + data.auroraeName + '/' + data.auroraeName + "rc", KConfig::FullConfig, "data");
m_theme->loadTheme(data.auroraeName, conf);
m_theme->setBorderSize(data.borderSize);
m_theme->setButtonSize(data.buttonSize);
m_scene->setButtons(m_customButtons ? m_leftButtons : m_theme->defaultButtonsLeft(),
m_customButtons ? m_rightButtons : m_theme->defaultButtonsRight());
int left, top, right, bottom;
m_theme->borders(left, top, right, bottom, false);
int padLeft, padRight, padTop, padBottom;
m_theme->padding(padLeft, padTop, padRight, padBottom);
top = qMin(int(top * .9), 30);
int xoffset = qMin(qMax(10, QApplication::isRightToLeft() ? left : right), 30);
m_scene->setSceneRect(0, 0 ,
size.width() - xoffset - 20 + padLeft + padRight,
size.height() - top - 20 + padLeft + padRight);
m_scene->setActive(false, false);
m_scene->addTab(i18n("Inactive Window"));
m_scene->updateLayout();
QPainter painter(&pix);
QRect rect = QRectF(QPointF(10 + xoffset - padLeft, 10 - padTop), m_scene->sceneRect().size()).toRect();
m_scene->render(&painter, QStyle::visualRect(QApplication::layoutDirection(), pix.rect(), rect));
m_scene->setActive(true, false);
m_scene->setCaption(i18n("Active Window"));
rect = QRectF(QPointF(10 - padLeft, top + 10 - padTop), m_scene->sceneRect().size()).toRect();
m_scene->render(&painter, QStyle::visualRect(QApplication::layoutDirection(), pix.rect(), rect));
const int width = rect.width() - left - right - padLeft - padRight;
const int height = rect.height() - top - bottom - padTop - padBottom;
m_renderWidget->setGeometry(0, 0, width, height);
painter.save();
const QPoint topLeft = QStyle::visualRect(QApplication::layoutDirection(), pix.rect(), rect).topLeft() +
QPoint(left + padLeft, top + padTop);
m_renderWidget->render(&painter, topLeft);
painter.restore();
//Enable word-wrap
document.setTextWidth(width - margin * 2);
painter.save();
painter.translate(topLeft);
document.drawContents(&painter, QRectF(margin, margin, width - margin * 2, height - margin * 2));
painter.restore();
data.preview = pix;
break;
}
default:
// nothing
break;

View file

@ -30,12 +30,6 @@ class KDesktopFile;
class KDecorationPlugins;
class KDecorationPreview;
namespace Aurorae
{
class AuroraeTheme;
class AuroraeScene;
}
namespace KWin
{
@ -113,11 +107,11 @@ public:
public slots:
void regeneratePreview(const QModelIndex& index, const QSize& size);
void regeneratePreviews();
private:
void findDecorations();
void findAuroraeThemes();
void regeneratePreviews();
void metaData(DecorationModelData& data, const KDesktopFile& df);
QList<DecorationModelData> m_decorations;
KDecorationPlugins* m_plugins;
@ -125,8 +119,6 @@ private:
bool m_customButtons;
QString m_leftButtons;
QString m_rightButtons;
Aurorae::AuroraeTheme* m_theme;
Aurorae::AuroraeScene* m_scene;
KSharedConfigPtr m_config;
QWidget* m_renderWidget;
};

View file

@ -31,17 +31,22 @@
#include "kwindecoration.h"
#include "buttonsconfigdialog.h"
#include "configdialog.h"
#include "decorationdelegate.h"
#include "decorationmodel.h"
#include "auroraetheme.h"
// Qt
#include <QtDBus/QtDBus>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeView>
#include <QtGui/QSortFilterProxyModel>
// KDE
#include <KAboutData>
#include <KDialog>
#include <KLocale>
#include <KNS3/DownloadDialog>
#include <KDE/KStandardDirs>
#include <KPluginFactory>
#include <qdeclarative.h>
// KCModule plugin interface
// =========================
@ -69,9 +74,8 @@ KWinDecorationModule::KWinDecorationModule(QWidget* parent, const QVariantList &
, m_rightButtons(QString())
, m_configLoaded(false)
{
qmlRegisterType<Aurorae::AuroraeTheme>("org.kde.kwin.aurorae", 0, 1, "AuroraeTheme");
m_ui = new KWinDecorationForm(this);
DecorationDelegate* delegate = new DecorationDelegate(this);
m_ui->decorationList->setItemDelegate(delegate);
m_ui->configureDecorationButton->setIcon(KIcon("configure"));
m_ui->configureButtonsButton->setIcon(KIcon("configure"));
m_ui->ghnsButton->setIcon(KIcon("get-hot-new-stuff"));
@ -85,16 +89,21 @@ KWinDecorationModule::KWinDecorationModule(QWidget* parent, const QVariantList &
m_proxyModel = new QSortFilterProxyModel(this);
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_ui->decorationList->setModel(m_proxyModel);
m_ui->decorationList->setResizeMode(QDeclarativeView::SizeRootObjectToView);
foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) {
m_ui->decorationList->engine()->addImportPath(importPath);
}
m_ui->decorationList->rootContext()->setContextProperty("decorationModel", m_proxyModel);
m_ui->decorationList->rootContext()->setContextProperty("auroraeSource", KStandardDirs::locate("data", "kwin/aurorae/aurorae.qml"));
m_ui->decorationList->setSource(KStandardDirs::locate("data", "kwin/kcm_kwindecoration/main.qml"));
readConfig(style);
connect(m_ui->decorationList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged()));
connect(m_ui->decorationList->rootObject(), SIGNAL(currentIndexChanged()), SLOT(slotSelectionChanged()));
connect(m_ui->decorationList->rootObject(), SIGNAL(widthChanged()), m_model, SLOT(regeneratePreviews()));
connect(m_ui->configureButtonsButton, SIGNAL(clicked(bool)), this, SLOT(slotConfigureButtons()));
connect(m_ui->ghnsButton, SIGNAL(clicked(bool)), SLOT(slotGHNSClicked()));
connect(m_ui->searchEdit, SIGNAL(textChanged(QString)), m_proxyModel, SLOT(setFilterFixedString(QString)));
connect(delegate, SIGNAL(regeneratePreview(QModelIndex,QSize)),
m_model, SLOT(regeneratePreview(QModelIndex,QSize)));
connect(m_ui->configureDecorationButton, SIGNAL(clicked(bool)), SLOT(slotConfigureDecoration()));
KAboutData *about =
@ -104,6 +113,7 @@ KWinDecorationModule::KWinDecorationModule(QWidget* parent, const QVariantList &
ki18n("(c) 2001 Karol Szwed"));
about->addAuthor(ki18n("Karol Szwed"), KLocalizedString(), "gallium@kde.org");
setAboutData(about);
m_model->regeneratePreviews();
}
@ -111,6 +121,11 @@ KWinDecorationModule::~KWinDecorationModule()
{
}
int KWinDecorationModule::itemWidth() const
{
return m_ui->decorationList->rootObject()->property("width").toInt();
}
// This is the selection handler setting
void KWinDecorationModule::slotSelectionChanged()
{
@ -144,13 +159,13 @@ void KWinDecorationModule::readConfig(const KConfigGroup & conf)
const QString themeName = group.readEntry("ThemeName", "example-deco");
const QModelIndex index = m_proxyModel->mapFromSource(m_model->indexOfAuroraeName(themeName));
if (index.isValid()) {
m_ui->decorationList->setCurrentIndex(index);
m_ui->decorationList->rootObject()->setProperty("currentIndex", index.row());
}
} else {
const QModelIndex index = m_proxyModel->mapFromSource(m_model->indexOfLibrary(libraryName));
if (index.isValid()) {
m_model->setBorderSize(index, borderSize);
m_ui->decorationList->setCurrentIndex(index);
m_ui->decorationList->rootObject()->setProperty("currentIndex", index.row());
}
}
@ -175,7 +190,7 @@ void KWinDecorationModule::readConfig(const KConfigGroup & conf)
// Writes the selected user configuration to the kwin config file
void KWinDecorationModule::writeConfig(KConfigGroup & conf)
{
const QModelIndex index = m_proxyModel->mapToSource(m_ui->decorationList->currentIndex());
const QModelIndex index = m_proxyModel->mapToSource(m_proxyModel->index(m_ui->decorationList->rootObject()->property("currentIndex").toInt(), 0));
const QString libName = m_model->data(index, DecorationModel::LibraryNameRole).toString();
// General settings
@ -231,7 +246,7 @@ void KWinDecorationModule::defaults()
m_showTooltips = true;
const QModelIndex index = m_proxyModel->mapFromSource(m_model->indexOfName(i18n("Oxygen")));
if (index.isValid())
m_ui->decorationList->setCurrentIndex(index);
m_ui->decorationList->rootObject()->setProperty("currentIndex", index.row());
m_leftButtons = KDecorationOptions::defaultTitleButtonsLeft();
m_rightButtons = KDecorationOptions::defaultTitleButtonsRight();
@ -273,7 +288,7 @@ void KWinDecorationModule::slotGHNSClicked()
QPointer<KNS3::DownloadDialog> downloadDialog = new KNS3::DownloadDialog("aurorae.knsrc", this);
if (downloadDialog->exec() == KDialog::Accepted) {
if (!downloadDialog->changedEntries().isEmpty()) {
const QModelIndex index = m_proxyModel->mapToSource(m_ui->decorationList->currentIndex());
const QModelIndex index = m_proxyModel->mapToSource(m_proxyModel->index(m_ui->decorationList->rootObject()->property("currentIndex").toInt(), 0));
const QString libraryName = m_model->data(index, DecorationModel::LibraryNameRole).toString();
bool aurorae = m_model->data(index, DecorationModel::TypeRole).toInt() == DecorationModelData::AuroraeDecoration;
const QString auroraeName = m_model->data(index, DecorationModel::AuroraeNameRole).toString();
@ -281,11 +296,11 @@ void KWinDecorationModule::slotGHNSClicked()
if (aurorae) {
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(m_model->indexOfAuroraeName(auroraeName));
if (proxyIndex.isValid())
m_ui->decorationList->setCurrentIndex(proxyIndex);
m_ui->decorationList->rootObject()->setProperty("currentIndex", proxyIndex.row());
} else {
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(m_model->indexOfLibrary(libraryName));
if (proxyIndex.isValid())
m_ui->decorationList->setCurrentIndex(proxyIndex);
m_ui->decorationList->rootObject()->setProperty("currentIndex", proxyIndex.row());
}
}
}
@ -294,7 +309,7 @@ void KWinDecorationModule::slotGHNSClicked()
void KWinDecorationModule::slotConfigureDecoration()
{
const QModelIndex index = m_proxyModel->mapToSource(m_ui->decorationList->currentIndex());
const QModelIndex index = m_proxyModel->mapToSource(m_proxyModel->index(m_ui->decorationList->rootObject()->property("currentIndex").toInt(), 0));
bool reload = false;
if (index.data(DecorationModel::TypeRole).toInt() == DecorationModelData::AuroraeDecoration) {
QPointer< KDialog > dlg = new KDialog(this);

View file

@ -66,6 +66,8 @@ public:
QString quickHelp() const;
int itemWidth() const;
signals:
void pluginLoad(const KConfigGroup& conf);
void pluginSave(KConfigGroup &conf);

View file

@ -0,0 +1,51 @@
/********************************************************************
Copyright (C) 2012 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 1.1
Item {
property alias active: decoration.active
property alias source: auroraeLoader.source
QtObject {
id: decoration
property bool active: false
property string caption: display
property int desktop: 1
property variant icon: "xorg"
property bool closeable: true
property bool maximizeable: true
property bool minimizeable: true
property bool modal: false
property bool moveable: true
property bool onAllDesktops: false
property bool preview: true
property bool resizeable: true
property bool setShade: false
property bool shade: false
property bool shadeable: false
property bool keepAbove: false
property bool keepBelow: false
property bool maximized: false
property bool providesContextHelp: true
property string leftButtons: "MS"
property string rightButtons: "HIA__X"
function titleMouseMoved() {}
}
Loader {
id: auroraeLoader
anchors.fill: parent
}
}

View file

@ -0,0 +1,85 @@
/********************************************************************
Copyright (C) 2012 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 1.1
import org.kde.qtextracomponents 0.1 as QtExtra
import org.kde.kwin.aurorae 0.1
import org.kde.plasma.components 0.1 as PlasmaComponents
Item {
property alias currentIndex: listView.currentIndex
ListView {
id: listView
anchors.fill: parent
model: decorationModel
highlight: PlasmaComponents.Highlight {
width: listView.width - 10
height: 140
hover: true
}
delegate: Item {
width: listView.width
height: 150
QtExtra.QPixmapItem {
pixmap: preview
anchors.fill: parent
visible: type == 0
}
Item {
id: aurorae
visible: type == 1
anchors.fill: parent
AuroraeTheme {
id: auroraeTheme
Component.onCompleted: {
auroraeTheme.loadTheme(auroraeThemeName);
inactiveAurorae.source = auroraeSource;
activeAurorae.source = auroraeSource;
}
}
AuroraeDecoration {
id: inactiveAurorae
active: false
anchors {
fill: parent
leftMargin: 40 - auroraeTheme.paddingLeft
rightMargin: 10 - auroraeTheme.paddingRight
topMargin: 10 - auroraeTheme.paddingTop
bottomMargin: 40 - auroraeTheme.paddingBottom
}
}
AuroraeDecoration {
id: activeAurorae
active: true
anchors {
fill: parent
leftMargin: 10 - auroraeTheme.paddingLeft
rightMargin: 40 - auroraeTheme.paddingRight
topMargin: 40 - auroraeTheme.paddingTop
bottomMargin: 10 - auroraeTheme.paddingBottom
}
}
}
MouseArea {
hoverEnabled: false
anchors.fill: parent
onClicked: {
listView.currentIndex = index;
}
}
}
}
}