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 QT_DBUS_LIB
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 QT_DBUS_LIB
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 // Set the icon theme fallback to breeze (if not already set)
249 // Most of our apps use "lots" of icons that most of the times
250 // are only available with breeze, we still honour the user icon
251 // theme but if the icon is not found there, we go to breeze
252 // since it's almost sure it'll be there.
253 // This should be done as soon as possible (preferably via
254 // Q_COREAPP_STARTUP_FUNCTION), but as for now it cannot be done too soon
255 // as at that point QPlatformTheme is not instantiated yet and breaks the
256 // internal status of QIconLoader (see QTBUG-74252).
257 // See also discussion at https://phabricator.kde.org/D22488
258 // TODO: remove this once we depend on Qt 5.15.1, where this is fixed
259 if (QIcon::fallbackThemeName().isEmpty()) {
260 QIcon::setFallbackThemeName(QStringLiteral("breeze"));
261 }
262
263 // If application is translated, load translator information for use in
264 // KAboutApplicationDialog or other getters. The context and messages below
265 // both must be exactly as listed, and are forced to be loaded from the
266 // application's own message catalog instead of kxmlgui's.
268 if (aboutData.translators().isEmpty()) {
269 aboutData.setTranslator(i18ndc(nullptr, "NAME OF TRANSLATORS", "Your names"), //
270 i18ndc(nullptr, "EMAIL OF TRANSLATORS", "Your emails"));
271
273 }
274
275 settingsDirty = false;
276 autoSaveSettings = false;
277 autoSaveWindowSize = true; // for compatibility
278 // d->kaccel = actionCollection()->kaccel();
279 settingsTimer = nullptr;
280 sizeTimer = nullptr;
281
282 dockResizeListener = new DockResizeListener(_q);
283 letDirtySettings = true;
284
285 sizeApplied = false;
286 suppressCloseEvent = false;
287
288 qApp->installEventFilter(KToolTipHelper::instance());
289}
290
291static bool endsWithHashNumber(const QString &s)
292{
293 for (int i = s.length() - 1; i > 0; --i) {
294 if (s[i] == QLatin1Char('#') && i != s.length() - 1) {
295 return true; // ok
296 }
297 if (!s[i].isDigit()) {
298 break;
299 }
300 }
301 return false;
302}
303
304static inline bool isValidDBusObjectPathCharacter(const QChar &c)
305{
306 ushort u = c.unicode();
307 /* clang-format off */
308 return (u >= QLatin1Char('a') && u <= QLatin1Char('z'))
309 || (u >= QLatin1Char('A') && u <= QLatin1Char('Z'))
310 || (u >= QLatin1Char('0') && u <= QLatin1Char('9'))
311 || (u == QLatin1Char('_')) || (u == QLatin1Char('/'));
312 /* clang-format off */
313}
314
315void KMainWindowPrivate::polish(KMainWindow *q)
316{
317 // Set a unique object name. Required by session management, window management, and for the dbus interface.
318 QString objname;
319 QString s;
320 int unusedNumber = 1;
321 const QString name = q->objectName();
322 bool startNumberingImmediately = true;
323 bool tryReuse = false;
324 if (name.isEmpty()) {
325 // no name given
326 objname = QStringLiteral("MainWindow#");
327 } else if (name.endsWith(QLatin1Char('#'))) {
328 // trailing # - always add a number - KWin uses this for better grouping
329 objname = name;
330 } else if (endsWithHashNumber(name)) {
331 // trailing # with a number - like above, try to use the given number first
332 objname = name;
333 tryReuse = true;
334 startNumberingImmediately = false;
335 } else {
336 objname = name;
337 startNumberingImmediately = false;
338 }
339
340 s = objname;
341 if (startNumberingImmediately) {
342 s += QLatin1Char('1');
343 }
344
345 for (;;) {
346 const QList<QWidget *> list = qApp->topLevelWidgets();
347 bool found = false;
348 for (QWidget *w : list) {
349 if (w != q && w->objectName() == s) {
350 found = true;
351 break;
352 }
353 }
354 if (!found) {
355 break;
356 }
357 if (tryReuse) {
358 objname = name.left(name.length() - 1); // lose the hash
359 unusedNumber = 0; // start from 1 below
360 tryReuse = false;
361 }
362 s.setNum(++unusedNumber);
363 s = objname + s;
364 }
365 q->setObjectName(s);
366 if (!q->window() || q->window() == q) {
367 q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
368 q->setWindowRole(s); // will keep insisting that object name suddenly should not be used for window role
369 }
370
372 dbusName += q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
373 // Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
374 for (QChar &c : dbusName) {
375 if (!isValidDBusObjectPathCharacter(c)) {
376 c = QLatin1Char('_');
377 }
378 }
379
380#ifdef QT_DBUS_LIB
381 /* clang-format off */
382 constexpr auto opts = QDBusConnection::ExportScriptableSlots
387 /* clang-format on */
388 QDBusConnection::sessionBus().registerObject(dbusName, q, opts);
389#endif
390}
391
392void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
393{
394 if (!letDirtySettings) {
395 return;
396 }
397
398 settingsDirty = true;
399 if (autoSaveSettings) {
400 if (callCompression == CompressCalls) {
401 if (!settingsTimer) {
402 settingsTimer = new QTimer(q);
403 settingsTimer->setInterval(500);
404 settingsTimer->setSingleShot(true);
406 }
407 settingsTimer->start();
408 } else {
410 }
411 }
412}
413
414void KMainWindowPrivate::setSizeDirty()
415{
416 if (autoSaveWindowSize) {
417 if (!sizeTimer) {
418 sizeTimer = new QTimer(q);
419 sizeTimer->setInterval(500);
420 sizeTimer->setSingleShot(true);
421 QObject::connect(sizeTimer, &QTimer::timeout, q, [this]() {
422 _k_slotSaveAutoSaveSize();
423 });
424 }
425 sizeTimer->start();
426 }
427}
428
430{
431 sMemberList()->removeAll(this);
432 delete static_cast<QObject *>(d_ptr->dockResizeListener); // so we don't get anymore events after d_ptr is destroyed
433}
434
435bool KMainWindow::canBeRestored(int numberOfInstances)
436{
438 if (!config) {
439 return false;
440 }
441
442 KConfigGroup group(config, QStringLiteral("Number"));
443 // TODO KF6: we should use 0 as the default value, not 1
444 // See also https://bugs.kde.org/show_bug.cgi?id=427552
445 const int n = group.readEntry("NumberOfWindows", 1);
446 return numberOfInstances >= 1 && numberOfInstances <= n;
447}
448
450{
452 if (!config) {
453 return QString();
454 }
455
456 KConfigGroup group(config, QStringLiteral("WindowProperties%1").arg(instanceNumber));
457 if (!group.hasKey("ClassName")) {
458 return QString();
459 } else {
460 return group.readEntry("ClassName");
461 }
462}
463
464bool KMainWindow::restore(int numberOfInstances, bool show)
465{
467 return false;
468 }
470 if (readPropertiesInternal(config, numberOfInstances)) {
471 if (show) {
473 }
474 return false;
475 }
476 return false;
477}
478
480{
481 setPlainCaption(caption);
482}
483
484void KMainWindow::setCaption(const QString &caption, bool modified)
485{
486 QString title = caption;
487 if (!title.contains(QLatin1String("[*]")) && !title.isEmpty()) { // append the placeholder so that the modified mechanism works
488 title.append(QLatin1String(" [*]"));
489 }
490 setPlainCaption(title);
491 setWindowModified(modified);
492}
493
495{
496 setWindowTitle(caption);
497}
498
500{
502 if (!d->helpMenu) {
503 d->helpMenu = new KHelpMenu(this);
504 if (!d->helpMenu) {
505 return;
506 }
507 }
508 d->helpMenu->appHelpActivated();
509}
510
512{
514 if (d->suppressCloseEvent) {
515 e->accept();
516 return;
517 }
518
519 // Save settings if auto-save is enabled, and settings have changed
520 if (d->settingsTimer && d->settingsTimer->isActive()) {
521 d->settingsTimer->stop();
523 }
524 if (d->sizeTimer && d->sizeTimer->isActive()) {
525 d->sizeTimer->stop();
526 d->_k_slotSaveAutoSaveSize();
527 }
528 // Delete the marker that says we don't want to restore the position of the
529 // next-opened instance; now that a window is closing, we do want to do this
530 if (d->autoSaveGroup.isValid()) {
531 d->getStateConfig().deleteEntry("RestorePositionForNextInstance");
532 }
533 d->_k_slotSaveAutoSavePosition();
534
535 if (queryClose()) {
536 // widgets will start destroying themselves at this point and we don't
537 // want to save state anymore after this as it might be incorrect
538 d->autoSaveSettings = false;
539 d->letDirtySettings = false;
540 e->accept();
541 } else {
542 e->ignore(); // if the window should not be closed, don't close it
543 }
544
545#ifndef QT_NO_SESSIONMANAGER
546 // If saving session, we are processing a fake close event, and might get the real one later.
547 if (e->isAccepted() && qApp->isSavingSession()) {
548 d->suppressCloseEvent = true;
549 }
550#endif
551}
552
554{
555 return true;
556}
557
561
565
566void KMainWindow::savePropertiesInternal(KConfig *config, int number)
567{
569 const bool oldASWS = d->autoSaveWindowSize;
570 d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
571
572 KConfigGroup cg(config, QStringLiteral("WindowProperties%1").arg(number));
573
574 // store objectName, className, Width and Height for later restoring
575 // (Only useful for session management)
576 cg.writeEntry("ObjectName", objectName());
577 cg.writeEntry("ClassName", metaObject()->className());
578
579 saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
580
581 cg = KConfigGroup(config, QString::number(number));
583
584 d->autoSaveWindowSize = oldASWS;
585}
586
588{
590 // qDebug(200) << "KMainWindow::saveMainWindowSettings " << cg.name();
591
592 // Called by session management - or if we want to save the window size anyway
593 if (d->autoSaveWindowSize) {
594 KWindowConfig::saveWindowSize(windowHandle(), d->getStateConfig());
595 KWindowConfig::saveWindowPosition(windowHandle(), d->getStateConfig());
596 }
597
598 // One day will need to save the version number, but for now, assume 0
599 // Utilise the QMainWindow::saveState() functionality.
600 const QByteArray state = saveState();
601 d->getStateConfig().writeEntry("State", state.toBase64());
602
603 QStatusBar *sb = internalStatusBar(this);
604 if (sb) {
605 if (!cg.hasDefault("StatusBar") && !sb->isHidden()) {
606 cg.revertToDefault("StatusBar");
607 } else {
608 cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
609 }
610 }
611
612 QMenuBar *mb = internalMenuBar(this);
613
614 if (mb && !mb->isNativeMenuBar()) {
615 if (!cg.hasDefault("MenuBar") && !mb->isHidden()) {
616 cg.revertToDefault("MenuBar");
617 } else {
618 cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
619 }
620 }
621
622 if (!autoSaveSettings() || cg.name() == autoSaveGroup()) {
623 // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
624 if (!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked()) {
625 cg.revertToDefault("ToolBarsMovable");
626 } else {
627 cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
628 }
629 }
630
631 int n = 1; // Toolbar counter. toolbars are counted from 1,
632 const auto toolBars = this->toolBars();
633 for (KToolBar *toolbar : toolBars) {
634 // Give a number to the toolbar, but prefer a name if there is one,
635 // because there's no real guarantee on the ordering of toolbars
636 const QString groupName = toolbar->objectName().isEmpty() ? QStringLiteral("Toolbar%1").arg(n) : (QStringLiteral("Toolbar ") + toolbar->objectName());
637
638 KConfigGroup toolbarGroup(&cg, groupName);
639 toolbar->saveSettings(toolbarGroup);
640 n++;
641 }
642}
643
644bool KMainWindow::readPropertiesInternal(KConfig *config, int number)
645{
647
648 const bool oldLetDirtySettings = d->letDirtySettings;
649 d->letDirtySettings = false;
650
651 if (number == 1) {
652 readGlobalProperties(config);
653 }
654
655 // in order they are in toolbar list
656 KConfigGroup cg(config, QStringLiteral("WindowProperties%1").arg(number));
657
658 // restore the object name (window role)
659 if (cg.hasKey("ObjectName")) {
660 setObjectName(cg.readEntry("ObjectName"));
661 }
662
663 d->sizeApplied = false; // since we are changing config file, reload the size of the window
664 // if necessary. Do it before the call to applyMainWindowSettings.
665 applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
666
667 KConfigGroup grp(config, QString::number(number));
669
670 d->letDirtySettings = oldLetDirtySettings;
671
672 return true;
673}
674
676{
678 // qDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
679
681 d->migrateStateDataIfNeeded(cg);
682
684
685 const bool oldLetDirtySettings = d->letDirtySettings;
686 d->letDirtySettings = false;
687
688 KConfigGroup stateConfig = d->getStateConfig();
689
690 if (!d->sizeApplied && (!window() || window() == this)) {
691 winId(); // ensure there's a window created
692 // Set the window's size from the existing widget geometry to respect the
693 // implicit size when there is no saved geometry in the config file for
694 // KWindowConfig::restoreWindowSize() to restore
695 // TODO: remove once QTBUG-40584 is fixed; see below
699 // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
700 // window was created -> QTBUG-40584. We therefore copy the size here.
701 // TODO: remove once this was resolved in QWidget QPA
703 d->sizeApplied = true;
704
705 // Let the user opt out of KDE apps remembering window sizes if they
706 // find it annoying or it doesn't work for them due to other bugs.
708 KConfigGroup group(config, QStringLiteral("General"));
709 if (group.readEntry("AllowKDEAppsToRememberWindowPositions", true)) {
710 if (stateConfig.readEntry("RestorePositionForNextInstance", true)) {
712 // Save the fact that we now don't want to restore position
713 // anymore; if we did, the next instance would completely cover
714 // the existing one
715 stateConfig.writeEntry("RestorePositionForNextInstance", false);
716 }
717 }
718 }
719
720 QStatusBar *sb = internalStatusBar(this);
721 if (sb) {
722 QString entry = cg.readEntry("StatusBar", "Enabled");
723 sb->setVisible(entry != QLatin1String("Disabled"));
724 }
725
726 QMenuBar *mb = internalMenuBar(this);
727 if (mb && !mb->isNativeMenuBar()) {
728 QString entry = cg.readEntry("MenuBar", "Enabled");
729 mb->setVisible(entry != QLatin1String("Disabled"));
730 }
731
732 if (!autoSaveSettings() || cg.name() == autoSaveGroup()) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
733 QString entry = cg.readEntry("ToolBarsMovable", "Disabled");
734 KToolBar::setToolBarsLocked(entry == QLatin1String("Disabled"));
735 }
736
737 int n = 1; // Toolbar counter. toolbars are counted from 1,
738 const auto toolBars = this->toolBars();
739 for (KToolBar *toolbar : toolBars) {
740 // Give a number to the toolbar, but prefer a name if there is one,
741 // because there's no real guarantee on the ordering of toolbars
742 const QString groupName = toolbar->objectName().isEmpty() ? QStringLiteral("Toolbar%1").arg(n) : (QStringLiteral("Toolbar ") + toolbar->objectName());
743
744 KConfigGroup toolbarGroup(&cg, groupName);
745 toolbar->applySettings(toolbarGroup);
746 n++;
747 }
748
749 if (stateConfig.hasKey("State")) {
750 QByteArray state;
751 state = stateConfig.readEntry("State", state);
752 state = QByteArray::fromBase64(state);
753 // One day will need to load the version number, but for now, assume 0
754 restoreState(state);
755 }
756
757 if (focusedWidget) {
758 focusedWidget->setFocus();
759 }
760
761 d->settingsDirty = false;
762 d->letDirtySettings = oldLetDirtySettings;
763}
764
766{
768 d->setSettingsDirty();
769}
770
772{
773 Q_D(const KMainWindow);
774 return d->settingsDirty;
775}
776
777void KMainWindow::setAutoSaveSettings(const QString &groupName, bool saveWindowSize)
778{
779 setAutoSaveSettings(KConfigGroup(KSharedConfig::openConfig(), groupName), saveWindowSize);
780}
781
782void KMainWindow::setAutoSaveSettings(const KConfigGroup &group, bool saveWindowSize)
783{
784 // We re making a little assumption that if you want to save the window
785 // size, you probably also want to save the window position too
786 // This avoids having to re-implement a new version of
787 // KMainWindow::setAutoSaveSettings that handles these cases independently
789 d->autoSaveSettings = true;
790 d->autoSaveGroup = group;
791 d->autoSaveWindowSize = saveWindowSize;
792
793 if (!saveWindowSize && d->sizeTimer) {
794 d->sizeTimer->stop();
795 }
796
797 // Now read the previously saved settings
798 applyMainWindowSettings(d->autoSaveGroup);
799}
800
802{
804 d->autoSaveSettings = false;
805 if (d->settingsTimer) {
806 d->settingsTimer->stop();
807 }
808}
809
810bool KMainWindow::autoSaveSettings() const
811{
812 Q_D(const KMainWindow);
813 return d->autoSaveSettings;
814}
815
816QString KMainWindow::autoSaveGroup() const
817{
818 Q_D(const KMainWindow);
819 return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
820}
821
823{
824 Q_D(const KMainWindow);
825 return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
826}
827
829{
831 d->m_stateConfigGroup = KSharedConfig::openStateConfig()->group(configGroup);
832}
833
835{
836 Q_D(const KMainWindow);
837 return d->getStateConfig();
838}
839
841{
843 Q_ASSERT(d->autoSaveSettings);
844 // qDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
845 saveMainWindowSettings(d->autoSaveGroup);
846 d->autoSaveGroup.sync();
847 d->m_stateConfigGroup.sync();
848 d->settingsDirty = false;
849}
850
852{
854 switch (ev->type()) {
855#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
856 case QEvent::Move:
857#endif
858 case QEvent::Resize:
859 d->setSizeDirty();
860 break;
861 case QEvent::Polish:
862 d->polish(this);
863 break;
865 QChildEvent *event = static_cast<QChildEvent *>(ev);
867 KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
869 if (dock) {
872
873 // there is no signal emitted if the size of the dock changes,
874 // hence install an event filter instead
875 dock->installEventFilter(d->dockResizeListener);
876 } else if (toolbar) {
877 // there is no signal emitted if the size of the toolbar changes,
878 // hence install an event filter instead
879 toolbar->installEventFilter(d->dockResizeListener);
880 } else if (menubar) {
881 // there is no signal emitted if the size of the menubar changes,
882 // hence install an event filter instead
883 menubar->installEventFilter(d->dockResizeListener);
884 }
885 break;
886 }
888 QChildEvent *event = static_cast<QChildEvent *>(ev);
890 KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
892 if (dock) {
895 dock->removeEventFilter(d->dockResizeListener);
896 } else if (toolbar) {
897 toolbar->removeEventFilter(d->dockResizeListener);
898 } else if (menubar) {
899 menubar->removeEventFilter(d->dockResizeListener);
900 }
901 break;
902 }
903 default:
904 break;
905 }
906 return QMainWindow::event(ev);
907}
908
910{
911 if (KStandardShortcut::openContextMenu().contains(QKeySequence(keyEvent->key() | keyEvent->modifiers()))) {
912 if (QWidget *widgetWithKeyboardFocus = qApp->focusWidget()) {
913 const QPoint centerOfWidget(widgetWithKeyboardFocus->width() / 2, widgetWithKeyboardFocus->height() / 2);
914 qApp->postEvent(widgetWithKeyboardFocus,
916 return;
917 }
918 if (qApp->focusObject()) {
919 qApp->postEvent(qApp->focusObject(), new QContextMenuEvent(QContextMenuEvent::Keyboard, mapFromGlobal(QCursor::pos()), QCursor::pos()));
920 return;
921 }
922 }
924}
925
926bool KMainWindow::hasMenuBar()
927{
928 return internalMenuBar(this);
929}
930
931void KMainWindowPrivate::_k_slotSettingsChanged(int category)
932{
933 Q_UNUSED(category);
934
935 // This slot will be called when the style KCM changes settings that need
936 // to be set on the already running applications.
937
938 // At this level (KMainWindow) the only thing we need to restore is the
939 // animations setting (whether the user wants builtin animations or not).
940
942}
943
944void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
945{
946 if (autoSaveGroup.isValid()) {
947 KWindowConfig::saveWindowSize(q->windowHandle(), getStateConfig());
948 }
949}
950
951void KMainWindowPrivate::_k_slotSaveAutoSavePosition()
952{
953 if (autoSaveGroup.isValid()) {
954 KWindowConfig::saveWindowPosition(q->windowHandle(), getStateConfig());
955 }
956}
957
959{
960 QString childName = name;
961 if (childName.isEmpty()) {
962 childName = QStringLiteral("mainToolBar");
963 }
964
966 if (tb) {
967 return tb;
968 }
969
970 KToolBar *toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
971 return toolbar;
972}
973
975{
977
978 const auto theChildren = children();
979 for (QObject *child : theChildren) {
982 }
983 }
984
985 return ret;
986}
987
992
994{
995 Q_D(const KMainWindow);
996
997 return d->dbusName;
998}
999
1000#include "kmainwindow.moc"
1001#include "moc_kmainwindow.cpp"
1002#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)
KGuiItem discard()
QString name(StandardShortcut id)
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)
QString fallbackThemeName()
void setFallbackThemeName(const QString &name)
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 Tue Mar 26 2024 11:21:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.