KXmlGui

kmainwindow.cpp
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 SPDX-FileCopyrightText: 2000-2008 David Faure <faure@kde.org>
11
12 SPDX-License-Identifier: LGPL-2.0-only
13*/
14
15#include "kmainwindow.h"
16
17#include "kmainwindow_p.h"
18#ifdef WITH_QTDBUS
19#include "kmainwindowiface_p.h"
20#endif
21#include "khelpmenu.h"
22#include "ktoolbar.h"
23#include "ktoolbarhandler_p.h"
24#include "ktooltiphelper.h"
25
26#include <QApplication>
27#include <QCloseEvent>
28#include <QDockWidget>
29#include <QFile>
30#include <QList>
31#include <QMenuBar>
32#include <QObject>
33#ifndef QT_NO_SESSIONMANAGER
34#include <QSessionManager>
35#endif
36#include <QStatusBar>
37#include <QStyle>
38#include <QTimer>
39#include <QWidget>
40#include <QWindow>
41#ifdef WITH_QTDBUS
42#include <QDBusConnection>
43#endif
44
45#include <KAboutData>
46#include <KConfig>
47#include <KConfigGroup>
48#include <KConfigGui>
49#include <KLocalizedString>
50#include <KSharedConfig>
51#include <KStandardShortcut>
52#include <KWindowConfig>
53
54static QMenuBar *internalMenuBar(KMainWindow *mw)
55{
57}
58
59static QStatusBar *internalStatusBar(KMainWindow *mw)
60{
62}
63
64/**
65
66 * Listens to resize events from QDockWidgets. The KMainWindow
67 * settings are set as dirty, as soon as at least one resize
68 * event occurred. The listener is attached to the dock widgets
69 * by dock->installEventFilter(dockResizeListener) inside
70 * KMainWindow::event().
71 */
72class DockResizeListener : public QObject
73{
75public:
76 DockResizeListener(KMainWindow *win);
77 ~DockResizeListener() override;
78 bool eventFilter(QObject *watched, QEvent *event) override;
79
80private:
81 KMainWindow *const m_win;
82};
83
84DockResizeListener::DockResizeListener(KMainWindow *win)
85 : QObject(win)
86 , m_win(win)
87{
88}
89
90DockResizeListener::~DockResizeListener()
91{
92}
93
94bool DockResizeListener::eventFilter(QObject *watched, QEvent *event)
95{
96 switch (event->type()) {
97 case QEvent::Resize:
98 case QEvent::Move:
99 case QEvent::Show:
100 case QEvent::Hide:
101 m_win->d_ptr->setSettingsDirty(KMainWindowPrivate::CompressCalls);
102 break;
103
104 default:
105 break;
106 }
107
109}
110
111KMWSessionManager::KMWSessionManager()
112{
113#ifndef QT_NO_SESSIONMANAGER
114 connect(qApp, &QGuiApplication::saveStateRequest, this, &KMWSessionManager::saveState);
115 connect(qApp, &QGuiApplication::commitDataRequest, this, &KMWSessionManager::commitData);
116#endif
117}
118
119KMWSessionManager::~KMWSessionManager()
120{
121}
122
123void KMWSessionManager::saveState(QSessionManager &sm)
124{
125#ifndef QT_NO_SESSIONMANAGER
127
129 const auto windows = KMainWindow::memberList();
130 if (!windows.isEmpty()) {
131 // According to Jochen Wilhelmy <digisnap@cs.tu-berlin.de>, this
132 // hook is useful for better document orientation
133 windows.at(0)->saveGlobalProperties(config);
134 }
135
136 int n = 0;
137 for (KMainWindow *mw : windows) {
138 n++;
139 mw->savePropertiesInternal(config, n);
140 }
141
142 KConfigGroup group(config, QStringLiteral("Number"));
143 group.writeEntry("NumberOfWindows", n);
144
145 // store new status to disk
146 config->sync();
147
148 // generate discard command for new file
150 if (QFile::exists(localFilePath)) {
152 discard << QStringLiteral("rm");
153 discard << localFilePath;
154 sm.setDiscardCommand(discard);
155 }
156#else
157 Q_UNUSED(sm)
158#endif // QT_NO_SESSIONMANAGER
159}
160
161void KMWSessionManager::commitData(QSessionManager &sm)
162{
163#ifndef QT_NO_SESSIONMANAGER
164 if (!sm.allowsInteraction()) {
165 return;
166 }
167
168 /*
169 Purpose of this exercise: invoke queryClose() without actually closing the
170 windows, because
171 - queryClose() may contain session management code, so it must be invoked
172 - actually closing windows may quit the application - cf.
173 QGuiApplication::quitOnLastWindowClosed()
174 - quitting the application and thus closing the session manager connection
175 violates the X11 XSMP protocol.
176 The exact requirement of XSMP that would be broken is,
177 in the description of the client's state machine:
178
179 save-yourself-done: (changing state is forbidden)
180
181 Closing the session manager connection causes a state change.
182 Worst of all, that is a real problem with ksmserver - it will not save
183 applications that quit on their own in state save-yourself-done.
184 */
185 const auto windows = KMainWindow::memberList();
186 for (KMainWindow *window : windows) {
188 continue;
189 }
190 QCloseEvent e;
191 QApplication::sendEvent(window, &e);
192 if (!e.isAccepted()) {
193 sm.cancel();
194 return;
195 }
196 }
197#else
198 Q_UNUSED(sm)
199#endif // QT_NO_SESSIONMANAGER
200}
201
202#ifndef QT_NO_SESSIONMANAGER
203Q_GLOBAL_STATIC(KMWSessionManager, ksm)
204#endif
205Q_GLOBAL_STATIC(QList<KMainWindow *>, sMemberList)
206
207KMainWindow::KMainWindow(QWidget *parent, Qt::WindowFlags flags)
208 : QMainWindow(parent, flags)
209 , d_ptr(new KMainWindowPrivate)
210{
212
213 d->init(this);
214}
215
216KMainWindow::KMainWindow(KMainWindowPrivate &dd, QWidget *parent, Qt::WindowFlags f)
217 : QMainWindow(parent, f)
218 , d_ptr(&dd)
219{
221
222 d->init(this);
223}
224
225void KMainWindowPrivate::init(KMainWindow *_q)
226{
227 q = _q;
228
229 q->setAnimated(q->style()->styleHint(QStyle::SH_Widget_Animate, nullptr, q));
230
231 q->setAttribute(Qt::WA_DeleteOnClose);
232
233 helpMenu = nullptr;
234
235 // actionCollection()->setWidget( this );
236#if 0
237 QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
238 q, SLOT(_k_slotSettingsChanged(int)));
239#endif
240
241#ifndef QT_NO_SESSIONMANAGER
242 // force KMWSessionManager creation
243 ksm();
244#endif
245
246 sMemberList()->append(q);
247
248 // If application is translated, load translator information for use in
249 // KAboutApplicationDialog or other getters. The context and messages below
250 // both must be exactly as listed, and are forced to be loaded from the
251 // application's own message catalog instead of kxmlgui's.
253 if (aboutData.translators().isEmpty()) {
254 aboutData.setTranslator(i18ndc(nullptr, "NAME OF TRANSLATORS", "Your names"), //
255 i18ndc(nullptr, "EMAIL OF TRANSLATORS", "Your emails"));
256
258 }
259
260 settingsDirty = false;
261 autoSaveSettings = false;
262 autoSaveWindowSize = true; // for compatibility
263 // d->kaccel = actionCollection()->kaccel();
264 settingsTimer = nullptr;
265 sizeTimer = nullptr;
266
267 dockResizeListener = new DockResizeListener(_q);
268 letDirtySettings = true;
269
270 sizeApplied = false;
271 suppressCloseEvent = false;
272
273 qApp->installEventFilter(KToolTipHelper::instance());
274}
275
276static bool endsWithHashNumber(const QString &s)
277{
278 for (int i = s.length() - 1; i > 0; --i) {
279 if (s[i] == QLatin1Char('#') && i != s.length() - 1) {
280 return true; // ok
281 }
282 if (!s[i].isDigit()) {
283 break;
284 }
285 }
286 return false;
287}
288
289static inline bool isValidDBusObjectPathCharacter(const QChar &c)
290{
291 ushort u = c.unicode();
292 /* clang-format off */
293 return (u >= QLatin1Char('a') && u <= QLatin1Char('z'))
294 || (u >= QLatin1Char('A') && u <= QLatin1Char('Z'))
295 || (u >= QLatin1Char('0') && u <= QLatin1Char('9'))
296 || (u == QLatin1Char('_')) || (u == QLatin1Char('/'));
297 /* clang-format off */
298}
299
300void KMainWindowPrivate::polish(KMainWindow *q)
301{
302 // Set a unique object name. Required by session management, window management, and for the dbus interface.
303 QString objname;
304 QString s;
305 int unusedNumber = 1;
306 const QString name = q->objectName();
307 bool startNumberingImmediately = true;
308 bool tryReuse = false;
309 if (name.isEmpty()) {
310 // no name given
311 objname = QStringLiteral("MainWindow#");
312 } else if (name.endsWith(QLatin1Char('#'))) {
313 // trailing # - always add a number - KWin uses this for better grouping
314 objname = name;
315 } else if (endsWithHashNumber(name)) {
316 // trailing # with a number - like above, try to use the given number first
317 objname = name;
318 tryReuse = true;
319 startNumberingImmediately = false;
320 } else {
321 objname = name;
322 startNumberingImmediately = false;
323 }
324
325 s = objname;
326 if (startNumberingImmediately) {
327 s += QLatin1Char('1');
328 }
329
330 for (;;) {
331 const QList<QWidget *> list = qApp->topLevelWidgets();
332 bool found = false;
333 for (QWidget *w : list) {
334 if (w != q && w->objectName() == s) {
335 found = true;
336 break;
337 }
338 }
339 if (!found) {
340 break;
341 }
342 if (tryReuse) {
343 objname = name.left(name.length() - 1); // lose the hash
344 unusedNumber = 0; // start from 1 below
345 tryReuse = false;
346 }
347 s.setNum(++unusedNumber);
348 s = objname + s;
349 }
350 q->setObjectName(s);
351 if (!q->window() || q->window() == q) {
352 q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
353 q->setWindowRole(s); // will keep insisting that object name suddenly should not be used for window role
354 }
355
357 dbusName += q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
358 // Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
359 for (QChar &c : dbusName) {
360 if (!isValidDBusObjectPathCharacter(c)) {
361 c = QLatin1Char('_');
362 }
363 }
364
365#ifdef WITH_QTDBUS
366 /* clang-format off */
367 constexpr auto opts = QDBusConnection::ExportScriptableSlots
372 /* clang-format on */
373 QDBusConnection::sessionBus().registerObject(dbusName, q, opts);
374#endif
375}
376
377void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
378{
379 if (!letDirtySettings) {
380 return;
381 }
382
383 settingsDirty = true;
384 if (autoSaveSettings) {
385 if (callCompression == CompressCalls) {
386 if (!settingsTimer) {
387 settingsTimer = new QTimer(q);
388 settingsTimer->setInterval(500);
389 settingsTimer->setSingleShot(true);
391 }
392 settingsTimer->start();
393 } else {
395 }
396 }
397}
398
399void KMainWindowPrivate::setSizeDirty()
400{
401 if (autoSaveWindowSize) {
402 if (!sizeTimer) {
403 sizeTimer = new QTimer(q);
404 sizeTimer->setInterval(500);
405 sizeTimer->setSingleShot(true);
406 QObject::connect(sizeTimer, &QTimer::timeout, q, [this]() {
407 _k_slotSaveAutoSaveSize();
408 });
409 }
410 sizeTimer->start();
411 }
412}
413
415{
416 sMemberList()->removeAll(this);
417 delete static_cast<QObject *>(d_ptr->dockResizeListener); // so we don't get anymore events after d_ptr is destroyed
418}
419
420bool KMainWindow::canBeRestored(int numberOfInstances)
421{
423 if (!config) {
424 return false;
425 }
426
427 KConfigGroup group(config, QStringLiteral("Number"));
428 // TODO KF6: we should use 0 as the default value, not 1
429 // See also https://bugs.kde.org/show_bug.cgi?id=427552
430 const int n = group.readEntry("NumberOfWindows", 1);
431 return numberOfInstances >= 1 && numberOfInstances <= n;
432}
433
435{
437 if (!config) {
438 return QString();
439 }
440
441 KConfigGroup group(config, QStringLiteral("WindowProperties%1").arg(instanceNumber));
442 if (!group.hasKey("ClassName")) {
443 return QString();
444 } else {
445 return group.readEntry("ClassName");
446 }
447}
448
449bool KMainWindow::restore(int numberOfInstances, bool show)
450{
452 return false;
453 }
455 if (readPropertiesInternal(config, numberOfInstances)) {
456 if (show) {
458 }
459 return false;
460 }
461 return false;
462}
463
465{
466 setPlainCaption(caption);
467}
468
469void KMainWindow::setCaption(const QString &caption, bool modified)
470{
471 QString title = caption;
472 if (!title.contains(QLatin1String("[*]")) && !title.isEmpty()) { // append the placeholder so that the modified mechanism works
473 title.append(QLatin1String(" [*]"));
474 }
475 setPlainCaption(title);
476 setWindowModified(modified);
477}
478
480{
481 setWindowTitle(caption);
482}
483
485{
487 if (!d->helpMenu) {
488 d->helpMenu = new KHelpMenu(this);
489 if (!d->helpMenu) {
490 return;
491 }
492 }
493 d->helpMenu->appHelpActivated();
494}
495
497{
499 if (d->suppressCloseEvent) {
500 e->accept();
501 return;
502 }
503
504 // Save settings if auto-save is enabled, and settings have changed
505 if (d->settingsTimer && d->settingsTimer->isActive()) {
506 d->settingsTimer->stop();
508 }
509 if (d->sizeTimer && d->sizeTimer->isActive()) {
510 d->sizeTimer->stop();
511 d->_k_slotSaveAutoSaveSize();
512 }
513 // Delete the marker that says we don't want to restore the position of the
514 // next-opened instance; now that a window is closing, we do want to do this
515 if (d->autoSaveGroup.isValid()) {
516 d->getStateConfig().deleteEntry("RestorePositionForNextInstance");
517 }
518 d->_k_slotSaveAutoSavePosition();
519
520 if (queryClose()) {
521 // widgets will start destroying themselves at this point and we don't
522 // want to save state anymore after this as it might be incorrect
523 d->autoSaveSettings = false;
524 d->letDirtySettings = false;
525 e->accept();
526 } else {
527 e->ignore(); // if the window should not be closed, don't close it
528 }
529
530#ifndef QT_NO_SESSIONMANAGER
531 // If saving session, we are processing a fake close event, and might get the real one later.
532 if (e->isAccepted() && qApp->isSavingSession()) {
533 d->suppressCloseEvent = true;
534 }
535#endif
536}
537
539{
540 return true;
541}
542
546
550
551void KMainWindow::savePropertiesInternal(KConfig *config, int number)
552{
554 const bool oldASWS = d->autoSaveWindowSize;
555 d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
556
557 KConfigGroup cg(config, QStringLiteral("WindowProperties%1").arg(number));
558
559 // store objectName, className, Width and Height for later restoring
560 // (Only useful for session management)
561 cg.writeEntry("ObjectName", objectName());
562 cg.writeEntry("ClassName", metaObject()->className());
563
564 saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
565
566 cg = KConfigGroup(config, QString::number(number));
568
569 d->autoSaveWindowSize = oldASWS;
570}
571
573{
575 // qDebug(200) << "KMainWindow::saveMainWindowSettings " << cg.name();
576
577 // Called by session management - or if we want to save the window size anyway
578 if (d->autoSaveWindowSize) {
579 KWindowConfig::saveWindowSize(windowHandle(), d->getStateConfig());
580 KWindowConfig::saveWindowPosition(windowHandle(), d->getStateConfig());
581 }
582
583 // One day will need to save the version number, but for now, assume 0
584 // Utilise the QMainWindow::saveState() functionality.
585 const QByteArray state = saveState();
586 d->getStateConfig().writeEntry("State", state.toBase64());
587
588 QStatusBar *sb = internalStatusBar(this);
589 if (sb) {
590 if (!cg.hasDefault("StatusBar") && !sb->isHidden()) {
591 cg.revertToDefault("StatusBar");
592 } else {
593 cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
594 }
595 }
596
597 QMenuBar *mb = internalMenuBar(this);
598
599 if (mb && !mb->isNativeMenuBar()) {
600 if (!cg.hasDefault("MenuBar") && !mb->isHidden()) {
601 cg.revertToDefault("MenuBar");
602 } else {
603 cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
604 }
605 }
606
607 if (!autoSaveSettings() || cg.name() == autoSaveGroup()) {
608 // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
609 if (!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked()) {
610 cg.revertToDefault("ToolBarsMovable");
611 } else {
612 cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
613 }
614 }
615
616 int n = 1; // Toolbar counter. toolbars are counted from 1,
617 const auto toolBars = this->toolBars();
618 for (KToolBar *toolbar : toolBars) {
619 // Give a number to the toolbar, but prefer a name if there is one,
620 // because there's no real guarantee on the ordering of toolbars
621 const QString groupName = toolbar->objectName().isEmpty() ? QStringLiteral("Toolbar%1").arg(n) : (QStringLiteral("Toolbar ") + toolbar->objectName());
622
623 KConfigGroup toolbarGroup(&cg, groupName);
624 toolbar->saveSettings(toolbarGroup);
625 n++;
626 }
627}
628
629bool KMainWindow::readPropertiesInternal(KConfig *config, int number)
630{
632
633 const bool oldLetDirtySettings = d->letDirtySettings;
634 d->letDirtySettings = false;
635
636 if (number == 1) {
637 readGlobalProperties(config);
638 }
639
640 // in order they are in toolbar list
641 KConfigGroup cg(config, QStringLiteral("WindowProperties%1").arg(number));
642
643 // restore the object name (window role)
644 if (cg.hasKey("ObjectName")) {
645 setObjectName(cg.readEntry("ObjectName"));
646 }
647
648 d->sizeApplied = false; // since we are changing config file, reload the size of the window
649 // if necessary. Do it before the call to applyMainWindowSettings.
650 applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
651
652 KConfigGroup grp(config, QString::number(number));
654
655 d->letDirtySettings = oldLetDirtySettings;
656
657 return true;
658}
659
661{
663 // qDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
664
666 d->migrateStateDataIfNeeded(cg);
667
669
670 const bool oldLetDirtySettings = d->letDirtySettings;
671 d->letDirtySettings = false;
672
673 KConfigGroup stateConfig = d->getStateConfig();
674
675 if (!d->sizeApplied && (!window() || window() == this)) {
676 winId(); // ensure there's a window created
677 // Set the window's size from the existing widget geometry to respect the
678 // implicit size when there is no saved geometry in the config file for
679 // KWindowConfig::restoreWindowSize() to restore
680 // TODO: remove once QTBUG-40584 is fixed; see below
684 // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
685 // window was created -> QTBUG-40584. We therefore copy the size here.
686 // TODO: remove once this was resolved in QWidget QPA
688 d->sizeApplied = true;
689
690 // Let the user opt out of KDE apps remembering window sizes if they
691 // find it annoying or it doesn't work for them due to other bugs.
693 KConfigGroup group(config, QStringLiteral("General"));
694 if (group.readEntry("AllowKDEAppsToRememberWindowPositions", true)) {
695 if (stateConfig.readEntry("RestorePositionForNextInstance", true)) {
697 // Save the fact that we now don't want to restore position
698 // anymore; if we did, the next instance would completely cover
699 // the existing one
700 stateConfig.writeEntry("RestorePositionForNextInstance", false);
701 }
702 }
703 }
704
705 QStatusBar *sb = internalStatusBar(this);
706 if (sb) {
707 QString entry = cg.readEntry("StatusBar", "Enabled");
708 sb->setVisible(entry != QLatin1String("Disabled"));
709 }
710
711 QMenuBar *mb = internalMenuBar(this);
712 if (mb && !mb->isNativeMenuBar()) {
713 QString entry = cg.readEntry("MenuBar", "Enabled");
714 mb->setVisible(entry != QLatin1String("Disabled"));
715 }
716
717 if (!autoSaveSettings() || cg.name() == autoSaveGroup()) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
718 QString entry = cg.readEntry("ToolBarsMovable", "Disabled");
719 KToolBar::setToolBarsLocked(entry == QLatin1String("Disabled"));
720 }
721
722 int n = 1; // Toolbar counter. toolbars are counted from 1,
723 const auto toolBars = this->toolBars();
724 for (KToolBar *toolbar : toolBars) {
725 // Give a number to the toolbar, but prefer a name if there is one,
726 // because there's no real guarantee on the ordering of toolbars
727 const QString groupName = toolbar->objectName().isEmpty() ? QStringLiteral("Toolbar%1").arg(n) : (QStringLiteral("Toolbar ") + toolbar->objectName());
728
729 KConfigGroup toolbarGroup(&cg, groupName);
730 toolbar->applySettings(toolbarGroup);
731 n++;
732 }
733
734 if (stateConfig.hasKey("State")) {
735 QByteArray state;
736 state = stateConfig.readEntry("State", state);
737 state = QByteArray::fromBase64(state);
738 // One day will need to load the version number, but for now, assume 0
739 restoreState(state);
740 }
741
742 if (focusedWidget) {
743 focusedWidget->setFocus();
744 }
745
746 d->settingsDirty = false;
747 d->letDirtySettings = oldLetDirtySettings;
748}
749
751{
753 d->setSettingsDirty();
754}
755
757{
758 Q_D(const KMainWindow);
759 return d->settingsDirty;
760}
761
762void KMainWindow::setAutoSaveSettings(const QString &groupName, bool saveWindowSize)
763{
764 setAutoSaveSettings(KConfigGroup(KSharedConfig::openConfig(), groupName), saveWindowSize);
765}
766
767void KMainWindow::setAutoSaveSettings(const KConfigGroup &group, bool saveWindowSize)
768{
769 // We re making a little assumption that if you want to save the window
770 // size, you probably also want to save the window position too
771 // This avoids having to re-implement a new version of
772 // KMainWindow::setAutoSaveSettings that handles these cases independently
774 d->autoSaveSettings = true;
775 d->autoSaveGroup = group;
776 d->autoSaveWindowSize = saveWindowSize;
777
778 if (!saveWindowSize && d->sizeTimer) {
779 d->sizeTimer->stop();
780 }
781
782 // Now read the previously saved settings
783 applyMainWindowSettings(d->autoSaveGroup);
784}
785
787{
789 d->autoSaveSettings = false;
790 if (d->settingsTimer) {
791 d->settingsTimer->stop();
792 }
793}
794
795bool KMainWindow::autoSaveSettings() const
796{
797 Q_D(const KMainWindow);
798 return d->autoSaveSettings;
799}
800
801QString KMainWindow::autoSaveGroup() const
802{
803 Q_D(const KMainWindow);
804 return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
805}
806
808{
809 Q_D(const KMainWindow);
810 return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
811}
812
814{
816 d->m_stateConfigGroup = KSharedConfig::openStateConfig()->group(configGroup);
817}
818
820{
821 Q_D(const KMainWindow);
822 return d->getStateConfig();
823}
824
826{
828 Q_ASSERT(d->autoSaveSettings);
829 // qDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
830 saveMainWindowSettings(d->autoSaveGroup);
831 d->autoSaveGroup.sync();
832 d->m_stateConfigGroup.sync();
833 d->settingsDirty = false;
834}
835
837{
839 switch (ev->type()) {
840#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
841 case QEvent::Move:
842#endif
843 case QEvent::Resize:
844 d->setSizeDirty();
845 break;
846 case QEvent::Polish:
847 d->polish(this);
848 break;
850 QChildEvent *event = static_cast<QChildEvent *>(ev);
852 KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
854 if (dock) {
857
858 // there is no signal emitted if the size of the dock changes,
859 // hence install an event filter instead
860 dock->installEventFilter(d->dockResizeListener);
861 } else if (toolbar) {
862 // there is no signal emitted if the size of the toolbar changes,
863 // hence install an event filter instead
864 toolbar->installEventFilter(d->dockResizeListener);
865 } else if (menubar) {
866 // there is no signal emitted if the size of the menubar changes,
867 // hence install an event filter instead
868 menubar->installEventFilter(d->dockResizeListener);
869 }
870 break;
871 }
873 QChildEvent *event = static_cast<QChildEvent *>(ev);
875 KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
877 if (dock) {
880 dock->removeEventFilter(d->dockResizeListener);
881 } else if (toolbar) {
882 toolbar->removeEventFilter(d->dockResizeListener);
883 } else if (menubar) {
884 menubar->removeEventFilter(d->dockResizeListener);
885 }
886 break;
887 }
888 default:
889 break;
890 }
891 return QMainWindow::event(ev);
892}
893
895{
896 if (KStandardShortcut::openContextMenu().contains(QKeySequence(keyEvent->key() | keyEvent->modifiers()))) {
897 if (QWidget *widgetWithKeyboardFocus = qApp->focusWidget()) {
898 const QPoint centerOfWidget(widgetWithKeyboardFocus->width() / 2, widgetWithKeyboardFocus->height() / 2);
899 qApp->postEvent(widgetWithKeyboardFocus,
901 return;
902 }
903 if (qApp->focusObject()) {
904 qApp->postEvent(qApp->focusObject(), new QContextMenuEvent(QContextMenuEvent::Keyboard, mapFromGlobal(QCursor::pos()), QCursor::pos()));
905 return;
906 }
907 }
909}
910
911bool KMainWindow::hasMenuBar()
912{
913 return internalMenuBar(this);
914}
915
916void KMainWindowPrivate::_k_slotSettingsChanged(int category)
917{
918 Q_UNUSED(category);
919
920 // This slot will be called when the style KCM changes settings that need
921 // to be set on the already running applications.
922
923 // At this level (KMainWindow) the only thing we need to restore is the
924 // animations setting (whether the user wants builtin animations or not).
925
927}
928
929void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
930{
931 if (autoSaveGroup.isValid()) {
932 KWindowConfig::saveWindowSize(q->windowHandle(), getStateConfig());
933 }
934}
935
936void KMainWindowPrivate::_k_slotSaveAutoSavePosition()
937{
938 if (autoSaveGroup.isValid()) {
939 KWindowConfig::saveWindowPosition(q->windowHandle(), getStateConfig());
940 }
941}
942
944{
945 QString childName = name;
946 if (childName.isEmpty()) {
947 childName = QStringLiteral("mainToolBar");
948 }
949
951 if (tb) {
952 return tb;
953 }
954
955 KToolBar *toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
956 return toolbar;
957}
958
960{
962
963 const auto theChildren = children();
964 for (QObject *child : theChildren) {
967 }
968 }
969
970 return ret;
971}
972
977
979{
980 Q_D(const KMainWindow);
981
982 return d->dbusName;
983}
984
985#include "kmainwindow.moc"
986#include "moc_kmainwindow.cpp"
987#include "moc_kmainwindow_p.cpp"
static void setApplicationData(const KAboutData &aboutData)
static KAboutData applicationData()
bool hasKey(const char *key) const
QString readEntry(const char *key, const char *aDefault=nullptr) const
bool sync() override
QString name() const
Standard KDE help menu with dialog boxes.
Definition khelpmenu.h:109
KMainWindow represents a top-level main window.
Definition kmainwindow.h:60
void appHelpActivated()
Opens the help page for the application.
virtual void applyMainWindowSettings(const KConfigGroup &config)
Read settings for statusbar, menubar and toolbar from their respective groups in the config file and ...
KConfigGroup stateConfigGroup() const
bool restore(int numberOfInstances, bool show=true)
Attempt to restore the top-level widget as defined by numberOfInstances (1..X).
KToolBar * toolBar(const QString &name=QString())
This is useful to both call specific toolbars that have been created or to generate a default one upo...
virtual void readGlobalProperties(KConfig *sessionConfig)
Reads your application-wide properties.
bool event(QEvent *event) override
Reimplemented to catch QEvent::Polish in order to adjust the object name if needed,...
void saveAutoSaveSettings()
This slot should only be called in case you reimplement closeEvent() and if you are using the autosav...
void setAutoSaveSettings(const QString &groupName=QStringLiteral("MainWindow"), bool saveWindowSize=true)
This enables autosave of toolbar/menubar/statusbar settings (and optionally window size).
void closeEvent(QCloseEvent *) override
Reimplemented to autosave settings and call queryClose().
virtual void saveProperties(KConfigGroup &)
Saves your instance-specific properties.
void resetAutoSaveSettings()
Disables the autosave settings feature.
void setSettingsDirty()
Tell the main window that it should save its settings when being closed.
KConfigGroup autoSaveConfigGroup() const
QList< KToolBar * > toolBars() const
void saveMainWindowSettings(KConfigGroup &config)
Manually save the settings for statusbar, menubar and toolbar to their respective groups in the KConf...
static const QString classNameOfToplevel(int instanceNumber)
Useful if your application uses different kinds of top-level windows.
virtual void setCaption(const QString &caption)
Assigns a KDE compliant caption (window title).
static QList< KMainWindow * > memberList()
~KMainWindow() override
Destructor.
virtual void setPlainCaption(const QString &caption)
Make a plain caption without any modifications.
void setStateConfigGroup(const QString &configGroup)
Assigns the config group name for the KConfigGroup returned by stateConfigGroup.
KMainWindow(QWidget *parent=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())
Constructs a main window.
virtual void readProperties(const KConfigGroup &)
Reads your instance-specific properties.
virtual void saveGlobalProperties(KConfig *sessionConfig)
Saves your application-wide properties.
bool settingsDirty() const
For inherited classes.
static bool canBeRestored(int numberOfInstances)
void keyPressEvent(QKeyEvent *keyEvent) override
Reimplemented to open context menus on Shift+F10.
QString dbusName() const
virtual bool queryClose()
This function is called before the window is closed, either by the user or indirectly by the session ...
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
Floatable toolbar with auto resize.
Definition ktoolbar.h:68
static bool toolBarsLocked()
Returns whether the toolbars are locked (i.e., moving of the toobars disallowed).
static void setToolBarsLocked(bool locked)
Allows you to lock and unlock all toolbars (i.e., disallow/allow moving of the toobars).
QString i18ndc(const char *domain, const char *context, const char *text, const TYPE &arg...)
KCONFIGGUI_EXPORT void setSessionConfig(const QString &id, const QString &key)
KCONFIGGUI_EXPORT KConfig * sessionConfig()
QWidget * window(QObject *job)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
KGuiItem discard()
const QList< QKeySequence > & openContextMenu()
KCONFIGGUI_EXPORT void saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
KCONFIGGUI_EXPORT void saveWindowPosition(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
KCONFIGGUI_EXPORT void restoreWindowSize(QWindow *window, const KConfigGroup &config)
KCONFIGGUI_EXPORT void restoreWindowPosition(QWindow *window, const KConfigGroup &config)
QWidget * focusWidget()
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
QByteArray toBase64(Base64Options options) const const
char16_t & unicode()
bool sendEvent(QObject *receiver, QEvent *event)
QPoint pos()
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
void dockLocationChanged(Qt::DockWidgetArea area)
void topLevelChanged(bool topLevel)
void accept()
bool isAccepted() const const
void ignore()
bool exists() const const
void commitDataRequest(QSessionManager &manager)
void saveStateRequest(QSessionManager &manager)
void append(QList< T > &&value)
bool isEmpty() const const
qsizetype removeAll(const AT &t)
void setAnimated(bool enabled)
virtual bool event(QEvent *event) override
bool restoreState(const QByteArray &state, int version)
QByteArray saveState(int version) const const
Q_OBJECTQ_OBJECT
const QObjectList & children() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
virtual bool event(QEvent *e)
virtual bool eventFilter(QObject *watched, QEvent *event)
T findChild(const QString &name, Qt::FindChildOptions options) const const
QList< T > findChildren(Qt::FindChildOptions options) const const
void installEventFilter(QObject *filterObj)
virtual const QMetaObject * metaObject() const const
void removeEventFilter(QObject *obj)
void setObjectName(QAnyStringView name)
bool allowsInteraction()
QString sessionId() const const
QString sessionKey() const const
void setDiscardCommand(const QStringList &command)
QString writableLocation(StandardLocation type)
QString & append(QChar ch)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & setNum(double n, char format, int precision)
SH_Widget_Animate
virtual int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const=0
FindDirectChildrenOnly
WA_WState_Hidden
typedef WindowFlags
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
virtual void keyPressEvent(QKeyEvent *event)
QPoint mapFromGlobal(const QPoint &pos) const const
void setWindowRole(const QString &role)
void show()
void resize(const QSize &)
QStyle * style() const const
bool testAttribute(Qt::WidgetAttribute attribute) const const
WId winId() const const
QWidget * window() const const
QWindow * windowHandle() const const
void setWindowModified(bool)
void setWindowTitle(const QString &)
void setHeight(int arg)
void setWidth(int arg)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:55:55 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.