Changeset View
Standalone View
kcmkwin/kwindecoration/kcm.cpp
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright 2014 Martin Gräßlin <mgraesslin@kde.org> | 2 | * Copyright (c) 2019 Valerio Pilo <vpilo@coldshock.net> | ||
3 | * | 3 | * | ||
4 | * This program is free software; you can redistribute it and/or | 4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | 5 | * modify it under the terms of the GNU Library General Public | ||
6 | * published by the Free Software Foundation; either version 2 of | 6 | * License version 2 as published by the Free Software Foundation. | ||
7 | * the License or (at your option) version 3 or any later version | | |||
8 | * accepted by the membership of KDE e.V. (or its successor approved | | |||
9 | * by the membership of KDE e.V.), which shall act as a proxy | | |||
10 | * defined in Section 14 of version 3 of the license. | | |||
11 | * | 7 | * | ||
12 | * This program is distributed in the hope that it will be useful, | 8 | * This library is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * GNU General Public License for more details. | 11 | * Library General Public License for more details. | ||
16 | * | 12 | * | ||
17 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU Library General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this library; see the file COPYING.LIB. If not, write to | ||
15 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
16 | * Boston, MA 02110-1301, USA. | ||||
19 | */ | 17 | */ | ||
18 | | ||||
20 | #include "kcm.h" | 19 | #include "kcm.h" | ||
21 | #include "decorationmodel.h" | 20 | #include "decorationmodel.h" | ||
22 | #include "declarative-plugin/buttonsmodel.h" | 21 | #include "declarative-plugin/buttonsmodel.h" | ||
23 | #include <config-kwin.h> | 22 | #include <config-kwin.h> | ||
24 | 23 | | |||
25 | // KDE | 24 | #include <KAboutData> | ||
26 | #include <KConfigGroup> | 25 | #include <KConfigGroup> | ||
26 | #include <KLocalizedString> | ||||
27 | #include <KPluginFactory> | 27 | #include <KPluginFactory> | ||
28 | #include <KSharedConfig> | 28 | #include <KNSCore/Engine> | ||
29 | #include <KDecoration2/DecorationButton> | 29 | | ||
30 | #include <KNewStuff3/KNS3/DownloadDialog> | | |||
31 | #include <kdeclarative/kdeclarative.h> | | |||
32 | // Qt | | |||
33 | #include <QDBusConnection> | 30 | #include <QDBusConnection> | ||
34 | #include <QDBusMessage> | 31 | #include <QDBusMessage> | ||
35 | #include <QFontDatabase> | 32 | #include <QDebug> | ||
36 | #include <QMenu> | | |||
37 | #include <QQmlContext> | | |||
38 | #include <QQmlEngine> | | |||
39 | #include <QQuickItem> | 33 | #include <QQuickItem> | ||
40 | #include <QQuickView> | 34 | #include <QQuickWindow> | ||
41 | #include <QSortFilterProxyModel> | 35 | #include <QSortFilterProxyModel> | ||
42 | #include <QStandardPaths> | | |||
43 | #include <QVBoxLayout> | | |||
44 | 36 | | |||
45 | K_PLUGIN_FACTORY(KDecorationFactory, | 37 | #include <KNewStuff3/KNS3/DownloadDialog> | ||
46 | registerPlugin<KDecoration2::Configuration::ConfigurationModule>(); | 38 | | ||
47 | ) | 39 | | ||
40 | K_PLUGIN_FACTORY_WITH_JSON(KCMKWinDecorationFactory, "kwindecoration.json", registerPlugin<KCMKWinDecoration>();) | ||||
48 | 41 | | |||
49 | Q_DECLARE_METATYPE(KDecoration2::BorderSize) | 42 | Q_DECLARE_METATYPE(KDecoration2::BorderSize) | ||
50 | 43 | | |||
51 | namespace KDecoration2 | | |||
52 | { | | |||
53 | 44 | | |||
davidedmundson: See next comment | |||||
54 | namespace Configuration | 45 | namespace | ||
55 | { | 46 | { | ||
SimpleKCM expects there to be a central flickable Item See the base class Kirigami.ScrollablePage Given our main central item is the tabview we might be best off inheriting from Kirigami.Page davidedmundson: SimpleKCM expects there to be a central flickable Item
See the base class Kirigami. | |||||
Setting a couple properties for the Page's flickable item seems to fix the issue, but I fear it's not enough: look at the last image of this gallery vpilo: Setting a couple properties for the Page's `flickable` item seems to fix the issue, but I fear… | |||||
@davidedmundson I can not find a good way to avoid this issue, do you have time to help me a bit? vpilo: @davidedmundson I can not find a good way to avoid this issue, do you have time to help me a… | |||||
56 | static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); | 47 | static const QString s_configFile { QStringLiteral("kwinrc") }; | ||
57 | #if HAVE_BREEZE_DECO | 48 | static const QString s_configGroup { QStringLiteral("org.kde.kdecoration2") }; | ||
58 | static const QString s_defaultPlugin = QStringLiteral(BREEZE_KDECORATION_PLUGIN_ID); | 49 | static const QString s_configPlugin { QStringLiteral("library") }; | ||
davidedmundson: that's not your issue, ignore this one. | |||||
59 | static const QString s_defaultTheme; | 50 | static const QString s_configTheme { QStringLiteral("theme") }; | ||
60 | #else | 51 | static const QString s_configBorderSize { QStringLiteral("BorderSize") }; | ||
61 | static const QString s_defaultPlugin = QStringLiteral("org.kde.kwin.aurorae"); | 52 | static const QString s_configCloseOnDoubleClickOnMenu { QStringLiteral("CloseOnDoubleClickOnMenu") }; | ||
Given that this is anonymous namespace you don't need static, also please don't indent contents of the namespace. zzag: Given that this is anonymous namespace you don't need `static`, also please don't indent… | |||||
62 | static const QString s_defaultTheme = QStringLiteral("kwin4_decoration_qml_plastik"); | 53 | static const QString s_configDecoButtonsOnLeft { QStringLiteral("ButtonsOnLeft") }; | ||
63 | #endif | 54 | static const QString s_configDecoButtonsOnRight { QStringLiteral("ButtonsOnRight") }; | ||
64 | static const QString s_borderSizeNormal = QStringLiteral("Normal"); | | |||
65 | static const QString s_ghnsIcon = QStringLiteral("get-hot-new-stuff"); | | |||
66 | 55 | | |||
67 | ConfigurationForm::ConfigurationForm(QWidget *parent) | 56 | static const KDecoration2::BorderSize s_defaultBorderSize = KDecoration2::BorderSize::Normal; | ||
68 | : QWidget(parent) | 57 | static const bool s_defaultCloseOnDoubleClickOnMenu = false; | ||
69 | { | | |||
70 | setupUi(this); | | |||
71 | } | | |||
72 | 58 | | |||
73 | static bool s_loading = false; | 59 | static const DecorationButtonsList s_defaultDecoButtonsOnLeft { | ||
74 | 60 | KDecoration2::DecorationButtonType::Menu, | |||
75 | ConfigurationModule::ConfigurationModule(QWidget *parent, const QVariantList &args) | 61 | KDecoration2::DecorationButtonType::OnAllDesktops | ||
76 | : KCModule(parent, args) | 62 | }; | ||
77 | , m_model(new DecorationsModel(this)) | 63 | static const DecorationButtonsList s_defaultDecoButtonsOnRight { | ||
78 | , m_proxyModel(new QSortFilterProxyModel(this)) | 64 | KDecoration2::DecorationButtonType::ContextHelp, | ||
79 | , m_ui(new ConfigurationForm(this)) | 65 | KDecoration2::DecorationButtonType::Minimize, | ||
80 | , m_leftButtons(new Preview::ButtonsModel(QVector<DecorationButtonType>(), this)) | 66 | KDecoration2::DecorationButtonType::Maximize, | ||
81 | , m_rightButtons(new Preview::ButtonsModel(QVector<DecorationButtonType>(), this)) | 67 | KDecoration2::DecorationButtonType::Close | ||
82 | , m_availableButtons(new Preview::ButtonsModel(this)) | | |||
83 | { | | |||
84 | m_proxyModel->setSourceModel(m_model); | | |||
85 | m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); | | |||
86 | m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); | | |||
87 | m_proxyModel->sort(0); | | |||
88 | connect(m_ui->filter, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterFixedString); | | |||
89 | | ||||
90 | m_quickView = new QQuickView(0); | | |||
91 | KDeclarative::KDeclarative kdeclarative; | | |||
92 | kdeclarative.setDeclarativeEngine(m_quickView->engine()); | | |||
93 | kdeclarative.setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); | | |||
94 | kdeclarative.setupContext(); | | |||
95 | kdeclarative.setupEngine(m_quickView->engine()); | | |||
96 | | ||||
97 | qmlRegisterType<QAbstractItemModel>(); | | |||
98 | QWidget *widget = QWidget::createWindowContainer(m_quickView, this); | | |||
99 | QVBoxLayout* layout = new QVBoxLayout(m_ui->view); | | |||
100 | layout->setContentsMargins(0,0,0,0); | | |||
101 | layout->addWidget(widget); | | |||
102 | | ||||
103 | m_quickView->rootContext()->setContextProperty(QStringLiteral("decorationsModel"), m_proxyModel); | | |||
104 | updateColors(); | | |||
105 | m_quickView->rootContext()->setContextProperty("_borderSizesIndex", 3); // 3 is normal | | |||
106 | m_quickView->rootContext()->setContextProperty("leftButtons", m_leftButtons); | | |||
107 | m_quickView->rootContext()->setContextProperty("rightButtons", m_rightButtons); | | |||
108 | m_quickView->rootContext()->setContextProperty("availableButtons", m_availableButtons); | | |||
109 | m_quickView->rootContext()->setContextProperty("initialThemeIndex", -1); | | |||
110 | | ||||
111 | m_quickView->rootContext()->setContextProperty("titleFont", QFontDatabase::systemFont(QFontDatabase::TitleFont)); | | |||
112 | m_quickView->setResizeMode(QQuickView::SizeRootObjectToView); | | |||
113 | m_quickView->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/kcm_kwindecoration/main.qml")))); | | |||
114 | if (m_quickView->status() == QQuickView::Ready) { | | |||
115 | auto listView = m_quickView->rootObject()->findChild<QQuickItem*>("listView"); | | |||
116 | if (listView) { | | |||
117 | connect(listView, SIGNAL(userChangedSelection()), this, SLOT(changed())); | | |||
118 | } | | |||
119 | } | | |||
120 | | ||||
121 | m_ui->tabWidget->tabBar()->disconnect(); | | |||
122 | auto setCurrentTab = [this](int index) { | | |||
123 | if (index == 0) | | |||
124 | m_ui->doubleClickMessage->hide(); | | |||
125 | m_ui->filter->setVisible(index == 0); | | |||
126 | m_ui->knsButton->setVisible(index == 0); | | |||
127 | if (auto themeList = m_quickView->rootObject()->findChild<QQuickItem*>("themeList")) { | | |||
128 | themeList->setVisible(index == 0); | | |||
129 | } | | |||
130 | m_ui->borderSizesLabel->setVisible(index == 0); | | |||
131 | m_ui->borderSizesCombo->setVisible(index == 0); | | |||
132 | | ||||
133 | m_ui->closeWindowsDoubleClick->setVisible(index == 1); | | |||
134 | if (auto buttonLayout = m_quickView->rootObject()->findChild<QQuickItem*>("buttonLayout")) { | | |||
135 | buttonLayout->setVisible(index == 1); | | |||
136 | } | | |||
137 | }; | 68 | }; | ||
138 | connect(m_ui->tabWidget->tabBar(), &QTabBar::currentChanged, this, setCurrentTab); | | |||
139 | setCurrentTab(0); | | |||
140 | 69 | | |||
141 | m_ui->doubleClickMessage->setVisible(false); | 70 | #if HAVE_BREEZE_DECO | ||
142 | m_ui->doubleClickMessage->setText(i18n("Close by double clicking:\n To open the menu, keep the button pressed until it appears.")); | 71 | static const QString s_defaultPlugin { QStringLiteral(BREEZE_KDECORATION_PLUGIN_ID) }; | ||
143 | m_ui->doubleClickMessage->setCloseButtonVisible(true); | 72 | static const QString s_defaultTheme { QStringLiteral("Breeze") }; | ||
144 | m_ui->borderSizesCombo->setItemData(0, QVariant::fromValue(BorderSize::None)); | 73 | #else | ||
145 | m_ui->borderSizesCombo->setItemData(1, QVariant::fromValue(BorderSize::NoSides)); | 74 | static const QString s_defaultPlugin { QStringLiteral("org.kde.kwin.aurorae") }; | ||
146 | m_ui->borderSizesCombo->setItemData(2, QVariant::fromValue(BorderSize::Tiny)); | 75 | static const QString s_defaultTheme { QStringLiteral("kwin4_decoration_qml_plastik") }; | ||
147 | m_ui->borderSizesCombo->setItemData(3, QVariant::fromValue(BorderSize::Normal)); | 76 | #endif | ||
148 | m_ui->borderSizesCombo->setItemData(4, QVariant::fromValue(BorderSize::Large)); | | |||
149 | m_ui->borderSizesCombo->setItemData(5, QVariant::fromValue(BorderSize::VeryLarge)); | | |||
150 | m_ui->borderSizesCombo->setItemData(6, QVariant::fromValue(BorderSize::Huge)); | | |||
151 | m_ui->borderSizesCombo->setItemData(7, QVariant::fromValue(BorderSize::VeryHuge)); | | |||
152 | m_ui->borderSizesCombo->setItemData(8, QVariant::fromValue(BorderSize::Oversized)); | | |||
153 | m_ui->knsButton->setIcon(QIcon::fromTheme(s_ghnsIcon)); | | |||
154 | | ||||
155 | auto changedSlot = static_cast<void (ConfigurationModule::*)()>(&ConfigurationModule::changed); | | |||
156 | connect(m_ui->closeWindowsDoubleClick, &QCheckBox::stateChanged, this, changedSlot); | | |||
157 | connect(m_ui->closeWindowsDoubleClick, &QCheckBox::toggled, this, | | |||
158 | [this] (bool toggled) { | | |||
159 | if (s_loading) { | | |||
160 | return; | | |||
161 | } | | |||
162 | if (toggled) | | |||
163 | m_ui->doubleClickMessage->animatedShow(); | | |||
164 | else | | |||
165 | m_ui->doubleClickMessage->animatedHide(); | | |||
166 | } | | |||
167 | ); | | |||
168 | connect(m_ui->borderSizesCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | | |||
169 | this, [this] (int index) { | | |||
170 | auto listView = m_quickView->rootObject()->findChild<QQuickItem*>("listView"); | | |||
171 | if (listView) { | | |||
172 | listView->setProperty("borderSizesIndex", index); | | |||
173 | } | | |||
174 | changed(); | | |||
175 | } | | |||
176 | ); | | |||
177 | connect(m_model, &QAbstractItemModel::modelReset, this, | | |||
178 | [this] { | | |||
179 | const auto &kns = m_model->knsProviders(); | | |||
180 | m_ui->knsButton->setEnabled(!kns.isEmpty()); | | |||
181 | if (kns.isEmpty()) { | | |||
182 | return; | | |||
183 | } | | |||
184 | if (kns.count() > 1) { | | |||
185 | QMenu *menu = new QMenu(m_ui->knsButton); | | |||
186 | for (auto it = kns.begin(); it != kns.end(); ++it) { | | |||
187 | QAction *action = menu->addAction(QIcon::fromTheme(s_ghnsIcon), it.value()); | | |||
188 | action->setData(it.key()); | | |||
189 | connect(action, &QAction::triggered, this, [this, action] { showKNS(action->data().toString());}); | | |||
190 | } | | |||
191 | m_ui->knsButton->setMenu(menu); | | |||
192 | } | | |||
193 | } | | |||
194 | ); | | |||
195 | connect(m_ui->knsButton, &QPushButton::clicked, this, | | |||
196 | [this] { | | |||
197 | const auto &kns = m_model->knsProviders(); | | |||
198 | if (kns.isEmpty()) { | | |||
199 | return; | | |||
200 | } | | |||
201 | showKNS(kns.firstKey()); | | |||
202 | } | 77 | } | ||
203 | ); | | |||
204 | connect(m_leftButtons, &QAbstractItemModel::rowsInserted, this, changedSlot); | | |||
205 | connect(m_leftButtons, &QAbstractItemModel::rowsMoved, this, changedSlot); | | |||
206 | connect(m_leftButtons, &QAbstractItemModel::rowsRemoved, this, changedSlot); | | |||
207 | connect(m_rightButtons, &QAbstractItemModel::rowsInserted, this, changedSlot); | | |||
208 | connect(m_rightButtons, &QAbstractItemModel::rowsMoved, this, changedSlot); | | |||
209 | connect(m_rightButtons, &QAbstractItemModel::rowsRemoved, this, changedSlot); | | |||
210 | 78 | | |||
211 | QVBoxLayout *l = new QVBoxLayout(this); | 79 | KCMKWinDecoration::KCMKWinDecoration(QObject *parent, const QVariantList &arguments) | ||
212 | l->addWidget(m_ui); | 80 | : KQuickAddons::ConfigModule(parent, arguments) | ||
213 | QMetaObject::invokeMethod(m_model, "init", Qt::QueuedConnection); | 81 | , m_themesModel(new KDecoration2::Configuration::DecorationsModel(this)) | ||
82 | , m_proxyThemesModel(new QSortFilterProxyModel(this)) | ||||
83 | , m_leftButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this)) | ||||
84 | , m_rightButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this)) | ||||
85 | , m_availableButtonsModel(new KDecoration2::Preview::ButtonsModel(this)) | ||||
86 | , m_savedSettings{ s_defaultBorderSize, -2 /* for setTheme() */, false, s_defaultDecoButtonsOnLeft, s_defaultDecoButtonsOnRight } | ||||
87 | , m_currentSettings(m_savedSettings) | ||||
88 | { | ||||
89 | KAboutData* about = new KAboutData(QStringLiteral("kcm_kwindecoration"), | ||||
90 | i18n("Configure Window Decorations"), | ||||
ngraham: The string from the`Comment` in the desktop file needs to be duplicated here. | |||||
91 | QStringLiteral("1.0"), | ||||
92 | QString(), | ||||
93 | KAboutLicense::GPL); | ||||
zzag: Please align it. | |||||
94 | about->addAuthor(i18n("Valerio Pilo"), | ||||
95 | i18n("Author"), | ||||
96 | QStringLiteral("vpilo@coldshock.net")); | ||||
97 | setAboutData(about); | ||||
214 | 98 | | |||
215 | m_ui->installEventFilter(this); | 99 | qmlRegisterType<QAbstractListModel>(); | ||
216 | } | 100 | qmlRegisterType<QSortFilterProxyModel>(); | ||
217 | 101 | | |||
218 | ConfigurationModule::~ConfigurationModule() = default; | 102 | m_proxyThemesModel->setSourceModel(m_themesModel); | ||
103 | m_proxyThemesModel->setFilterCaseSensitivity(Qt::CaseInsensitive); | ||||
104 | m_proxyThemesModel->setSortCaseSensitivity(Qt::CaseInsensitive); | ||||
105 | m_proxyThemesModel->sort(0); | ||||
219 | 106 | | |||
220 | void ConfigurationModule::showEvent(QShowEvent *ev) | 107 | connect(m_leftButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave); | ||
221 | { | 108 | connect(m_leftButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave); | ||
222 | KCModule::showEvent(ev); | 109 | connect(m_leftButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave); | ||
223 | } | 110 | connect(m_leftButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave); | ||
111 | connect(m_rightButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave); | ||||
112 | connect(m_rightButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave); | ||||
113 | connect(m_rightButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave); | ||||
114 | connect(m_rightButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave); | ||||
224 | 115 | | |||
225 | static const QMap<QString, KDecoration2::BorderSize> s_sizes = QMap<QString, KDecoration2::BorderSize>({ | 116 | // Update the themes when the color scheme or a theme's settings change | ||
226 | {QStringLiteral("None"), BorderSize::None}, | 117 | QDBusConnection::sessionBus() | ||
227 | {QStringLiteral("NoSides"), BorderSize::NoSides}, | 118 | .connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"), | ||
228 | {QStringLiteral("Tiny"), BorderSize::Tiny}, | 119 | this, | ||
229 | {s_borderSizeNormal, BorderSize::Normal}, | 120 | SLOT(reloadKWinSettings())); | ||
230 | {QStringLiteral("Large"), BorderSize::Large}, | | |||
231 | {QStringLiteral("VeryLarge"), BorderSize::VeryLarge}, | | |||
232 | {QStringLiteral("Huge"), BorderSize::Huge}, | | |||
233 | {QStringLiteral("VeryHuge"), BorderSize::VeryHuge}, | | |||
234 | {QStringLiteral("Oversized"), BorderSize::Oversized} | | |||
235 | }); | | |||
236 | 121 | | |||
237 | static BorderSize stringToSize(const QString &name) | 122 | QMetaObject::invokeMethod(m_themesModel, "init", Qt::QueuedConnection); | ||
zzag: Use `auto`. | |||||
238 | { | | |||
239 | auto it = s_sizes.constFind(name); | | |||
240 | if (it == s_sizes.constEnd()) { | | |||
241 | // non sense values are interpreted just like normal | | |||
242 | return BorderSize::Normal; | | |||
243 | } | | |||
244 | return it.value(); | | |||
245 | } | 123 | } | ||
246 | 124 | | |||
247 | static QString sizeToString(BorderSize size) | 125 | void KCMKWinDecoration::reloadKWinSettings() | ||
248 | { | 126 | { | ||
249 | return s_sizes.key(size, s_borderSizeNormal); | 127 | QMetaObject::invokeMethod(m_themesModel, "init", Qt::QueuedConnection); | ||
250 | } | 128 | } | ||
251 | 129 | | |||
252 | static QHash<KDecoration2::DecorationButtonType, QChar> s_buttonNames; | 130 | void KCMKWinDecoration::getNewStuff(QQuickItem *context) | ||
253 | static void initButtons() | | |||
254 | { | 131 | { | ||
255 | if (!s_buttonNames.isEmpty()) { | 132 | if (!m_newStuffDialog) { | ||
256 | return; | 133 | m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("window-decorations.knsrc")); | ||
134 | m_newStuffDialog->setWindowTitle(i18n("Download New Window Decorations")); | ||||
135 | m_newStuffDialog->setWindowModality(Qt::WindowModal); | ||||
136 | connect(m_newStuffDialog, &KNS3::DownloadDialog::accepted, this, &KCMKWinDecoration::load); | ||||
257 | } | 137 | } | ||
258 | s_buttonNames[KDecoration2::DecorationButtonType::Menu] = QChar('M'); | 138 | | ||
259 | s_buttonNames[KDecoration2::DecorationButtonType::ApplicationMenu] = QChar('N'); | 139 | if (context && context->window()) { | ||
davidedmundson: Can I check this FIXME is just a new idea and not a regression? | |||||
It is a regression, the older KCM collected from plugins one "KNewStuff" field, and added it to the categories. This seems not to be possible anymore because
I'll just take it away for now. I'd just like a confirmation that the categories I chose for the .knsrc file are correct/acceptable. vpilo: It is a regression, the older KCM collected from plugins one "KNewStuff" field, and added it to… | |||||
260 | s_buttonNames[KDecoration2::DecorationButtonType::OnAllDesktops] = QChar('S'); | 140 | m_newStuffDialog->winId(); // so it creates the windowHandle() | ||
261 | s_buttonNames[KDecoration2::DecorationButtonType::ContextHelp] = QChar('H'); | 141 | m_newStuffDialog->windowHandle()->setTransientParent(context->window()); | ||
262 | s_buttonNames[KDecoration2::DecorationButtonType::Minimize] = QChar('I'); | | |||
263 | s_buttonNames[KDecoration2::DecorationButtonType::Maximize] = QChar('A'); | | |||
264 | s_buttonNames[KDecoration2::DecorationButtonType::Close] = QChar('X'); | | |||
265 | s_buttonNames[KDecoration2::DecorationButtonType::KeepAbove] = QChar('F'); | | |||
266 | s_buttonNames[KDecoration2::DecorationButtonType::KeepBelow] = QChar('B'); | | |||
267 | s_buttonNames[KDecoration2::DecorationButtonType::Shade] = QChar('L'); | | |||
268 | } | | |||
269 | | ||||
270 | static QString buttonsToString(const QVector<KDecoration2::DecorationButtonType> &buttons) | | |||
271 | { | | |||
272 | auto buttonToString = [](KDecoration2::DecorationButtonType button) -> QChar { | | |||
273 | const auto it = s_buttonNames.constFind(button); | | |||
274 | if (it != s_buttonNames.constEnd()) { | | |||
275 | return it.value(); | | |||
276 | } | | |||
277 | return QChar(); | | |||
278 | }; | | |||
279 | QString ret; | | |||
280 | for (auto button : buttons) { | | |||
281 | ret.append(buttonToString(button)); | | |||
282 | } | 142 | } | ||
283 | return ret; | 143 | | ||
144 | m_newStuffDialog->show(); | ||||
284 | } | 145 | } | ||
285 | 146 | | |||
286 | static | 147 | void KCMKWinDecoration::load() | ||
287 | QVector< KDecoration2::DecorationButtonType > readDecorationButtons(const KConfigGroup &config, | | |||
288 | const char *key, | | |||
289 | const QVector< KDecoration2::DecorationButtonType > &defaultValue) | | |||
290 | { | 148 | { | ||
291 | initButtons(); | 149 | const KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup); | ||
292 | auto buttonsFromString = [](const QString &buttons) -> QVector<KDecoration2::DecorationButtonType> { | 150 | | ||
293 | QVector<KDecoration2::DecorationButtonType> ret; | 151 | const QString plugin = config.readEntry(s_configPlugin, s_defaultPlugin); | ||
294 | for (auto it = buttons.begin(); it != buttons.end(); ++it) { | 152 | const QString theme = config.readEntry(s_configTheme, s_defaultTheme); | ||
295 | for (auto it2 = s_buttonNames.constBegin(); it2 != s_buttonNames.constEnd(); ++it2) { | 153 | int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(plugin, theme)).row(); | ||
296 | if (it2.value() == (*it)) { | 154 | if (themeIndex < 0) { | ||
297 | ret << it2.key(); | 155 | qWarning() << "Plugin" << plugin << "and theme" << theme << "not found"; | ||
298 | } | 156 | } else { | ||
299 | } | 157 | qDebug() << "Current theme: plugin" << plugin << "and theme" << theme; | ||
300 | } | | |||
301 | return ret; | | |||
302 | }; | | |||
303 | return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue))); | | |||
304 | } | 158 | } | ||
159 | setTheme(themeIndex); | ||||
305 | 160 | | |||
306 | void ConfigurationModule::load() | 161 | setCloseOnDoubleClickOnMenu(config.readEntry(s_configCloseOnDoubleClickOnMenu, s_defaultCloseOnDoubleClickOnMenu)); | ||
307 | { | | |||
308 | s_loading = true; | | |||
309 | const KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName); | | |||
310 | const QString plugin = config.readEntry("library", s_defaultPlugin); | | |||
311 | const QString theme = config.readEntry("theme", s_defaultTheme); | | |||
312 | m_ui->closeWindowsDoubleClick->setChecked(config.readEntry("CloseOnDoubleClickOnMenu", false)); | | |||
313 | const QVariant border = QVariant::fromValue(stringToSize(config.readEntry("BorderSize", s_borderSizeNormal))); | | |||
314 | m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(border)); | | |||
315 | 162 | | |||
316 | int themeIndex = m_proxyModel->mapFromSource(m_model->findDecoration(plugin, theme)).row(); | 163 | const QString defaultSizeName = Utils::borderSizeToString(s_defaultBorderSize); | ||
317 | m_quickView->rootContext()->setContextProperty("initialThemeIndex", themeIndex); | 164 | setBorderSize(Utils::stringToBorderSize(config.readEntry(s_configBorderSize, defaultSizeName))); | ||
318 | 165 | | |||
319 | // buttons | 166 | m_leftButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnLeft, s_defaultDecoButtonsOnLeft)); | ||
320 | const auto &left = readDecorationButtons(config, "ButtonsOnLeft", QVector<KDecoration2::DecorationButtonType >{ | 167 | m_rightButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnRight, s_defaultDecoButtonsOnRight)); | ||
321 | KDecoration2::DecorationButtonType::Menu, | 168 | m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons(); | ||
322 | KDecoration2::DecorationButtonType::OnAllDesktops | 169 | m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons(); | ||
323 | }); | 170 | | ||
324 | while (m_leftButtons->rowCount() > 0) { | 171 | m_savedSettings = m_currentSettings; | ||
325 | m_leftButtons->remove(0); | | |||
326 | } | | |||
327 | for (auto it = left.begin(); it != left.end(); ++it) { | | |||
328 | m_leftButtons->add(*it); | | |||
329 | } | | |||
330 | const auto &right = readDecorationButtons(config, "ButtonsOnRight", QVector<KDecoration2::DecorationButtonType >{ | | |||
331 | KDecoration2::DecorationButtonType::ContextHelp, | | |||
332 | KDecoration2::DecorationButtonType::Minimize, | | |||
333 | KDecoration2::DecorationButtonType::Maximize, | | |||
334 | KDecoration2::DecorationButtonType::Close | | |||
335 | }); | | |||
336 | while (m_rightButtons->rowCount() > 0) { | | |||
337 | m_rightButtons->remove(0); | | |||
338 | } | | |||
339 | for (auto it = right.begin(); it != right.end(); ++it) { | | |||
340 | m_rightButtons->add(*it); | | |||
341 | } | | |||
342 | 172 | | |||
343 | KCModule::load(); | 173 | updateNeedsSave(); | ||
344 | s_loading = false; | | |||
345 | } | 174 | } | ||
346 | 175 | | |||
347 | void ConfigurationModule::save() | 176 | void KCMKWinDecoration::save() | ||
348 | { | 177 | { | ||
349 | KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName); | 178 | KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup); | ||
350 | config.writeEntry("CloseOnDoubleClickOnMenu", m_ui->closeWindowsDoubleClick->isChecked()); | 179 | | ||
351 | config.writeEntry("BorderSize", sizeToString(m_ui->borderSizesCombo->currentData().value<BorderSize>())); | 180 | if (m_currentSettings.themeIndex >= 0) { | ||
352 | if (auto listView = m_quickView->rootObject()->findChild<QQuickItem*>("listView")) { | 181 | const QModelIndex index = m_proxyThemesModel->index(m_currentSettings.themeIndex, 0); | ||
353 | const int currentIndex = listView->property("currentIndex").toInt(); | | |||
354 | if (currentIndex != -1) { | | |||
355 | const QModelIndex index = m_proxyModel->index(currentIndex, 0); | | |||
356 | if (index.isValid()) { | 182 | if (index.isValid()) { | ||
357 | config.writeEntry("library", index.data(Qt::UserRole + 4).toString()); | 183 | const QString plugin = index.data(KDecoration2::Configuration::DecorationsModel::PluginNameRole).toString(); | ||
358 | const QString theme = index.data(Qt::UserRole +5).toString(); | 184 | const QString theme = index.data(KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString(); | ||
359 | config.writeEntry("theme", theme); | 185 | config.writeEntry(s_configPlugin, plugin); | ||
186 | config.writeEntry(s_configTheme, theme); | ||||
187 | qDebug() << "Saved theme: plugin" << plugin << "and theme" << theme; | ||||
188 | } else { | ||||
189 | qWarning() << "Cannot match theme index" << m_currentSettings.themeIndex << "in model"; | ||||
360 | } | 190 | } | ||
361 | } | 191 | } | ||
362 | } | 192 | | ||
363 | config.writeEntry("ButtonsOnLeft", buttonsToString(m_leftButtons->buttons())); | 193 | config.writeEntry(s_configCloseOnDoubleClickOnMenu, m_currentSettings.closeOnDoubleClickOnMenu); | ||
364 | config.writeEntry("ButtonsOnRight", buttonsToString(m_rightButtons->buttons())); | 194 | config.writeEntry(s_configBorderSize, Utils::borderSizeToString(m_currentSettings.borderSize)); | ||
195 | config.writeEntry(s_configDecoButtonsOnLeft, Utils::buttonsToString(m_currentSettings.buttonsOnLeft)); | ||||
196 | config.writeEntry(s_configDecoButtonsOnRight, Utils::buttonsToString(m_currentSettings.buttonsOnRight)); | ||||
365 | config.sync(); | 197 | config.sync(); | ||
366 | KCModule::save(); | 198 | | ||
367 | // Send signal to all kwin instances | 199 | m_savedSettings = m_currentSettings; | ||
200 | | ||||
201 | // Send a signal to all kwin instances | ||||
368 | QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), | 202 | QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), | ||
369 | QStringLiteral("org.kde.KWin"), | 203 | QStringLiteral("org.kde.KWin"), | ||
370 | QStringLiteral("reloadConfig")); | 204 | QStringLiteral("reloadConfig")); | ||
371 | QDBusConnection::sessionBus().send(message); | 205 | QDBusConnection::sessionBus().send(message); | ||
206 | | ||||
207 | updateNeedsSave(); | ||||
372 | } | 208 | } | ||
373 | 209 | | |||
374 | void ConfigurationModule::defaults() | 210 | void KCMKWinDecoration::defaults() | ||
375 | { | 211 | { | ||
376 | if (auto listView = m_quickView->rootObject()->findChild<QQuickItem*>("listView")) { | 212 | int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(s_defaultPlugin, s_defaultTheme)).row(); | ||
377 | const QModelIndex index = m_proxyModel->mapFromSource(m_model->findDecoration(s_defaultPlugin)); | 213 | if (themeIndex < 0) { | ||
378 | listView->setProperty("currentIndex", index.isValid() ? index.row() : -1); | 214 | qWarning() << "Default plugin" << s_defaultPlugin << "and theme" << s_defaultTheme << "not found"; | ||
There's a typo in the QML, it is KCM.ConfigModule.Default (without an "s"). However, you seem to be doing it from both QML and C++ (setButtons()), one is sufficient. (I have seen this mistake in other QML KCMs, I assume you just copied that over) broulik: There's a typo in the QML, it is `KCM.ConfigModule.Default` (without an "s").
However, you… | |||||
379 | } | | |||
380 | m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(QVariant::fromValue(stringToSize(s_borderSizeNormal)))); | | |||
381 | m_ui->closeWindowsDoubleClick->setChecked(false); | | |||
382 | KCModule::defaults(); | | |||
383 | } | | |||
384 | | ||||
385 | void ConfigurationModule::showKNS(const QString &config) | | |||
386 | { | | |||
387 | QPointer<KNS3::DownloadDialog> downloadDialog = new KNS3::DownloadDialog(config, this); | | |||
388 | if (downloadDialog->exec() == QDialog::Accepted && !downloadDialog->changedEntries().isEmpty()) { | | |||
389 | auto listView = m_quickView->rootObject()->findChild<QQuickItem*>("listView"); | | |||
390 | QString selectedPluginName; | | |||
391 | QString selectedThemeName; | | |||
392 | if (listView) { | | |||
393 | const QModelIndex index = m_proxyModel->index(listView->property("currentIndex").toInt(), 0); | | |||
394 | if (index.isValid()) { | | |||
395 | selectedPluginName = index.data(Qt::UserRole + 4).toString(); | | |||
396 | selectedThemeName = index.data(Qt::UserRole + 5).toString(); | | |||
397 | } | 215 | } | ||
216 | setTheme(themeIndex); | ||||
217 | setBorderSize(s_defaultBorderSize); | ||||
218 | setCloseOnDoubleClickOnMenu(s_defaultCloseOnDoubleClickOnMenu); | ||||
219 | | ||||
220 | m_leftButtonsModel->replace(s_defaultDecoButtonsOnLeft); | ||||
221 | m_rightButtonsModel->replace(s_defaultDecoButtonsOnRight); | ||||
222 | | ||||
223 | updateNeedsSave(); | ||||
398 | } | 224 | } | ||
399 | m_model->init(); | 225 | | ||
400 | if (!selectedPluginName.isEmpty()) { | 226 | void KCMKWinDecoration::updateNeedsSave() | ||
401 | const QModelIndex index = m_model->findDecoration(selectedPluginName, selectedThemeName); | 227 | { | ||
402 | const QModelIndex proxyIndex = m_proxyModel->mapFromSource(index); | 228 | m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons(); | ||
403 | if (listView) { | 229 | m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons(); | ||
404 | listView->setProperty("currentIndex", proxyIndex.isValid() ? proxyIndex.row() : -1); | 230 | | ||
231 | setNeedsSave(m_savedSettings.closeOnDoubleClickOnMenu != m_currentSettings.closeOnDoubleClickOnMenu | ||||
232 | || m_savedSettings.borderSize != m_currentSettings.borderSize | ||||
233 | || m_savedSettings.themeIndex != m_currentSettings.themeIndex | ||||
234 | || m_savedSettings.buttonsOnLeft != m_currentSettings.buttonsOnLeft | ||||
235 | || m_savedSettings.buttonsOnRight != m_currentSettings.buttonsOnRight); | ||||
405 | } | 236 | } | ||
237 | | ||||
238 | QSortFilterProxyModel *KCMKWinDecoration::themesModel() const | ||||
239 | { | ||||
240 | return m_proxyThemesModel; | ||||
406 | } | 241 | } | ||
242 | | ||||
243 | QAbstractListModel *KCMKWinDecoration::leftButtonsModel() | ||||
244 | { | ||||
245 | return m_leftButtonsModel; | ||||
407 | } | 246 | } | ||
408 | delete downloadDialog; | 247 | | ||
248 | QAbstractListModel *KCMKWinDecoration::rightButtonsModel() | ||||
249 | { | ||||
250 | return m_rightButtonsModel; | ||||
251 | } | ||||
252 | | ||||
253 | QAbstractListModel *KCMKWinDecoration::availableButtonsModel() const | ||||
254 | { | ||||
255 | return m_availableButtonsModel; | ||||
256 | } | ||||
257 | | ||||
258 | QStringList KCMKWinDecoration::borderSizesModel() const | ||||
259 | { | ||||
260 | return Utils::getBorderSizeNames().values(); | ||||
261 | } | ||||
262 | | ||||
263 | int KCMKWinDecoration::borderSize() const | ||||
264 | { | ||||
265 | return Utils::getBorderSizeNames().keys().indexOf(m_currentSettings.borderSize); | ||||
266 | } | ||||
267 | | ||||
268 | int KCMKWinDecoration::theme() const | ||||
269 | { | ||||
270 | return m_currentSettings.themeIndex; | ||||
271 | } | ||||
272 | | ||||
273 | bool KCMKWinDecoration::closeOnDoubleClickOnMenu() const | ||||
274 | { | ||||
275 | return m_currentSettings.closeOnDoubleClickOnMenu; | ||||
409 | } | 276 | } | ||
410 | 277 | | |||
411 | bool ConfigurationModule::eventFilter(QObject *watched, QEvent *e) | 278 | void KCMKWinDecoration::setBorderSize(int index) | ||
412 | { | 279 | { | ||
413 | if (watched != m_ui) { | 280 | setBorderSize(Utils::getBorderSizeNames().keys().at(index)); | ||
414 | return false; | | |||
415 | } | 281 | } | ||
416 | if (e->type() == QEvent::PaletteChange) { | 282 | | ||
417 | updateColors(); | 283 | void KCMKWinDecoration::setBorderSize(KDecoration2::BorderSize size) | ||
284 | { | ||||
285 | if (m_currentSettings.borderSize == size) { | ||||
286 | return; | ||||
418 | } | 287 | } | ||
419 | return false; | 288 | m_currentSettings.borderSize = size; | ||
289 | emit borderSizeChanged(); | ||||
290 | updateNeedsSave(); | ||||
420 | } | 291 | } | ||
421 | 292 | | |||
422 | void ConfigurationModule::updateColors() | 293 | void KCMKWinDecoration::setTheme(int index) | ||
423 | { | 294 | { | ||
424 | m_quickView->rootContext()->setContextProperty("backgroundColor", m_ui->palette().color(QPalette::Active, QPalette::Window)); | 295 | // The initial themeIndex is set to -2 to always initially apply a theme, any theme | ||
425 | m_quickView->rootContext()->setContextProperty("highlightColor", m_ui->palette().color(QPalette::Active, QPalette::Shadow)); | 296 | if (m_currentSettings.themeIndex == index) { | ||
426 | m_quickView->rootContext()->setContextProperty("baseColor", m_ui->palette().color(QPalette::Active, QPalette::Base)); | 297 | return; | ||
298 | } | ||||
299 | m_currentSettings.themeIndex = index; | ||||
300 | emit themeChanged(); | ||||
301 | updateNeedsSave(); | ||||
427 | } | 302 | } | ||
428 | 303 | | |||
304 | void KCMKWinDecoration::setCloseOnDoubleClickOnMenu(bool enable) | ||||
305 | { | ||||
306 | if (m_currentSettings.closeOnDoubleClickOnMenu == enable) { | ||||
307 | return; | ||||
429 | } | 308 | } | ||
309 | m_currentSettings.closeOnDoubleClickOnMenu = enable; | ||||
310 | emit closeOnDoubleClickOnMenuChanged(); | ||||
311 | updateNeedsSave(); | ||||
430 | } | 312 | } | ||
431 | 313 | | |||
432 | #include "kcm.moc" | 314 | #include "kcm.moc" |
See next comment