KXmlGui

kxmlguiwindow.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2000 Reginald Stadlbauer <[email protected]>
4  SPDX-FileCopyrightText: 1997 Stephan Kulow <[email protected]>
5  SPDX-FileCopyrightText: 1997-2000 Sven Radej <[email protected]>
6  SPDX-FileCopyrightText: 1997-2000 Matthias Ettrich <[email protected]>
7  SPDX-FileCopyrightText: 1999 Chris Schlaeger <[email protected]>
8  SPDX-FileCopyrightText: 2002 Joseph Wenninger <[email protected]>
9  SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <[email protected]>
10 
11  SPDX-License-Identifier: LGPL-2.0-only
12 */
13 
14 #include "kxmlguiwindow.h"
15 #include "debug.h"
16 
17 #include "kmainwindow_p.h"
18 #include "kmessagebox.h"
19 #include "kactioncollection.h"
20 #ifdef QT_DBUS_LIB
21 #include "kmainwindowiface_p.h"
22 #endif
23 #include "ktoolbarhandler_p.h"
24 #include "kxmlguifactory.h"
25 #include "kedittoolbar.h"
26 #include "khelpmenu.h"
27 #include "ktoolbar.h"
28 
29 #ifdef QT_DBUS_LIB
30 #include <QDBusConnection>
31 #endif
32 #include <QDomDocument>
33 #include <QMenuBar>
34 #include <QStatusBar>
35 #include <QWidget>
36 #include <QList>
37 #include <QEvent>
38 
39 #include <ktoggleaction.h>
40 #include <kstandardaction.h>
41 #include <kconfig.h>
42 #include <klocalizedstring.h>
43 #include <kaboutdata.h>
44 #include <ksharedconfig.h>
45 #include <kconfiggroup.h>
46 
47 #include <stdlib.h>
48 #include <ctype.h>
49 
50 class KXmlGuiWindowPrivate : public KMainWindowPrivate
51 {
52 public:
53  void _k_slotFactoryMakingChanges(bool b)
54  {
55  // While the GUI factory is adding/removing clients,
56  // don't let KMainWindow think those are changes made by the user
57  // #105525
58  letDirtySettings = !b;
59  }
60 
61  bool showHelpMenu: 1;
63 
64  KDEPrivate::ToolBarHandler *toolBarHandler;
65  KToggleAction *showStatusBarAction;
66  QPointer<KEditToolBar> toolBarEditor;
67  KXMLGUIFactory *factory;
68 };
69 
71  : KMainWindow(*new KXmlGuiWindowPrivate, parent, f), KXMLGUIBuilder(this)
72 {
73  K_D(KXmlGuiWindow);
74  d->showHelpMenu = true;
75  d->toolBarHandler = nullptr;
76  d->showStatusBarAction = nullptr;
77  d->factory = nullptr;
78 #ifdef QT_DBUS_LIB
79  new KMainWindowInterface(this);
80 #endif
81 }
82 
84 {
85  K_D(KXmlGuiWindow);
86  if (!d->toolBarHandler) {
87  return nullptr;
88  }
89 
90  return d->toolBarHandler->toolBarMenuAction();
91 }
92 
94 {
95  K_D(KXmlGuiWindow);
96  if (d->toolBarHandler) {
97  d->toolBarHandler->setupActions();
98  }
99 }
100 
102 {
103  K_D(KXmlGuiWindow);
104  delete d->factory;
105 }
106 
108 {
109  bool ret = KMainWindow::event(ev);
110  if (ev->type() == QEvent::Polish) {
111 #ifdef QT_DBUS_LIB
118 #endif
119  }
120  return ret;
121 }
122 
123 void KXmlGuiWindow::setHelpMenuEnabled(bool showHelpMenu)
124 {
125  K_D(KXmlGuiWindow);
126  d->showHelpMenu = showHelpMenu;
127 }
128 
130 {
131  K_D(const KXmlGuiWindow);
132  return d->showHelpMenu;
133 }
134 
135 KXMLGUIFactory *KXmlGuiWindow::guiFactory()
136 {
137  K_D(KXmlGuiWindow);
138  if (!d->factory) {
139  d->factory = new KXMLGUIFactory(this, this);
140  connect(d->factory, SIGNAL(makingChanges(bool)),
141  this, SLOT(_k_slotFactoryMakingChanges(bool)));
142  }
143  return d->factory;
144 }
145 
147 {
148  K_D(KXmlGuiWindow);
151  if (!d->toolBarEditor) {
152  d->toolBarEditor = new KEditToolBar(guiFactory(), this);
153  d->toolBarEditor->setAttribute(Qt::WA_DeleteOnClose);
154  connect(d->toolBarEditor, &KEditToolBar::newToolBarConfig,
156  }
157  d->toolBarEditor->show();
158 }
159 
161 {
162  // createGUI(xmlFile()); // this loses any plugged-in guiclients, so we use remove+add instead.
163 
164  guiFactory()->removeClient(this);
165  guiFactory()->addClient(this);
166 
169 }
170 
172 {
173  setupGUI(QSize(), options, xmlfile);
174 }
175 
176 void KXmlGuiWindow::setupGUI(const QSize &defaultSize, StandardWindowOptions options, const QString &xmlfile)
177 {
178  K_D(KXmlGuiWindow);
179 
180  if (options & Keys) {
181  KStandardAction::keyBindings(guiFactory(),
182  SLOT(configureShortcuts()), actionCollection());
183  }
184 
185  if ((options & StatusBar) && statusBar()) {
187  }
188 
189  if (options & ToolBar) {
193  }
194 
195  d->defaultSize = defaultSize;
196 
197  if (options & Create) {
198  createGUI(xmlfile);
199  }
200 
201  if (d->defaultSize.isValid()) {
202  resize(d->defaultSize);
203  } else if (isHidden()) {
204  adjustSize();
205  }
206 
207  if (options & Save) {
208  const KConfigGroup cg(autoSaveConfigGroup());
209  if (cg.isValid()) {
211  } else {
213  }
214  }
215 }
216 void KXmlGuiWindow::createGUI(const QString &xmlfile)
217 {
218  K_D(KXmlGuiWindow);
219  // disabling the updates prevents unnecessary redraws
220  //setUpdatesEnabled( false );
221 
222  // just in case we are rebuilding, let's remove our old client
223  guiFactory()->removeClient(this);
224 
225  // make sure to have an empty GUI
226  QMenuBar *mb = menuBar();
227  if (mb) {
228  mb->clear();
229  }
230 
231  qDeleteAll(toolBars()); // delete all toolbars
232 
233  // don't build a help menu unless the user ask for it
234  if (d->showHelpMenu) {
235  delete d->helpMenu;
236  // we always want a help menu
237  d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true);
238 
240  QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents);
241  QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis);
242  QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug);
243  QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage);
244  QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp);
245  QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE);
246  QAction *donateAction = d->helpMenu->action(KHelpMenu::menuDonate);
247 
248  if (helpContentsAction) {
249  actions->addAction(helpContentsAction->objectName(), helpContentsAction);
250  }
251  if (whatsThisAction) {
252  actions->addAction(whatsThisAction->objectName(), whatsThisAction);
253  }
254  if (reportBugAction) {
255  actions->addAction(reportBugAction->objectName(), reportBugAction);
256  }
257  if (switchLanguageAction) {
258  actions->addAction(switchLanguageAction->objectName(), switchLanguageAction);
259  }
260  if (aboutAppAction) {
261  actions->addAction(aboutAppAction->objectName(), aboutAppAction);
262  }
263  if (aboutKdeAction) {
264  actions->addAction(aboutKdeAction->objectName(), aboutKdeAction);
265  }
266  if (donateAction) {
267  actions->addAction(donateAction->objectName(), donateAction);
268  }
269  }
270 
271  const QString windowXmlFile = xmlfile.isNull() ? componentName() + QLatin1String("ui.rc") : xmlfile;
272 
273  // Help beginners who call setXMLFile and then setupGUI...
274  if (!xmlFile().isEmpty() && xmlFile() != windowXmlFile) {
275  qCWarning(DEBUG_KXMLGUI) << "You called setXMLFile(" << xmlFile() << ") and then createGUI or setupGUI,"
276  << "which also calls setXMLFile and will overwrite the file you have previously set.\n"
277  << "You should call createGUI(" << xmlFile() << ") or setupGUI(<options>," << xmlFile() << ") instead.";
278  }
279 
280  // we always want to load in our global standards file
282 
283  // now, merge in our local xml file.
284  setXMLFile(windowXmlFile, true);
285 
286  // make sure we don't have any state saved already
288 
289  // do the actual GUI building
290  guiFactory()->reset();
291  guiFactory()->addClient(this);
292 
294 
295  // setUpdatesEnabled( true );
296 }
297 
299 {
300  stateChanged(newstate, KXMLGUIClient::StateNoReverse);
301 }
302 
304  bool reverse)
305 {
306  stateChanged(newstate,
307  reverse ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse);
308 }
309 
311 {
312  K_D(KXmlGuiWindow);
313  if (enable) {
314  if (d->toolBarHandler) {
315  return;
316  }
317 
318  d->toolBarHandler = new KDEPrivate::ToolBarHandler(this);
319 
320  if (factory()) {
321  factory()->addClient(d->toolBarHandler);
322  }
323  } else {
324  if (!d->toolBarHandler) {
325  return;
326  }
327 
328  if (factory()) {
329  factory()->removeClient(d->toolBarHandler);
330  }
331 
332  delete d->toolBarHandler;
333  d->toolBarHandler = nullptr;
334  }
335 }
336 
337 bool KXmlGuiWindow::isStandardToolBarMenuEnabled() const
338 {
339  K_D(const KXmlGuiWindow);
340  return (d->toolBarHandler);
341 }
342 
344 {
345  K_D(KXmlGuiWindow);
346  if (!d->showStatusBarAction) {
348  QStatusBar *sb = statusBar(); // Creates statusbar if it doesn't exist already.
349  connect(d->showStatusBarAction, &QAction::toggled,
350  sb, &QWidget::setVisible);
351  d->showStatusBarAction->setChecked(sb->isHidden());
352  } else {
353  // If the language has changed, we'll need to grab the new text and whatsThis
354  QAction *tmpStatusBar = KStandardAction::showStatusbar(nullptr, nullptr, nullptr);
355  d->showStatusBarAction->setText(tmpStatusBar->text());
356  d->showStatusBarAction->setWhatsThis(tmpStatusBar->whatsThis());
357  delete tmpStatusBar;
358  }
359 }
360 
361 void KXmlGuiWindow::finalizeGUI(bool /*force*/)
362 {
363  // FIXME: this really needs to be removed with a code more like the one we had on KDE3.
364  // what we need to do here is to position correctly toolbars so they don't overlap.
365  // Also, take in count plugins could provide their own toolbars and those also need to
366  // be restored.
367  if (autoSaveSettings() && autoSaveConfigGroup().isValid()) {
369  }
370 }
371 
373 {
374  K_D(KXmlGuiWindow);
376  QStatusBar *sb = findChild<QStatusBar *>();
377  if (sb && d->showStatusBarAction) {
378  d->showStatusBarAction->setChecked(!sb->isHidden());
379  }
380 }
381 
382 // KDE5 TODO: change it to "using KXMLGUIBuilder::finalizeGUI;" in the header
383 // and remove the reimplementation
384 void KXmlGuiWindow::finalizeGUI(KXMLGUIClient *client)
385 {
386  KXMLGUIBuilder::finalizeGUI(client);
387 }
388 
390 {
391  QMap<QString, QAction*> shortcuts;
392  QAction *editCutAction = actionCollection()->action(QStringLiteral("edit_cut"));
393  QAction *deleteFileAction = actionCollection()->action(QStringLiteral("deletefile"));
394  const auto actions = actionCollection()->actions();
395  for (QAction *action : actions) {
396  if (action->isEnabled()) {
397  const auto actionShortcuts = action->shortcuts();
398  for (const QKeySequence &shortcut : actionShortcuts) {
399  if (shortcut.isEmpty()) {
400  continue;
401  }
402  const QString portableShortcutText = shortcut.toString();
403  const QAction *existingShortcutAction = shortcuts.value(portableShortcutText);
404  if (existingShortcutAction) {
405  // If the shortcut is already in use we give a warning, so that hopefully the developer will find it
406  // There is one exception, if the conflicting shortcut is a non primary shortcut of "edit_cut"
407  // and "deleteFileAction" is the other action since Shift+Delete is used for both in our default code
408  bool showWarning = true;
409  if ((action == editCutAction && existingShortcutAction == deleteFileAction) ||
410  (action == deleteFileAction && existingShortcutAction == editCutAction)) {
411  QList<QKeySequence> editCutActionShortcuts = editCutAction->shortcuts();
412  if (editCutActionShortcuts.indexOf(shortcut) > 0) // alternate shortcut
413  {
414  editCutActionShortcuts.removeAll(shortcut);
415  editCutAction->setShortcuts(editCutActionShortcuts);
416 
417  showWarning = false;
418  }
419  }
420 
421  if (showWarning) {
423  const QString existingShortcutActionName = KLocalizedString::removeAcceleratorMarker(existingShortcutAction->text());
424  QString dontShowAgainString = existingShortcutActionName + actionName + shortcut.toString();
425  dontShowAgainString.remove(QLatin1Char('\\'));
426  KMessageBox::information(this, i18n("There are two actions (%1, %2) that want to use the same shortcut (%3). This is most probably a bug. Please report it in <a href='https://bugs.kde.org'>bugs.kde.org</a>", existingShortcutActionName, actionName, shortcut.toString(QKeySequence::NativeText)), i18n("Ambiguous Shortcuts"), dontShowAgainString, KMessageBox::Notify | KMessageBox::AllowLink);
427  }
428  } else {
429  shortcuts.insert(portableShortcutText, action);
430  }
431  }
432  }
433  }
434 }
435 
436 #include "moc_kxmlguiwindow.cpp"
437 
QAction * toolBarMenuAction()
Returns a pointer to the mainwindows action responsible for the toolbars menu.
bool event(QEvent *event) override
Reimplemented to catch QEvent::Polish in order to adjust the object name if needed, once all constructor code for the main window has run.
virtual void configureToolbars()
Show a standard configure toolbar dialog.
adds action to show/hide the statusbar if the statusbar exists.
void resize(int w, int h)
A container for a set of QAction objects.
QEvent::Type type() const const
void createGUI(const QString &xmlfile=QString())
Create a GUI given a local XML file.
bool isHidden() const const
void setSettingsDirty()
Tell the main window that it should save its settings when being closed.
virtual KActionCollection * actionCollection() const
Retrieves the entire action collection for the GUI client.
A KXMLGUIClient can be used with KXMLGUIFactory to create a GUI from actions and an XML document...
Definition: kxmlguiclient.h:38
bool event(QEvent *event) override
Reimplemented to catch QEvent::Polish in order to adjust the object name if needed, once all constructor code for the main window has run.
static KAboutData applicationData()
void setHelpMenuEnabled(bool showHelpMenu=true)
Enables the build of a standard help menu when calling createGUI() or setupGUI(). ...
QMenuBar * menuBar() const const
void removeClient(KXMLGUIClient *client)
Removes the GUI described by the client, by unplugging all provided actions and removing all owned co...
static QString removeAcceleratorMarker(const QString &label)
void clear()
KToggleAction * showStatusbar(const QObject *recvr, const char *slot, QObject *parent)
QStatusBar * statusBar() const const
void addClient(KXMLGUIClient *client)
Creates the GUI described by the QDomDocument of the client, using the client&#39;s actions, and merges it with the previously created GUI.
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
QList< QKeySequence > shortcuts() const const
void loadStandardsXmlFile()
Load the ui_standards.rc file.
virtual void setVisible(bool visible)
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
Add an action under the given name to the collection.
virtual void setXMLFile(const QString &file, bool merge=false, bool setXMLDoc=true)
Sets the name of the rc file containing the XML for the part.
QDBusConnection sessionBus()
KXMLGUIFactory * factory() const
Retrieves a pointer to the KXMLGUIFactory this client is associated with (will return nullptr if the ...
virtual QString componentName() const
virtual QString xmlFile() const
This will return the name of the XML file as set by setXMLFile().
bool isValid() const
virtual void slotStateChanged(const QString &newstate)
Apply a state change.
~KXmlGuiWindow() override
Destructor.
void reset()
Use this method to free all memory allocated by the KXMLGUIFactory.
void adjustSize()
void toggled(bool checked)
bool isNull() const const
int indexOf(const T &value, int from) const const
void checkAmbiguousShortcuts()
Checks if there are actions using the same shortcut.
void setShortcuts(const QList< QKeySequence > &shortcuts)
Standard KDE help menu with dialog boxes.
Definition: khelpmenu.h:109
Top level main window with predefined action layout.
Definition: kxmlguiwindow.h:45
virtual void stateChanged(const QString &newstate, ReverseStateChange reverse=StateNoReverse)
Actions can collectively be assigned a "State".
void newToolBarConfig()
Signal emitted when &#39;apply&#39; or &#39;ok&#39; is clicked or toolbars were reset.
KXmlGuiWindow(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
Construct a main window.
adds action to show/hide the toolbar(s) and adds action to configure the toolbar(s).
Top level main window.
Definition: kmainwindow.h:96
Implements the creation of the GUI (menubar, menus and toolbars) as requested by the GUI factory...
void setupToolbarMenuActions()
auto-saves (and loads) the toolbar/menubar/statusbar settings and window size using the default name...
A dialog used to customize or configure toolbars.
Definition: kedittoolbar.h:61
bool isEmpty() const const
int removeAll(const T &value)
QList< QAction * > actions() const
Returns the list of QActions which belong to this action collection.
void createStandardStatusBarAction()
Sets whether KMainWindow should provide a menu that allows showing/hiding of the statusbar ( using KS...
bool autoSaveSettings() const
void applyMainWindowSettings(const KConfigGroup &config) override
Read settings for statusbar, menubar and toolbar from their respective groups in the config file and ...
adds action to show the key configure action.
void setupGUI(StandardWindowOptions options=Default, const QString &xmlfile=QString())
Configures the current windows and its actions in the typical KDE fashion.
KXMLGUIFactory, together with KXMLGUIClient objects, can be used to create a GUI of container widgets...
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
KREPORT_EXPORT QPageSize::PageSizeId defaultSize()
WA_DeleteOnClose
QString i18n(const char *text, const TYPE &arg...)
void setAutoSaveSettings(const QString &groupName=QStringLiteral("MainWindow"), bool saveWindowSize=true)
Call this to enable "auto-save" of toolbar/menubar/statusbar settings (and optionally window size)...
QAction * action(const char *name) const
Retrieves an action of the client by name.
QAction * keyBindings(const QObject *recvr, const char *slot, QObject *parent)
virtual void saveNewToolbarConfig()
Rebuilds the GUI after KEditToolBar changed the toolbar layout.
void setStandardToolBarMenuEnabled(bool enable)
Sets whether KMainWindow should provide a menu that allows showing/hiding the available toolbars ( us...
QString dbusName() const
Returns the path under which this window&#39;s D-Bus object is exported.
QAction * action(int index) const
Return the QAction* at position index in the action collection.
QMap::iterator insert(const Key &key, const T &value)
void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const const
calls createGUI() once ToolBar, Keys and Statusbar have been taken care of.
bool isHelpMenuEnabled() const
Return true when the help menu is enabled.
typedef WindowFlags
void saveMainWindowSettings(KConfigGroup &config)
Save settings for statusbar, menubar and toolbar to their respective groups in the config group confi...
bool isEnabled() const const
KConfigGroup autoSaveConfigGroup() const
virtual void applyMainWindowSettings(const KConfigGroup &config)
Read settings for statusbar, menubar and toolbar from their respective groups in the config file and ...
QList< KToolBar * > toolBars() const
const T value(const Key &key, const T &defaultValue) const const
void setXMLGUIBuildDocument(const QDomDocument &doc)
QAction * configureToolbars(const QObject *recvr, const char *slot, QObject *parent)
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.