kwin/kcmkwin/kwincompositing/model.cpp

354 lines
12 KiB
C++
Raw Normal View History

2013-06-25 14:07:48 +00:00
/**************************************************************************
* KWin - the KDE window manager *
* This file is part of the KDE project. *
* *
* Copyright (C) 2013 Antonis Tsiapaliokas <kok3rs@gmail.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 "model.h"
#include "effectconfig.h"
2013-08-17 08:28:09 +00:00
#include "compositing.h"
#include <KDE/KPluginInfo>
#include <KDE/KService>
#include <KDE/KServiceTypeTrader>
#include <KDE/KSharedConfig>
#include <KDE/KCModuleProxy>
2013-06-25 14:07:48 +00:00
#include <QAbstractItemModel>
#include <QDBusConnection>
2013-08-08 13:47:01 +00:00
#include <QDBusInterface>
#include <QDBusPendingCall>
#include <QDBusMessage>
2013-06-25 14:07:48 +00:00
#include <QHash>
#include <QVariant>
#include <QList>
#include <QString>
#include <QQmlEngine>
#include <QtQml>
#include <QDebug>
namespace KWin {
namespace Compositing {
2013-06-25 14:07:48 +00:00
EffectModel::EffectModel(QObject *parent)
: QAbstractItemModel(parent) {
2013-06-25 14:07:48 +00:00
loadEffects();
}
QHash< int, QByteArray > EffectModel::roleNames() const
{
2013-06-25 14:07:48 +00:00
QHash<int, QByteArray> roleNames;
roleNames[NameRole] = "NameRole";
roleNames[DescriptionRole] = "DescriptionRole";
roleNames[AuthorNameRole] = "AuthorNameRole";
roleNames[AuthorEmailRole] = "AuthorEmailRole";
roleNames[LicenseRole] = "LicenseRole";
roleNames[VersionRole] = "VersionRole";
roleNames[CategoryRole] = "CategoryRole";
roleNames[ServiceNameRole] = "ServiceNameRole";
roleNames[EffectStatusRole] = "EffectStatusRole";
return roleNames;
2013-06-25 14:07:48 +00:00
}
QModelIndex EffectModel::index(int row, int column, const QModelIndex &parent) const {
2013-08-09 13:34:50 +00:00
if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effectsList.count()) {
return QModelIndex();
}
return createIndex(row, column);
}
QModelIndex EffectModel::parent(const QModelIndex &child) const {
Q_UNUSED(child)
2013-08-09 13:34:50 +00:00
return QModelIndex();
}
int EffectModel::columnCount(const QModelIndex &parent) const {
return 1;
}
2013-06-25 14:07:48 +00:00
int EffectModel::rowCount(const QModelIndex &parent) const {
2013-08-09 13:34:50 +00:00
if (parent.isValid()) {
return 0;
}
2013-06-25 14:07:48 +00:00
return m_effectsList.count();
}
QVariant EffectModel::data(const QModelIndex &index, int role) const {
if (!index.isValid()) {
return QVariant();
}
EffectData currentEffect = m_effectsList.at(index.row());
2013-06-25 14:07:48 +00:00
switch (role) {
case Qt::DisplayRole:
case NameRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).name;
case DescriptionRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).description;
case AuthorNameRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).authorName;
case AuthorEmailRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).authorEmail;
case LicenseRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).license;
case VersionRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).version;
case CategoryRole:
2013-06-25 14:07:48 +00:00
return m_effectsList.at(index.row()).category;
case ServiceNameRole:
return m_effectsList.at(index.row()).serviceName;
case EffectStatusRole:
return m_effectsList.at(index.row()).effectStatus;
2013-06-25 14:07:48 +00:00
default:
return QVariant();
}
}
bool EffectModel::setData(const QModelIndex& index, const QVariant& value, int role) {
if (!index.isValid())
return QAbstractItemModel::setData(index, value, role);
if (role == EffectModel::EffectStatusRole) {
m_effectsList[index.row()].effectStatus = value.toBool();
const QString effectServiceName = m_effectsList[index.row()].serviceName;
if (effectServiceName == "kwin4_effect_slide") {
handleDesktopSwitching(index.row());
} else if (effectServiceName == "kwin4_effect_fadedesktop") {
handleDesktopSwitching(index.row());
} else if (effectServiceName == "kwin4_effect_cubeslide") {
handleDesktopSwitching(index.row());
}
emit dataChanged(index, index);
return true;
} else if (role == EffectModel::WindowManagementRole) {
bool enabled = value.toBool();
handleWindowManagement(index.row(), enabled);
emit dataChanged(index, index);
return true;
}
return QAbstractItemModel::setData(index, value, role);
}
2013-06-25 14:07:48 +00:00
void EffectModel::loadEffects() {
EffectData effect;
KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins");
2013-08-08 13:47:01 +00:00
QDBusInterface interface(QStringLiteral("org.kde.kwin"), QStringLiteral("/Effects"));
2013-06-25 14:07:48 +00:00
beginResetModel();
2013-07-31 07:39:06 +00:00
KService::List offers = KServiceTypeTrader::self()->query("KWin/Effect");
for(KService::Ptr service : offers) {
2013-08-21 10:15:24 +00:00
const QString effectPluginPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kde5/services/"+ service->entryPath(), QStandardPaths::LocateFile);
KPluginInfo plugin(effectPluginPath);
2013-06-25 14:07:48 +00:00
effect.name = plugin.name();
effect.description = plugin.comment();
effect.authorName = plugin.author();
effect.authorEmail = plugin.email();
effect.license = plugin.license();
effect.version = plugin.version();
effect.category = plugin.category();
2013-08-21 10:15:24 +00:00
effect.serviceName = plugin.pluginName();
effect.effectStatus = kwinConfig.readEntry(effect.serviceName + "Enabled", false);
2013-08-08 13:47:01 +00:00
if (effect.effectStatus) {
interface.asyncCall("loadEffect", effect.serviceName);
} else {
interface.asyncCall("unloadEffect", effect.serviceName);
}
2013-06-25 14:07:48 +00:00
m_effectsList << effect;
}
2013-08-08 13:47:01 +00:00
qSort(m_effectsList.begin(), m_effectsList.end(), [](const EffectData &a, const EffectData &b) {
return a.category < b.category;
});
2013-07-31 07:39:06 +00:00
endResetModel();
}
void EffectModel::handleDesktopSwitching(int row) {
//Q: Why do we need the handleDesktopSwitching?
//A: Because of the setData, when we enable the effect
//and then we scroll, our model is being updated,
//so the setData is being called again, and as a result
//of that we have multiple effects enabled for the desktop switching.
const QString currentEffect = m_effectsList[row].serviceName;
for (int it = 0; it < m_effectsList.size(); it++) {
EffectData effect = m_effectsList.at(it);
if (effect.serviceName == "kwin4_effect_slide" && currentEffect != effect.serviceName && effect.effectStatus) {
m_effectsList[it].effectStatus = !m_effectsList[it].effectStatus;
} else if (effect.serviceName == "kwin4_effect_cubeslide" && currentEffect != effect.serviceName && effect.effectStatus) {
m_effectsList[it].effectStatus = !m_effectsList[it].effectStatus;
}else if (effect.serviceName == "kwin4_effect_fadedesktop" && currentEffect != effect.serviceName && effect.effectStatus) {
m_effectsList[it].effectStatus = !m_effectsList[it].effectStatus;
}
}
2013-06-25 14:07:48 +00:00
}
void EffectModel::handleWindowManagement(int row, bool enabled) {
m_effectsList[row].effectStatus = enabled;
}
int EffectModel::findRowByServiceName(const QString &serviceName) {
for (int it=0; m_effectsList.size(); it++) {
if (m_effectsList.at(it).serviceName == serviceName) {
return it;
}
}
return -1;
}
bool EffectModel::effectListContains(const QString &effectFilter, int source_row) {
EffectData effect;
effect = m_effectsList.at(source_row);
return effect.name.contains(effectFilter, Qt::CaseInsensitive);
}
QString EffectModel::findImage(const QString &imagePath, int size) {
const QString relativePath("icons/oxygen/" + QString::number(size) + 'x' + QString::number(size) + '/' + imagePath);
const QString fullImagePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, relativePath, QStandardPaths::LocateFile);
return fullImagePath;
}
void EffectModel::reload() {
m_effectsList.clear();
loadEffects();
}
void EffectModel::effectStatus(const QModelIndex &index, bool effectState) {
setData(index, effectState, EffectModel::EffectStatusRole);
}
void EffectModel::syncConfig() {
KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins");
for (auto it = m_effectsList.begin(); it != m_effectsList.end(); it++) {
EffectData effect = *(it);
bool effectConfigStatus = kwinConfig.readEntry(effect.serviceName + "Enabled", false);
if (effect.effectStatus) {
kwinConfig.writeEntry(effect.serviceName + "Enabled", effect.effectStatus);
} else if (effect.effectStatus != effectConfigStatus) {
kwinConfig.writeEntry(effect.serviceName + "Enabled", effect.effectStatus);
}
}
kwinConfig.sync();
}
void EffectModel::enableWidnowManagement(bool enabled) {
int desktopGridRow = findRowByServiceName("kwin4_effect_desktopgrid");
const QModelIndex desktopGridIndex = createIndex(desktopGridRow, 0);
setData(desktopGridIndex, enabled, EffectModel::WindowManagementRole);
int dialogParentRow = findRowByServiceName("kwin4_effect_dialogparent");
const QModelIndex dialogParentIndex = createIndex(dialogParentRow, 0);
setData(dialogParentIndex, enabled, EffectModel::WindowManagementRole);
int presentWindowsRow = findRowByServiceName("kwin4_effect_presentwindows");
const QModelIndex presentWindowsIndex = createIndex(presentWindowsRow, 0);
setData(presentWindowsIndex, enabled, EffectModel::WindowManagementRole);
}
EffectFilterModel::EffectFilterModel(QObject *parent)
:QSortFilterProxyModel(parent),
m_effectModel(0)
{
}
EffectModel *EffectFilterModel::effectModel() const {
return m_effectModel;
}
const QString &EffectFilterModel::filter() const {
return m_filter;
}
void EffectFilterModel::setEffectModel(EffectModel *effectModel) {
if (effectModel == m_effectModel) {
return;
}
m_effectModel = effectModel;
setSourceModel(m_effectModel);
emit effectModelChanged();
}
void EffectFilterModel::setFilter(const QString &filter) {
if (filter == m_filter) {
return;
}
m_filter = filter;
emit filterChanged();
invalidateFilter();
}
bool EffectFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
if (!m_effectModel) {
return false;
}
if (m_filter.isEmpty()) {
return true;
}
QModelIndex index = m_effectModel->index(source_row, 0, source_parent);
if (!index.isValid()) {
return false;
}
QVariant data = index.data();
if (!data.isValid()) {
//An invalid QVariant is valid data
return true;
}
if (m_effectModel->effectListContains(m_filter, source_row)) {
return true;
}
return false;
}
2013-06-25 14:07:48 +00:00
EffectView::EffectView(QWindow *parent)
: QQuickView(parent)
{
qmlRegisterType<EffectModel>("org.kde.kwin.kwincompositing", 1, 0, "EffectModel");
qmlRegisterType<EffectConfig>("org.kde.kwin.kwincompositing", 1, 0, "EffectConfig");
qmlRegisterType<EffectFilterModel>("org.kde.kwin.kwincompositing", 1, 0, "EffectFilterModel");
2013-08-17 08:28:09 +00:00
qmlRegisterType<Compositing>("org.kde.kwin.kwincompositing", 1, 0, "Compositing");
2013-06-25 14:07:48 +00:00
init();
}
void EffectView::init() {
QString mainFile = QStandardPaths::locate(QStandardPaths::DataLocation, "qml/main.qml", QStandardPaths::LocateFile);
setResizeMode(QQuickView::SizeRootObjectToView);
setSource(QUrl(mainFile));
}
}//end namespace Compositing
}//end namespace KWin