1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2000 Reginald Stadlbauer <reggie@kde.org> |
4 | SPDX-FileCopyrightText: 1997 Stephan Kulow <coolo@kde.org> |
5 | SPDX-FileCopyrightText: 1997-2000 Sven Radej <radej@kde.org> |
6 | SPDX-FileCopyrightText: 1997-2000 Matthias Ettrich <ettrich@kde.org> |
7 | SPDX-FileCopyrightText: 1999 Chris Schlaeger <cs@kde.org> |
8 | SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org> |
9 | SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org> |
10 | |
11 | SPDX-License-Identifier: LGPL-2.0-only |
12 | */ |
13 | |
14 | #include "kxmlguiwindow.h" |
15 | #include "debug.h" |
16 | |
17 | #include "kactioncollection.h" |
18 | #include "kmainwindow_p.h" |
19 | #include <KMessageBox> |
20 | #include <kcommandbar.h> |
21 | #ifdef WITH_QTDBUS |
22 | #include "kmainwindowiface_p.h" |
23 | #endif |
24 | #include "kedittoolbar.h" |
25 | #include "khelpmenu.h" |
26 | #include "ktoolbar.h" |
27 | #include "ktoolbarhandler_p.h" |
28 | #include "kxmlguifactory.h" |
29 | |
30 | #ifdef WITH_QTDBUS |
31 | #include <QDBusConnection> |
32 | #endif |
33 | #include <QDomDocument> |
34 | #include <QEvent> |
35 | #include <QList> |
36 | #include <QMenuBar> |
37 | #include <QStatusBar> |
38 | #include <QWidget> |
39 | |
40 | #include <KAboutData> |
41 | #include <KCommandBar> |
42 | #include <KConfig> |
43 | #include <KConfigGroup> |
44 | #include <KLocalizedString> |
45 | #include <KSharedConfig> |
46 | #include <KStandardActions> |
47 | #include <KToggleAction> |
48 | |
49 | #include <cctype> |
50 | #include <cstdlib> |
51 | |
52 | /* |
53 | * A helper function that takes a list of KActionCollection* and converts it |
54 | * to KCommandBar::ActionGroup |
55 | */ |
56 | static QList<KCommandBar::ActionGroup> actionCollectionToActionGroup(const std::vector<KActionCollection *> &actionCollections) |
57 | { |
58 | using ActionGroup = KCommandBar::ActionGroup; |
59 | |
60 | QList<ActionGroup> actionList; |
61 | actionList.reserve(asize: actionCollections.size()); |
62 | |
63 | for (const auto collection : actionCollections) { |
64 | const QList<QAction *> collectionActions = collection->actions(); |
65 | const QString componentName = collection->componentDisplayName(); |
66 | |
67 | ActionGroup ag; |
68 | ag.name = componentName; |
69 | ag.actions.reserve(asize: collection->count()); |
70 | for (const auto action : collectionActions) { |
71 | /* |
72 | * If this action is a menu, fetch all its child actions |
73 | * and skip the menu action itself |
74 | */ |
75 | if (QMenu * = action->menu()) { |
76 | const QList<QAction *> = menu->actions(); |
77 | |
78 | ActionGroup ; |
79 | menuActionGroup.name = KLocalizedString::removeAcceleratorMarker(label: action->text()); |
80 | menuActionGroup.actions.reserve(asize: menuActions.size()); |
81 | for (const auto mAct : menuActions) { |
82 | if (mAct) { |
83 | menuActionGroup.actions.append(t: mAct); |
84 | } |
85 | } |
86 | |
87 | /* |
88 | * If there were no actions in the menu, we |
89 | * add the menu to the list instead because it could |
90 | * be that the actions are created on demand i.e., aboutToShow() |
91 | */ |
92 | if (!menuActions.isEmpty()) { |
93 | actionList.append(t: menuActionGroup); |
94 | continue; |
95 | } |
96 | } |
97 | |
98 | if (action && !action->text().isEmpty()) { |
99 | ag.actions.append(t: action); |
100 | } |
101 | } |
102 | actionList.append(t: ag); |
103 | } |
104 | return actionList; |
105 | } |
106 | |
107 | static void getActionCollections(KXMLGUIClient *client, std::vector<KActionCollection *> &actionCollections) |
108 | { |
109 | if (!client) { |
110 | return; |
111 | } |
112 | |
113 | auto actionCollection = client->actionCollection(); |
114 | if (actionCollection && !actionCollection->isEmpty()) { |
115 | actionCollections.push_back(x: client->actionCollection()); |
116 | } |
117 | |
118 | const QList<KXMLGUIClient *> childClients = client->childClients(); |
119 | for (auto child : childClients) { |
120 | getActionCollections(client: child, actionCollections); |
121 | } |
122 | } |
123 | |
124 | class KXmlGuiWindowPrivate : public KMainWindowPrivate |
125 | { |
126 | public: |
127 | void slotFactoryMakingChanges(bool b) |
128 | { |
129 | // While the GUI factory is adding/removing clients, |
130 | // don't let KMainWindow think those are changes made by the user |
131 | // #105525 |
132 | letDirtySettings = !b; |
133 | } |
134 | |
135 | bool commandBarEnabled = true; |
136 | // Last executed actions in command bar |
137 | QList<QString> lastExecutedActions; |
138 | |
139 | bool : 1; |
140 | QSize defaultSize; |
141 | |
142 | KDEPrivate::ToolBarHandler *toolBarHandler; |
143 | KToggleAction *showStatusBarAction; |
144 | QPointer<KEditToolBar> toolBarEditor; |
145 | KXMLGUIFactory *factory; |
146 | }; |
147 | |
148 | KXmlGuiWindow::KXmlGuiWindow(QWidget *parent, Qt::WindowFlags flags) |
149 | : KMainWindow(*new KXmlGuiWindowPrivate, parent, flags) |
150 | , KXMLGUIBuilder(this) |
151 | { |
152 | Q_D(KXmlGuiWindow); |
153 | d->showHelpMenu = true; |
154 | d->toolBarHandler = nullptr; |
155 | d->showStatusBarAction = nullptr; |
156 | d->factory = nullptr; |
157 | #ifdef WITH_QTDBUS |
158 | new KMainWindowInterface(this); |
159 | #endif |
160 | |
161 | /* |
162 | * Set up KCommandBar launcher action |
163 | */ |
164 | auto a = actionCollection()->addAction(QStringLiteral("open_kcommand_bar" ), receiver: this, slot: [this] { |
165 | /* |
166 | * Do nothing when command bar is disabled |
167 | */ |
168 | if (!isCommandBarEnabled()) { |
169 | return; |
170 | } |
171 | |
172 | auto ac = actionCollection(); |
173 | if (!ac) { |
174 | return; |
175 | } |
176 | |
177 | auto kc = new KCommandBar(this); |
178 | std::vector<KActionCollection *> actionCollections; |
179 | const auto clients = guiFactory()->clients(); |
180 | actionCollections.reserve(n: clients.size()); |
181 | |
182 | // Grab action collections recursively |
183 | for (const auto &client : clients) { |
184 | getActionCollections(client, actionCollections); |
185 | } |
186 | |
187 | kc->setActions(actionCollectionToActionGroup(actionCollections)); |
188 | kc->show(); |
189 | }); |
190 | a->setIcon(QIcon::fromTheme(QStringLiteral("search" ))); |
191 | a->setText(i18n("Find Action…" )); |
192 | KActionCollection::setDefaultShortcut(action: a, shortcut: QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I)); |
193 | } |
194 | |
195 | QAction *KXmlGuiWindow::() |
196 | { |
197 | Q_D(KXmlGuiWindow); |
198 | if (!d->toolBarHandler) { |
199 | return nullptr; |
200 | } |
201 | |
202 | return d->toolBarHandler->toolBarMenuAction(); |
203 | } |
204 | |
205 | void KXmlGuiWindow::() |
206 | { |
207 | Q_D(KXmlGuiWindow); |
208 | if (d->toolBarHandler) { |
209 | d->toolBarHandler->setupActions(); |
210 | } |
211 | } |
212 | |
213 | bool KXmlGuiWindow::isToolBarVisible(const QString &name) |
214 | { |
215 | KToolBar *tb = findChild<KToolBar *>(aName: name); |
216 | if (!tb) { |
217 | return false; |
218 | } |
219 | |
220 | return tb->isVisible(); |
221 | } |
222 | |
223 | void KXmlGuiWindow::setToolBarVisible(const QString &name, bool visible) |
224 | { |
225 | KToolBar *tb = findChild<KToolBar *>(aName: name); |
226 | if (!tb) { |
227 | return; |
228 | } |
229 | |
230 | tb->setVisible(visible); |
231 | } |
232 | |
233 | QStringList KXmlGuiWindow::toolBarNames() const |
234 | { |
235 | QList<KToolBar *> bars = toolBars(); |
236 | QStringList ret; |
237 | |
238 | for (KToolBar *bar : bars) { |
239 | ret.append(t: bar->objectName()); |
240 | } |
241 | |
242 | return ret; |
243 | } |
244 | |
245 | KXmlGuiWindow::~KXmlGuiWindow() |
246 | { |
247 | Q_D(KXmlGuiWindow); |
248 | delete d->factory; |
249 | } |
250 | |
251 | bool KXmlGuiWindow::event(QEvent *ev) |
252 | { |
253 | bool ret = KMainWindow::event(event: ev); |
254 | if (ev->type() == QEvent::Polish) { |
255 | #ifdef WITH_QTDBUS |
256 | /* clang-format off */ |
257 | constexpr auto opts = QDBusConnection::ExportScriptableSlots |
258 | | QDBusConnection::ExportScriptableProperties |
259 | | QDBusConnection::ExportNonScriptableSlots |
260 | | QDBusConnection::ExportNonScriptableProperties |
261 | | QDBusConnection::ExportChildObjects; |
262 | /* clang-format on */ |
263 | QDBusConnection::sessionBus().registerObject(path: dbusName() + QLatin1String("/actions" ), object: actionCollection(), options: opts); |
264 | #endif |
265 | } |
266 | return ret; |
267 | } |
268 | |
269 | void KXmlGuiWindow::(bool ) |
270 | { |
271 | Q_D(KXmlGuiWindow); |
272 | d->showHelpMenu = showHelpMenu; |
273 | } |
274 | |
275 | bool KXmlGuiWindow::() const |
276 | { |
277 | Q_D(const KXmlGuiWindow); |
278 | return d->showHelpMenu; |
279 | } |
280 | |
281 | KXMLGUIFactory *KXmlGuiWindow::guiFactory() |
282 | { |
283 | Q_D(KXmlGuiWindow); |
284 | if (!d->factory) { |
285 | d->factory = new KXMLGUIFactory(this, this); |
286 | connect(sender: d->factory, signal: &KXMLGUIFactory::makingChanges, context: this, slot: [d](bool state) { |
287 | d->slotFactoryMakingChanges(b: state); |
288 | }); |
289 | } |
290 | return d->factory; |
291 | } |
292 | |
293 | void KXmlGuiWindow::configureToolbars() |
294 | { |
295 | Q_D(KXmlGuiWindow); |
296 | KConfigGroup cg(KSharedConfig::openConfig(), QString()); |
297 | saveMainWindowSettings(config&: cg); |
298 | if (!d->toolBarEditor) { |
299 | d->toolBarEditor = new KEditToolBar(guiFactory(), this); |
300 | d->toolBarEditor->setAttribute(Qt::WA_DeleteOnClose); |
301 | connect(sender: d->toolBarEditor, signal: &KEditToolBar::newToolBarConfig, context: this, slot: &KXmlGuiWindow::saveNewToolbarConfig); |
302 | } |
303 | d->toolBarEditor->show(); |
304 | } |
305 | |
306 | void KXmlGuiWindow::saveNewToolbarConfig() |
307 | { |
308 | // createGUI(xmlFile()); // this loses any plugged-in guiclients, so we use remove+add instead. |
309 | |
310 | guiFactory()->removeClient(client: this); |
311 | guiFactory()->addClient(client: this); |
312 | |
313 | KConfigGroup cg(KSharedConfig::openConfig(), QString()); |
314 | applyMainWindowSettings(config: cg); |
315 | } |
316 | |
317 | void KXmlGuiWindow::setupGUI(StandardWindowOptions options, const QString &xmlfile) |
318 | { |
319 | setupGUI(defaultSize: QSize(), options, xmlfile); |
320 | } |
321 | |
322 | void KXmlGuiWindow::setupGUI(const QSize &defaultSize, StandardWindowOptions options, const QString &xmlfile) |
323 | { |
324 | Q_D(KXmlGuiWindow); |
325 | |
326 | if (options & Keys) { |
327 | KStandardActions::keyBindings(recvr: guiFactory(), slot: &KXMLGUIFactory::showConfigureShortcutsDialog, parent: actionCollection()); |
328 | } |
329 | |
330 | if ((options & StatusBar) && statusBar()) { |
331 | createStandardStatusBarAction(); |
332 | } |
333 | |
334 | if (options & ToolBar) { |
335 | setStandardToolBarMenuEnabled(true); |
336 | KStandardActions::configureToolbars(recvr: this, slot: &KXmlGuiWindow::configureToolbars, parent: actionCollection()); |
337 | } |
338 | |
339 | d->defaultSize = defaultSize; |
340 | |
341 | if (options & Create) { |
342 | createGUI(xmlfile); |
343 | } |
344 | |
345 | if (d->defaultSize.isValid()) { |
346 | resize(d->defaultSize); |
347 | } else if (isHidden()) { |
348 | adjustSize(); |
349 | } |
350 | |
351 | if (options & Save) { |
352 | const KConfigGroup cg(autoSaveConfigGroup()); |
353 | if (cg.isValid()) { |
354 | setAutoSaveSettings(group: cg); |
355 | } else { |
356 | setAutoSaveSettings(); |
357 | } |
358 | } |
359 | } |
360 | void KXmlGuiWindow::createGUI(const QString &xmlfile) |
361 | { |
362 | Q_D(KXmlGuiWindow); |
363 | // disabling the updates prevents unnecessary redraws |
364 | // setUpdatesEnabled( false ); |
365 | |
366 | // just in case we are rebuilding, let's remove our old client |
367 | guiFactory()->removeClient(client: this); |
368 | |
369 | // make sure to have an empty GUI |
370 | QMenuBar *mb = menuBar(); |
371 | if (mb) { |
372 | mb->clear(); |
373 | } |
374 | |
375 | qDeleteAll(c: toolBars()); // delete all toolbars |
376 | |
377 | // don't build a help menu unless the user ask for it |
378 | if (d->showHelpMenu) { |
379 | delete d->helpMenu; |
380 | // we always want a help menu |
381 | d->helpMenu = new KHelpMenu(this); |
382 | |
383 | KActionCollection *actions = actionCollection(); |
384 | QAction *helpContentsAction = d->helpMenu->action(id: KHelpMenu::menuHelpContents); |
385 | QAction *whatsThisAction = d->helpMenu->action(id: KHelpMenu::menuWhatsThis); |
386 | QAction *reportBugAction = d->helpMenu->action(id: KHelpMenu::menuReportBug); |
387 | QAction *switchLanguageAction = d->helpMenu->action(id: KHelpMenu::menuSwitchLanguage); |
388 | QAction *aboutAppAction = d->helpMenu->action(id: KHelpMenu::menuAboutApp); |
389 | QAction *aboutKdeAction = d->helpMenu->action(id: KHelpMenu::menuAboutKDE); |
390 | QAction *donateAction = d->helpMenu->action(id: KHelpMenu::menuDonate); |
391 | |
392 | if (helpContentsAction) { |
393 | actions->addAction(name: helpContentsAction->objectName(), action: helpContentsAction); |
394 | } |
395 | if (whatsThisAction) { |
396 | actions->addAction(name: whatsThisAction->objectName(), action: whatsThisAction); |
397 | } |
398 | if (reportBugAction) { |
399 | actions->addAction(name: reportBugAction->objectName(), action: reportBugAction); |
400 | } |
401 | if (switchLanguageAction) { |
402 | actions->addAction(name: switchLanguageAction->objectName(), action: switchLanguageAction); |
403 | } |
404 | if (aboutAppAction) { |
405 | actions->addAction(name: aboutAppAction->objectName(), action: aboutAppAction); |
406 | } |
407 | if (aboutKdeAction) { |
408 | actions->addAction(name: aboutKdeAction->objectName(), action: aboutKdeAction); |
409 | } |
410 | if (donateAction) { |
411 | actions->addAction(name: donateAction->objectName(), action: donateAction); |
412 | } |
413 | } |
414 | |
415 | const QString windowXmlFile = xmlfile.isNull() ? componentName() + QLatin1String("ui.rc" ) : xmlfile; |
416 | |
417 | // Help beginners who call setXMLFile and then setupGUI... |
418 | if (!xmlFile().isEmpty() && xmlFile() != windowXmlFile) { |
419 | qCWarning(DEBUG_KXMLGUI) << "You called setXMLFile(" << xmlFile() << ") and then createGUI or setupGUI," |
420 | << "which also calls setXMLFile and will overwrite the file you have previously set.\n" |
421 | << "You should call createGUI(" << xmlFile() << ") or setupGUI(<options>," << xmlFile() << ") instead." ; |
422 | } |
423 | |
424 | // we always want to load in our global standards file |
425 | loadStandardsXmlFile(); |
426 | |
427 | // now, merge in our local xml file. |
428 | setXMLFile(file: windowXmlFile, merge: true); |
429 | |
430 | // make sure we don't have any state saved already |
431 | setXMLGUIBuildDocument(QDomDocument()); |
432 | |
433 | // do the actual GUI building |
434 | guiFactory()->reset(); |
435 | guiFactory()->addClient(client: this); |
436 | |
437 | checkAmbiguousShortcuts(); |
438 | |
439 | // setUpdatesEnabled( true ); |
440 | } |
441 | |
442 | void KXmlGuiWindow::slotStateChanged(const QString &newstate) |
443 | { |
444 | stateChanged(newstate, reverse: KXMLGUIClient::StateNoReverse); |
445 | } |
446 | |
447 | void KXmlGuiWindow::slotStateChanged(const QString &newstate, bool reverse) |
448 | { |
449 | stateChanged(newstate, reverse: reverse ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse); |
450 | } |
451 | |
452 | void KXmlGuiWindow::setStandardToolBarMenuEnabled(bool ) |
453 | { |
454 | Q_D(KXmlGuiWindow); |
455 | if (showToolBarMenu) { |
456 | if (d->toolBarHandler) { |
457 | return; |
458 | } |
459 | |
460 | d->toolBarHandler = new KDEPrivate::ToolBarHandler(this); |
461 | |
462 | if (factory()) { |
463 | factory()->addClient(client: d->toolBarHandler); |
464 | } |
465 | } else { |
466 | if (!d->toolBarHandler) { |
467 | return; |
468 | } |
469 | |
470 | if (factory()) { |
471 | factory()->removeClient(client: d->toolBarHandler); |
472 | } |
473 | |
474 | delete d->toolBarHandler; |
475 | d->toolBarHandler = nullptr; |
476 | } |
477 | } |
478 | |
479 | bool KXmlGuiWindow::isStandardToolBarMenuEnabled() const |
480 | { |
481 | Q_D(const KXmlGuiWindow); |
482 | return (d->toolBarHandler); |
483 | } |
484 | |
485 | void KXmlGuiWindow::createStandardStatusBarAction() |
486 | { |
487 | Q_D(KXmlGuiWindow); |
488 | if (!d->showStatusBarAction) { |
489 | d->showStatusBarAction = KStandardAction::showStatusbar(recvr: this, slot: &KMainWindow::setSettingsDirty, parent: actionCollection()); |
490 | QStatusBar *sb = statusBar(); // Creates statusbar if it doesn't exist already. |
491 | connect(sender: d->showStatusBarAction, signal: &QAction::toggled, context: sb, slot: &QWidget::setVisible); |
492 | d->showStatusBarAction->setChecked(sb->isHidden()); |
493 | } else { |
494 | // If the language has changed, we'll need to grab the new text and whatsThis |
495 | QAction *tmpStatusBar = KStandardAction::showStatusbar(recvr: nullptr, slot: nullptr, parent: nullptr); |
496 | d->showStatusBarAction->setText(tmpStatusBar->text()); |
497 | d->showStatusBarAction->setWhatsThis(tmpStatusBar->whatsThis()); |
498 | delete tmpStatusBar; |
499 | } |
500 | } |
501 | |
502 | void KXmlGuiWindow::finalizeGUI(bool /*force*/) |
503 | { |
504 | // FIXME: this really needs to be removed with a code more like the one we had on KDE3. |
505 | // what we need to do here is to position correctly toolbars so they don't overlap. |
506 | // Also, take in count plugins could provide their own toolbars and those also need to |
507 | // be restored. |
508 | if (autoSaveSettings() && autoSaveConfigGroup().isValid()) { |
509 | applyMainWindowSettings(config: autoSaveConfigGroup()); |
510 | } |
511 | } |
512 | |
513 | void KXmlGuiWindow::applyMainWindowSettings(const KConfigGroup &config) |
514 | { |
515 | Q_D(KXmlGuiWindow); |
516 | KMainWindow::applyMainWindowSettings(config); |
517 | QStatusBar *sb = findChild<QStatusBar *>(); |
518 | if (sb && d->showStatusBarAction) { |
519 | d->showStatusBarAction->setChecked(!sb->isHidden()); |
520 | } |
521 | } |
522 | |
523 | void KXmlGuiWindow::checkAmbiguousShortcuts() |
524 | { |
525 | QMap<QString, QAction *> shortcuts; |
526 | QAction *editCutAction = actionCollection()->action(QStringLiteral("edit_cut" )); |
527 | QAction *deleteFileAction = actionCollection()->action(QStringLiteral("deletefile" )); |
528 | const auto actions = actionCollection()->actions(); |
529 | for (QAction *action : actions) { |
530 | if (action->isEnabled()) { |
531 | const auto actionShortcuts = action->shortcuts(); |
532 | for (const QKeySequence &shortcut : actionShortcuts) { |
533 | if (shortcut.isEmpty()) { |
534 | continue; |
535 | } |
536 | const QString portableShortcutText = shortcut.toString(); |
537 | const QAction *existingShortcutAction = shortcuts.value(key: portableShortcutText); |
538 | if (existingShortcutAction) { |
539 | // If the shortcut is already in use we give a warning, so that hopefully the developer will find it |
540 | // There is one exception, if the conflicting shortcut is a non primary shortcut of "edit_cut" |
541 | // and "deleteFileAction" is the other action since Shift+Delete is used for both in our default code |
542 | bool showWarning = true; |
543 | if ((action == editCutAction && existingShortcutAction == deleteFileAction) |
544 | || (action == deleteFileAction && existingShortcutAction == editCutAction)) { |
545 | QList<QKeySequence> editCutActionShortcuts = editCutAction->shortcuts(); |
546 | if (editCutActionShortcuts.indexOf(t: shortcut) > 0) // alternate shortcut |
547 | { |
548 | editCutActionShortcuts.removeAll(t: shortcut); |
549 | editCutAction->setShortcuts(editCutActionShortcuts); |
550 | |
551 | showWarning = false; |
552 | } |
553 | } |
554 | |
555 | if (showWarning) { |
556 | const QString actionName = KLocalizedString::removeAcceleratorMarker(label: action->text()); |
557 | const QString existingShortcutActionName = KLocalizedString::removeAcceleratorMarker(label: existingShortcutAction->text()); |
558 | QString dontShowAgainString = existingShortcutActionName + actionName + shortcut.toString(); |
559 | dontShowAgainString.remove(c: QLatin1Char('\\')); |
560 | KMessageBox::information(parent: this, |
561 | i18n("There are two actions (%1, %2) that want to use the same shortcut (%3). This is most probably a bug. " |
562 | "Please report it in <a href='https://bugs.kde.org'>bugs.kde.org</a>" , |
563 | existingShortcutActionName, |
564 | actionName, |
565 | shortcut.toString(QKeySequence::NativeText)), |
566 | i18n("Ambiguous Shortcuts" ), |
567 | dontShowAgainName: dontShowAgainString, |
568 | options: KMessageBox::Notify | KMessageBox::AllowLink); |
569 | } |
570 | } else { |
571 | shortcuts.insert(key: portableShortcutText, value: action); |
572 | } |
573 | } |
574 | } |
575 | } |
576 | } |
577 | |
578 | void KXmlGuiWindow::setCommandBarEnabled(bool showCommandBar) |
579 | { |
580 | /* |
581 | * Unset the shortcut |
582 | */ |
583 | auto cmdBarAction = actionCollection()->action(QStringLiteral("open_kcommand_bar" )); |
584 | if (showCommandBar) { |
585 | KActionCollection::setDefaultShortcut(action: cmdBarAction, shortcut: Qt::CTRL | Qt::ALT | Qt::Key_I); |
586 | } else { |
587 | KActionCollection::setDefaultShortcut(action: cmdBarAction, shortcut: {}); |
588 | } |
589 | |
590 | Q_D(KXmlGuiWindow); |
591 | d->commandBarEnabled = showCommandBar; |
592 | } |
593 | |
594 | bool KXmlGuiWindow::isCommandBarEnabled() const |
595 | { |
596 | Q_D(const KXmlGuiWindow); |
597 | return d->commandBarEnabled; |
598 | } |
599 | |
600 | #include "moc_kxmlguiwindow.cpp" |
601 | |