]> cloud.milkyroute.net Git - dolphin.git/blob - src/settings/services/servicessettingspage.cpp
Improve Touch support
[dolphin.git] / src / settings / services / servicessettingspage.cpp
1 /*
2 * SPDX-FileCopyrightText: 2009-2010 Peter Penz <peter.penz19@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "servicessettingspage.h"
8
9 #include "dolphin_generalsettings.h"
10 #include "dolphin_versioncontrolsettings.h"
11 #include "settings/serviceitemdelegate.h"
12 #include "settings/servicemodel.h"
13
14 #include <KDesktopFile>
15 #include <KLocalizedString>
16 #include <KMessageBox>
17 #include <KNS3/Button>
18 #include <KPluginMetaData>
19 #include <KService>
20 #include <KServiceTypeTrader>
21 #include <KDesktopFileActions>
22
23 #include <QGridLayout>
24 #include <QLabel>
25 #include <QListWidget>
26 #include <QScroller>
27 #include <QShowEvent>
28 #include <QSortFilterProxyModel>
29 #include <QLineEdit>
30
31 namespace
32 {
33 const bool ShowDeleteDefault = false;
34 const char VersionControlServicePrefix[] = "_version_control_";
35 const char DeleteService[] = "_delete";
36 const char CopyToMoveToService[] ="_copy_to_move_to";
37 }
38
39 ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
40 SettingsPageBase(parent),
41 m_initialized(false),
42 m_serviceModel(nullptr),
43 m_sortModel(nullptr),
44 m_listView(nullptr),
45 m_enabledVcsPlugins()
46 {
47 QVBoxLayout* topLayout = new QVBoxLayout(this);
48
49 QLabel* label = new QLabel(i18nc("@label:textbox",
50 "Select which services should "
51 "be shown in the context menu:"), this);
52 label->setWordWrap(true);
53 m_searchLineEdit = new QLineEdit(this);
54 m_searchLineEdit->setPlaceholderText(i18nc("@label:textbox", "Search..."));
55 connect(m_searchLineEdit, &QLineEdit::textChanged, this, [this](const QString &filter){
56 m_sortModel->setFilterFixedString(filter);
57 });
58
59 m_listView = new QListView(this);
60 QScroller::grabGesture(m_listView->viewport(), QScroller::TouchGesture);
61
62 auto *delegate = new ServiceItemDelegate(m_listView, m_listView);
63 m_serviceModel = new ServiceModel(this);
64 m_sortModel = new QSortFilterProxyModel(this);
65 m_sortModel->setSourceModel(m_serviceModel);
66 m_sortModel->setSortRole(Qt::DisplayRole);
67 m_sortModel->setSortLocaleAware(true);
68 m_sortModel->setFilterRole(Qt::DisplayRole);
69 m_sortModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
70 m_listView->setModel(m_sortModel);
71 m_listView->setItemDelegate(delegate);
72 m_listView->setVerticalScrollMode(QListView::ScrollPerPixel);
73 connect(m_listView, &QListView::clicked, this, &ServicesSettingsPage::changed);
74
75 #ifndef Q_OS_WIN
76 auto *downloadButton = new KNS3::Button(i18nc("@action:button", "Download New Services..."),
77 QStringLiteral("servicemenu.knsrc"),
78 this);
79 connect(downloadButton, &KNS3::Button::dialogFinished, this, [this](const KNS3::Entry::List &changedEntries) {
80 if (!changedEntries.isEmpty()) {
81 m_serviceModel->clear();
82 loadServices();
83 }
84 });
85
86 #endif
87
88 topLayout->addWidget(label);
89 topLayout->addWidget(m_searchLineEdit);
90 topLayout->addWidget(m_listView);
91 #ifndef Q_OS_WIN
92 topLayout->addWidget(downloadButton);
93 #endif
94
95 m_enabledVcsPlugins = VersionControlSettings::enabledPlugins();
96 std::sort(m_enabledVcsPlugins.begin(), m_enabledVcsPlugins.end());
97 }
98
99 ServicesSettingsPage::~ServicesSettingsPage() = default;
100
101 void ServicesSettingsPage::applySettings()
102 {
103 if (!m_initialized) {
104 return;
105 }
106
107 KConfig config(QStringLiteral("kservicemenurc"), KConfig::NoGlobals);
108 KConfigGroup showGroup = config.group("Show");
109
110 QStringList enabledPlugins;
111
112 const QAbstractItemModel *model = m_listView->model();
113 for (int i = 0; i < model->rowCount(); ++i) {
114 const QModelIndex index = model->index(i, 0);
115 const QString service = model->data(index, ServiceModel::DesktopEntryNameRole).toString();
116 const bool checked = model->data(index, Qt::CheckStateRole).toBool();
117
118 if (service.startsWith(VersionControlServicePrefix)) {
119 if (checked) {
120 enabledPlugins.append(model->data(index, Qt::DisplayRole).toString());
121 }
122 } else if (service == QLatin1String(DeleteService)) {
123 KSharedConfig::Ptr globalConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals);
124 KConfigGroup configGroup(globalConfig, "KDE");
125 configGroup.writeEntry("ShowDeleteCommand", checked);
126 configGroup.sync();
127 } else if (service == QLatin1String(CopyToMoveToService)) {
128 GeneralSettings::setShowCopyMoveMenu(checked);
129 GeneralSettings::self()->save();
130 } else {
131 showGroup.writeEntry(service, checked);
132 }
133 }
134
135 showGroup.sync();
136
137 if (m_enabledVcsPlugins != enabledPlugins) {
138 VersionControlSettings::setEnabledPlugins(enabledPlugins);
139 VersionControlSettings::self()->save();
140
141 KMessageBox::information(window(),
142 i18nc("@info", "Dolphin must be restarted to apply the "
143 "updated version control systems settings."),
144 QString(), // default title
145 QStringLiteral("ShowVcsRestartInformation"));
146 }
147 }
148
149 void ServicesSettingsPage::restoreDefaults()
150 {
151 QAbstractItemModel* model = m_listView->model();
152 for (int i = 0; i < model->rowCount(); ++i) {
153 const QModelIndex index = model->index(i, 0);
154 const QString service = model->data(index, ServiceModel::DesktopEntryNameRole).toString();
155
156 const bool checked = !service.startsWith(VersionControlServicePrefix)
157 && service != QLatin1String(DeleteService)
158 && service != QLatin1String(CopyToMoveToService);
159 model->setData(index, checked, Qt::CheckStateRole);
160 }
161 }
162
163 void ServicesSettingsPage::showEvent(QShowEvent* event)
164 {
165 if (!event->spontaneous() && !m_initialized) {
166 loadServices();
167
168 loadVersionControlSystems();
169
170 // Add "Show 'Delete' command" as service
171 KSharedConfig::Ptr globalConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::IncludeGlobals);
172 KConfigGroup configGroup(globalConfig, "KDE");
173 addRow(QStringLiteral("edit-delete"),
174 i18nc("@option:check", "Delete"),
175 DeleteService,
176 configGroup.readEntry("ShowDeleteCommand", ShowDeleteDefault));
177
178 // Add "Show 'Copy To' and 'Move To' commands" as service
179 addRow(QStringLiteral("edit-copy"),
180 i18nc("@option:check", "'Copy To' and 'Move To' commands"),
181 CopyToMoveToService,
182 GeneralSettings::showCopyMoveMenu());
183
184 m_sortModel->sort(Qt::DisplayRole);
185
186 m_initialized = true;
187 }
188 SettingsPageBase::showEvent(event);
189 }
190
191 void ServicesSettingsPage::loadServices()
192 {
193 const KConfig config(QStringLiteral("kservicemenurc"), KConfig::NoGlobals);
194 const KConfigGroup showGroup = config.group("Show");
195
196 // Load generic services
197 const KService::List entries = KServiceTypeTrader::self()->query(QStringLiteral("KonqPopupMenu/Plugin"));
198 for (const KService::Ptr &service : entries) {
199 const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kservices5/" % service->entryPath());
200 const QList<KServiceAction> serviceActions = KDesktopFileActions::userDefinedServices(file, true);
201
202 const KDesktopFile desktopFile(file);
203 const QString subMenuName = desktopFile.desktopGroup().readEntry("X-KDE-Submenu");
204
205 for (const KServiceAction &action : serviceActions) {
206 const QString serviceName = action.name();
207 const bool addService = !action.noDisplay() && !action.isSeparator() && !isInServicesList(serviceName);
208
209 if (addService) {
210 const QString itemName = subMenuName.isEmpty()
211 ? action.text()
212 : i18nc("@item:inmenu", "%1: %2", subMenuName, action.text());
213 const bool checked = showGroup.readEntry(serviceName, true);
214 addRow(action.icon(), itemName, serviceName, checked);
215 }
216 }
217 }
218
219 // Load service plugins that implement the KFileItemActionPlugin interface
220 const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("KFileItemAction/Plugin"));
221 for (const KService::Ptr &service : pluginServices) {
222 const QString desktopEntryName = service->desktopEntryName();
223 if (!isInServicesList(desktopEntryName)) {
224 const bool checked = showGroup.readEntry(desktopEntryName, true);
225 addRow(service->icon(), service->name(), desktopEntryName, checked);
226 }
227 }
228
229 // Load JSON-based plugins that implement the KFileItemActionPlugin interface
230 const auto jsonPlugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kfileitemaction"), [](const KPluginMetaData& metaData) {
231 return metaData.serviceTypes().contains(QLatin1String("KFileItemAction/Plugin"));
232 });
233
234 for (const auto &jsonMetadata : jsonPlugins) {
235 const QString desktopEntryName = jsonMetadata.pluginId();
236 if (!isInServicesList(desktopEntryName)) {
237 const bool checked = showGroup.readEntry(desktopEntryName, true);
238 addRow(jsonMetadata.iconName(), jsonMetadata.name(), desktopEntryName, checked);
239 }
240 }
241
242 m_sortModel->sort(Qt::DisplayRole);
243 m_searchLineEdit->setFocus(Qt::OtherFocusReason);
244 }
245
246 void ServicesSettingsPage::loadVersionControlSystems()
247 {
248 const QStringList enabledPlugins = VersionControlSettings::enabledPlugins();
249
250 // Create a checkbox for each available version control plugin
251 const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("FileViewVersionControlPlugin"));
252 for (const auto &plugin : pluginServices) {
253 const QString pluginName = plugin->name();
254 addRow(QStringLiteral("code-class"),
255 pluginName,
256 VersionControlServicePrefix + pluginName,
257 enabledPlugins.contains(pluginName));
258 }
259
260 m_sortModel->sort(Qt::DisplayRole);
261 }
262
263 bool ServicesSettingsPage::isInServicesList(const QString &service) const
264 {
265 for (int i = 0; i < m_serviceModel->rowCount(); ++i) {
266 const QModelIndex index = m_serviceModel->index(i, 0);
267 if (m_serviceModel->data(index, ServiceModel::DesktopEntryNameRole).toString() == service) {
268 return true;
269 }
270 }
271 return false;
272 }
273
274 void ServicesSettingsPage::addRow(const QString &icon,
275 const QString &text,
276 const QString &value,
277 bool checked)
278 {
279 m_serviceModel->insertRow(0);
280
281 const QModelIndex index = m_serviceModel->index(0, 0);
282 m_serviceModel->setData(index, icon, Qt::DecorationRole);
283 m_serviceModel->setData(index, text, Qt::DisplayRole);
284 m_serviceModel->setData(index, value, ServiceModel::DesktopEntryNameRole);
285 m_serviceModel->setData(index, checked, Qt::CheckStateRole);
286 }
287