KXmlGui

kshortcutschemeseditor.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2008 Alexander Dymo <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 #include "kshortcutsdialog_p.h"
8 
9 #include <QDir>
10 #include <QLabel>
11 #include <QMenu>
12 #include <QFile>
13 #include <QPushButton>
14 #include <QTextStream>
15 #include <QDomDocument>
16 #include <QFileDialog>
17 #include <QStandardPaths>
18 #include <QInputDialog>
19 #include <QComboBox>
20 
21 #include <kconfiggroup.h>
22 #include <kmessagebox.h>
23 #include <ksharedconfig.h>
24 
25 #include "kshortcutsdialog.h"
26 #include "kshortcutschemeshelper_p.h"
27 #include "kactioncollection.h"
28 #include "kxmlguiclient.h"
29 #include <debug.h>
30 
31 KShortcutSchemesEditor::KShortcutSchemesEditor(KShortcutsDialog *parent)
32  : QGroupBox(i18nc("@title:group", "Shortcut Schemes"), parent), m_dialog(parent)
33 {
34  KConfigGroup group(KSharedConfig::openConfig(), "Shortcut Schemes");
35 
36  QStringList schemes;
37  schemes << QStringLiteral("Default");
38  // List files in the shortcuts subdir, each one is a scheme. See KShortcutSchemesHelper::{shortcutSchemeFileName,exportActionCollection}
40  qCDebug(DEBUG_KXMLGUI) << "shortcut scheme dirs:" << shortcutsDirs;
41  for (const QString &dir : shortcutsDirs) {
42  const auto files = QDir(dir).entryList(QDir::Files | QDir::NoDotAndDotDot);
43  for (const QString &file : files) {
44  qCDebug(DEBUG_KXMLGUI) << "shortcut scheme file:" << file;
45  schemes << file;
46  }
47  }
48 
49  const QString currentScheme = group.readEntry("Current Scheme", "Default");
50  qCDebug(DEBUG_KXMLGUI) << "Current Scheme" << currentScheme;
51 
52  QHBoxLayout *l = new QHBoxLayout(this);
53 
54  QLabel *schemesLabel = new QLabel(i18n("Current scheme:"), this);
55  l->addWidget(schemesLabel);
56 
57  m_schemesList = new QComboBox(this);
58  m_schemesList->setEditable(false);
59  m_schemesList->addItems(schemes);
60  m_schemesList->setSizeAdjustPolicy(QComboBox::AdjustToContents);
61  const int schemeIdx = m_schemesList->findText(currentScheme);
62  if (schemeIdx > -1) {
63  m_schemesList->setCurrentIndex(schemeIdx);
64  } else {
65  qCWarning(DEBUG_KXMLGUI) << "Current scheme" << currentScheme << "not found in" << shortcutsDirs;
66  }
67  schemesLabel->setBuddy(m_schemesList);
68  l->addWidget(m_schemesList);
69 
70  m_newScheme = new QPushButton(i18nc("@action:button", "New..."));
71  l->addWidget(m_newScheme);
72 
73  m_deleteScheme = new QPushButton(i18nc("@action:button", "Delete"));
74  l->addWidget(m_deleteScheme);
75 
76  QPushButton *moreActions = new QPushButton(i18nc("@action:button", "More Actions"));
77  l->addWidget(moreActions);
78 
79  QMenu *moreActionsMenu = new QMenu(this);
80  moreActionsMenu->addAction(i18nc("@action:inmenu", "Save shortcuts to scheme"),
81  this, &KShortcutSchemesEditor::saveAsDefaultsForScheme);
82  moreActionsMenu->addAction(i18nc("@action:inmenu", "Export Scheme..."),
83  this, &KShortcutSchemesEditor::exportShortcutsScheme);
84  moreActionsMenu->addAction(i18nc("@action:inmenu", "Import Scheme..."),
85  this, &KShortcutSchemesEditor::importShortcutsScheme);
86  moreActions->setMenu(moreActionsMenu);
87 
88  l->addStretch(1);
89 
90 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
91  connect(m_schemesList, QOverload<const QString &>::of(&QComboBox::activated),
92  this, &KShortcutSchemesEditor::shortcutsSchemeChanged);
93 #else
94  connect(m_schemesList, &QComboBox::textActivated,
95  this, &KShortcutSchemesEditor::shortcutsSchemeChanged);
96 #endif
97  connect(m_newScheme, &QPushButton::clicked, this, &KShortcutSchemesEditor::newScheme);
98  connect(m_deleteScheme, &QPushButton::clicked, this, &KShortcutSchemesEditor::deleteScheme);
99  updateDeleteButton();
100 }
101 
102 void KShortcutSchemesEditor::newScheme()
103 {
104  bool ok;
105  const QString newName = QInputDialog::getText(this, i18nc("@title:window", "Name for New Scheme"),
106  i18n("Name for new scheme:"), QLineEdit::Normal, i18n("New Scheme"), &ok);
107  if (!ok) {
108  return;
109  }
110 
111  if (m_schemesList->findText(newName) != -1) {
112  KMessageBox::sorry(this, i18n("A scheme with this name already exists."));
113  return;
114  }
115 
116  const QString newSchemeFileName = KShortcutSchemesHelper::writableApplicationShortcutSchemeFileName(newName);
117  QDir().mkpath(QFileInfo(newSchemeFileName).absolutePath());
118  QFile schemeFile(newSchemeFileName);
119  if (!schemeFile.open(QFile::WriteOnly | QFile::Truncate)) {
120  qCWarning(DEBUG_KXMLGUI) << "Couldn't write to" << newSchemeFileName;
121  return;
122  }
123 
124  QDomDocument doc;
125  QDomElement docElem = doc.createElement(QStringLiteral("gui"));
126  doc.appendChild(docElem);
127  QDomElement elem = doc.createElement(QStringLiteral("ActionProperties"));
128  docElem.appendChild(elem);
129 
130  QTextStream out(&schemeFile);
131  out << doc.toString(4);
132 
133  m_schemesList->addItem(newName);
134  m_schemesList->setCurrentIndex(m_schemesList->findText(newName));
135  updateDeleteButton();
136  emit shortcutsSchemeChanged(newName);
137 }
138 
139 void KShortcutSchemesEditor::deleteScheme()
140 {
142  i18n("Do you really want to delete the scheme %1?\n\
143 Note that this will not remove any system wide shortcut schemes.", currentScheme())) == KMessageBox::No) {
144  return;
145  }
146 
147  //delete the scheme for the app itself
148  QFile::remove(KShortcutSchemesHelper::writableApplicationShortcutSchemeFileName(currentScheme()));
149 
150  //delete all scheme files we can find for xmlguiclients in the user directories
151  const auto dialogCollections = m_dialog->actionCollections();
152  for (KActionCollection *collection : dialogCollections) {
153  const KXMLGUIClient *client = collection->parentGUIClient();
154  if (!client) {
155  continue;
156  }
157  QFile::remove(KShortcutSchemesHelper::writableShortcutSchemeFileName(client->componentName(), currentScheme()));
158  }
159 
160  m_schemesList->removeItem(m_schemesList->findText(currentScheme()));
161  updateDeleteButton();
162  emit shortcutsSchemeChanged(currentScheme());
163 }
164 
165 QString KShortcutSchemesEditor::currentScheme()
166 {
167  return m_schemesList->currentText();
168 }
169 
170 void KShortcutSchemesEditor::exportShortcutsScheme()
171 {
172  //ask user about dir
173  QString path = QFileDialog::getSaveFileName(this, i18nc("@title:window", "Export Shortcuts"),
174  QDir::currentPath(), i18n("Shortcuts (*.shortcuts)"));
175  if (path.isEmpty()) {
176  return;
177  }
178 
179  m_dialog->exportConfiguration(path);
180 }
181 
182 void KShortcutSchemesEditor::importShortcutsScheme()
183 {
184  //ask user about dir
185  QString path = QFileDialog::getOpenFileName(this, i18nc("@title:window", "Import Shortcuts"),
186  QDir::currentPath(), i18n("Shortcuts (*.shortcuts)"));
187  if (path.isEmpty()) {
188  return;
189  }
190 
191  m_dialog->importConfiguration(path);
192 }
193 
194 void KShortcutSchemesEditor::saveAsDefaultsForScheme()
195 {
196  if (KShortcutSchemesHelper::saveShortcutScheme(m_dialog->actionCollections(), currentScheme())) {
197  KMessageBox::information(this, i18n("Shortcut scheme successfully saved."));
198  } else {
199  // We'd need to return to return more than a bool, to show more details here.
200  KMessageBox::sorry(this, i18n("Error saving the shortcut scheme."));
201  }
202 }
203 
204 void KShortcutSchemesEditor::updateDeleteButton()
205 {
206  m_deleteScheme->setEnabled(m_schemesList->count() >= 1);
207 }
void setMenu(QMenu *menu)
A container for a set of QAction objects.
A KXMLGUIClient can be used with KXMLGUIFactory to create a GUI from actions and an XML document...
Definition: kxmlguiclient.h:38
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QDomNode appendChild(const QDomNode &newChild)
bool remove()
QString toString(int indent) const const
virtual QString componentName() const
QString currentPath()
QAction * addAction(const QString &text)
void setBuddy(QWidget *buddy)
void textActivated(const QString &text)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
bool isEmpty() const const
void clicked(bool checked)
void activated(int index)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
ButtonCode questionYesNo(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Notify)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18n(const char *text, const TYPE &arg...)
void addStretch(int stretch)
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
QDomElement createElement(const QString &tagName)
Dialog for configuration of KActionCollection and KGlobalAccel.
bool mkpath(const QString &dirPath) const const
QString applicationName()
void sorry(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Aug 12 2020 22:50:46 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.