kwin/kcmkwin/kwindecoration/decorationmodel.cpp
2011-01-31 20:07:03 +01:00

396 lines
15 KiB
C++

/********************************************************************
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 "decorationmodel.h"
#include "preview.h"
#include "auroraetheme.h"
#include "auroraescene.h"
// kwin
#include <kdecorationfactory.h>
// Qt
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QStyle>
#include <QtGui/QTextDocument>
// KDE
#include <KConfigGroup>
#include <KDesktopFile>
#include <KGlobalSettings>
#include <KIcon>
#include <KLocale>
#include <KStandardDirs>
namespace KWin
{
DecorationModel::DecorationModel(KSharedConfigPtr config, QObject* parent)
: QAbstractListModel(parent)
, m_plugins(new KDecorationPreviewPlugins(config))
, m_preview(new KDecorationPreview())
, 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))
{
m_config = KSharedConfig::openConfig("auroraerc");
m_scene->setIcon(KIcon("xorg"));
findDecorations();
}
DecorationModel::~DecorationModel()
{
delete m_preview;
delete m_plugins;
delete m_renderWidget;
}
void DecorationModel::reload()
{
m_decorations.clear();
findDecorations();
}
// Find all theme desktop files in all 'data' dirs owned by kwin.
// And insert these into a DecorationInfo structure
void DecorationModel::findDecorations()
{
beginResetModel();
const QStringList dirList = KGlobal::dirs()->findDirs("data", "kwin");
foreach (const QString & dir, dirList) {
QDir d(dir);
if (d.exists()) {
foreach (const QFileInfo & fi, d.entryInfoList()) {
const QString filename(fi.absoluteFilePath());
if (KDesktopFile::isDesktopFile(filename)) {
const KDesktopFile desktopFile(filename);
const QString libName = desktopFile.desktopGroup().readEntry("X-KDE-Library");
if (!libName.isEmpty() && libName.startsWith(QLatin1String("kwin3_"))) {
if (libName == "kwin3_aurorae") {
// read the Aurorae themes
findAuroraeThemes();
continue;
}
DecorationModelData data;
data.name = desktopFile.readName();
data.libraryName = libName;
data.type = DecorationModelData::NativeDecoration;
data.borderSize = KDecorationDefines::BorderNormal;
metaData(data, desktopFile);
m_decorations.append(data);
}
}
}
}
}
qSort(m_decorations.begin(), m_decorations.end(), DecorationModelData::less);
endResetModel();
}
void DecorationModel::findAuroraeThemes()
{
// get all desktop themes
QStringList themes = KGlobal::dirs()->findAllResources("data",
"aurorae/themes/*/metadata.desktop",
KStandardDirs::NoDuplicates);
foreach (const QString & theme, themes) {
int themeSepIndex = theme.lastIndexOf('/', -1);
QString themeRoot = theme.left(themeSepIndex);
int themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
KDesktopFile df(theme);
QString name = df.readName();
if (name.isEmpty()) {
name = packageName;
}
DecorationModelData data;
data.name = name;
data.libraryName = "kwin3_aurorae";
data.type = DecorationModelData::AuroraeDecoration;
data.auroraeName = packageName;
KConfigGroup config(m_config, data.auroraeName);
data.borderSize = (KDecorationDefines::BorderSize)config.readEntry< int >("BorderSize", KDecorationDefines::BorderNormal);
data.buttonSize = (KDecorationDefines::BorderSize)config.readEntry< int >("ButtonSize", KDecorationDefines::BorderNormal);
metaData(data, df);
m_decorations.append(data);
}
}
void DecorationModel::metaData(DecorationModelData& data, const KDesktopFile& df)
{
data.comment = df.readComment();
data.author = df.desktopGroup().readEntry("X-KDE-PluginInfo-Author", QString());
data.email = df.desktopGroup().readEntry("X-KDE-PluginInfo-Email", QString());
data.version = df.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString());
data.license = df.desktopGroup().readEntry("X-KDE-PluginInfo-License", QString());
data.website = df.desktopGroup().readEntry("X-KDE-PluginInfo-Website", QString());
}
int DecorationModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return m_decorations.count();
}
QVariant DecorationModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return QVariant();
switch(role) {
case Qt::DisplayRole:
case NameRole:
return m_decorations[ index.row()].name;
case LibraryNameRole:
return m_decorations[ index.row()].libraryName;
case PixmapRole:
return m_decorations[ index.row()].preview;
case TypeRole:
return m_decorations[ index.row()].type;
case AuroraeNameRole:
return m_decorations[ index.row()].auroraeName;
case PackageDescriptionRole:
return m_decorations[ index.row()].comment;
case PackageAuthorRole:
return m_decorations[ index.row()].author;
case PackageEmailRole:
return m_decorations[ index.row()].email;
case PackageWebsiteRole:
return m_decorations[ index.row()].website;
case PackageVersionRole:
return m_decorations[ index.row()].version;
case PackageLicenseRole:
return m_decorations[ index.row()].license;
case BorderSizeRole:
return static_cast< int >(m_decorations[ index.row()].borderSize);
case BorderSizesRole: {
QList< QVariant > sizes;
if (m_plugins->loadPlugin(m_decorations[ index.row()].libraryName) &&
m_plugins->factory() != NULL) {
foreach (KDecorationDefines::BorderSize size, m_plugins->factory()->borderSizes()) // krazy:exclude=foreach
sizes << int(size) ;
}
return sizes;
}
case ButtonSizeRole:
if (m_decorations[ index.row()].type == DecorationModelData::AuroraeDecoration)
return static_cast< int >(m_decorations[ index.row()].buttonSize);
else
return QVariant();
default:
return QVariant();
}
}
bool DecorationModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!index.isValid() || (role != BorderSizeRole && role != ButtonSizeRole))
return QAbstractItemModel::setData(index, value, role);
if (role == BorderSizeRole) {
m_decorations[ index.row()].borderSize = (KDecorationDefines::BorderSize)value.toInt();
if (m_decorations[ index.row()].type == DecorationModelData::AuroraeDecoration) {
KConfigGroup config(m_config, m_decorations[ index.row()].auroraeName);
config.writeEntry("BorderSize", value.toInt());
config.sync();
}
emit dataChanged(index, index);
regeneratePreview(index);
return true;
}
if (role == ButtonSizeRole && m_decorations[ index.row()].type == DecorationModelData::AuroraeDecoration) {
m_decorations[ index.row()].buttonSize = (KDecorationDefines::BorderSize)value.toInt();
KConfigGroup config(m_config, m_decorations[ index.row()].auroraeName);
config.writeEntry("ButtonSize", value.toInt());
config.sync();
emit dataChanged(index, index);
regeneratePreview(index);
return true;
}
return QAbstractItemModel::setData(index, value, role);
}
void DecorationModel::changeButtons(bool custom, const QString& left, const QString& right)
{
bool regenerate = (custom != m_customButtons);
if (!regenerate && custom)
regenerate = (left != m_leftButtons) || (right != m_rightButtons);
m_customButtons = custom;
m_leftButtons = left;
m_rightButtons = right;
if (regenerate)
regeneratePreviews();
}
void DecorationModel::setButtons(bool custom, const QString& left, const QString& right)
{
m_customButtons = custom;
m_leftButtons = left;
m_rightButtons = right;
}
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());
}
}
void DecorationModel::regeneratePreview(const QModelIndex& index, const QSize& size)
{
DecorationModelData& data = m_decorations[ index.row()];
//Use a QTextDocument to layout the text
QTextDocument document;
QString html = QString("<strong>%1</strong>").arg(data.name);
if (!data.author.isEmpty()) {
QString authorCaption = i18nc("Caption to decoration preview, %1 author name",
"by %1", data.author);
html += QString("<br /><span style=\"font-size: %1pt;\">%2</span>")
.arg(KGlobalSettings::smallestReadableFont().pointSize())
.arg(authorCaption);
}
QColor color = QApplication::palette().brush(QPalette::Text).color();
html = QString("<div style=\"color: %1\" align=\"center\">%2</div>").arg(color.name()).arg(html);
document.setHtml(html);
const int margin = 5;
switch(data.type) {
case DecorationModelData::NativeDecoration:
m_plugins->reset(KDecoration::SettingDecoration);
if (m_plugins->loadPlugin(data.libraryName) &&
m_preview->recreateDecoration(m_plugins))
m_preview->enablePreview();
else
m_preview->disablePreview();
m_plugins->destroyPreviousPlugin();
m_preview->resize(size);
m_preview->setTempButtons(m_plugins, m_customButtons, m_leftButtons, m_rightButtons);
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;
}
emit dataChanged(index, index);
}
void DecorationModel::regeneratePreview(const QModelIndex& index)
{
regeneratePreview(index, m_decorations.at(index.row()).preview.size());
}
QModelIndex DecorationModel::indexOfLibrary(const QString& libraryName) const
{
for (int i = 0; i < m_decorations.count(); i++) {
if (m_decorations.at(i).libraryName.compare(libraryName) == 0)
return index(i);
}
return QModelIndex();
}
QModelIndex DecorationModel::indexOfName(const QString& decoName) const
{
for (int i = 0; i < m_decorations.count(); i++) {
if (m_decorations.at(i).name.compare(decoName) == 0)
return index(i);
}
return QModelIndex();
}
QModelIndex DecorationModel::indexOfAuroraeName(const QString& auroraeName) const
{
for (int i = 0; i < m_decorations.count(); i++) {
const DecorationModelData& data = m_decorations.at(i);
if (data.type == DecorationModelData::AuroraeDecoration &&
data.auroraeName.compare(auroraeName) == 0)
return index(i);
}
return QModelIndex();
}
void DecorationModel::setBorderSize(const QModelIndex& index, KDecorationDefines::BorderSize size)
{
if (!index.isValid() || m_decorations[ index.row()].type == DecorationModelData::AuroraeDecoration)
return;
m_decorations[ index.row()].borderSize = size;
}
} // namespace KWin