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#ifndef KMAINWINDOW_H
16#define KMAINWINDOW_H
17
18#include <kxmlgui_export.h>
19
20#include <QMainWindow>
21#include <memory>
22
23class QMenu;
24class KConfig;
25class KConfigGroup;
26class KMWSessionManager;
27class KMainWindowPrivate;
28class KToolBar;
29
30/**
31 * @class KMainWindow kmainwindow.h KMainWindow
32 *
33 * @brief KMainWindow represents a top-level main window.
34 *
35 * It extends QMainWindow with session management capabilities. For ready-made window functionality and simpler UI management, use KXmlGuiWindow instead.
36 *
37 * Define the minimum/maximum height/width of your central widget and KMainWindow will take this into account.
38 * For fixed size windows set your main widget to a fixed size. Fixed aspect ratios (QWidget::heightForWidth()) and fixed width widgets are not supported.
39 *
40 * Use toolBar() to generate a main toolbar "mainToolBar" or refer to a specific toolbar.
41 * For a simpler way to manage your toolbars, use KXmlGuiWindow::setupGUI() instead.
42 *
43 * Use setAutoSaveSettings() to automatically save and restore the window geometry and toolbar/menubar/statusbar state when the application is restarted.
44 *
45 * Use kRestoreMainWindows() in your main function to restore your windows when the session is restored.
46 *
47 * The window state is saved when the application is exited.
48 * Reimplement queryClose() to warn the user of unsaved data upon close or exit.
49 *
50 * Reimplement saveProperties() / readProperties() or saveGlobalProperties() / readGlobalProperties()
51 * to save/restore application-specific state during session management.
52 *
53 * Note that session saving is automatically called, session restoring is not,
54 * and so it needs to be implemented in your main() function.
55 *
56 * See https://develop.kde.org/docs/use/session-managment for more information on session management.
57 */
58
59class KXMLGUI_EXPORT KMainWindow : public QMainWindow
60{
61 friend class KMWSessionManager;
62 friend class DockResizeListener;
63 Q_OBJECT
64 Q_PROPERTY(bool hasMenuBar READ hasMenuBar)
65 Q_PROPERTY(bool autoSaveSettings READ autoSaveSettings)
66 Q_PROPERTY(QString autoSaveGroup READ autoSaveGroup)
67
68public:
69 /**
70 * @brief Constructs a main window.
71 *
72 * @param parent The parent widget. This is usually @c nullptr, but it may also be
73 * the window group leader. In that case,
74 * the KMainWindow becomes a secondary window.
75 *
76 * @param flags Specify the window flags. The default is none.
77 *
78 * Note that by default a KMainWindow is created with the
79 * Qt::WA_DeleteOnClose attribute set, i.e. it is automatically destroyed
80 * when the window is closed. If you do not want this behavior, call
81 * \code
82 * window->setAttribute(Qt::WA_DeleteOnClose, false);
83 * \endcode
84 *
85 * KMainWindows must be created on the heap with 'new', like:
86 * \code
87 * KMainWindow *kmw = new KMainWindow(...);
88 * kmw->setObjectName(...);
89 * \endcode
90 *
91 * Since KDE Frameworks 5.16, KMainWindow will enter information regarding
92 * the application's translators by default, using KAboutData::setTranslator(). This only occurs
93 * if no translators are already assigned in KAboutData (see KAboutData::setTranslator() for
94 * details -- the auto-assignment here uses the same translated strings as specified for that
95 * function).
96 *
97 * IMPORTANT: For session management and window management to work
98 * properly, all main windows in the application should have a
99 * different name. Otherwise, KMainWindow will create
100 * a unique name, but it's recommended to explicitly pass a window name that will
101 * also describe the type of the window. If there can be several windows of the same
102 * type, append '#' (hash) to the name, and KMainWindow will replace it with numbers to make
103 * the names unique. For example, for a mail client which has one main window showing
104 * the mails and folders, and which can also have one or more windows for composing
105 * mails, the name for the folders window should be e.g. "mainwindow" and
106 * for the composer windows "composer#".
107 *
108 * @see KAboutData
109 */
110 explicit KMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
111
112 /**
113 * @brief Destructor.
114 *
115 * Will also destroy the toolbars and menubar if
116 * needed.
117 */
118 ~KMainWindow() override;
119
120 /**
121 * @param numberOfInstances The number of KMainWindow instances in the application.
122 * @returns @c true if the number of KMainWindow instances of the previous session did contain the requested @p numberOfInstances, @c false otherwise.
123 * @see restore()
124 **/
125 static bool canBeRestored(int numberOfInstances);
126
127 /**
128 * @brief Useful if your application uses
129 * different kinds of top-level windows.
130 *
131 * @returns The class name of the top-level window to be restored
132 * that corresponds to @p instanceNumber.
133 *
134 * @param instanceNumber
135 * @see restore()
136 */
137 static const QString classNameOfToplevel(int instanceNumber);
138
139 /**
140 * @brief Attempt to restore the top-level widget as defined by @p numberOfInstances (1..X).
141 *
142 * You should call canBeRestored() first.
143 *
144 * If the session did not contain so high a number, the configuration
145 * is not changed and @c false is returned.
146 *
147 * That means clients could simply do the following:
148 * \code
149 * if (qApp->isSessionRestored()){
150 * int n = 1;
151 * while (KMainWindow::canBeRestored(n)){
152 * (new childMW)->restore(n);
153 * n++;
154 * }
155 * } else {
156 * // create default application as usual
157 * }
158 * \endcode
159 * Note that if @p show is @c true (default), QWidget::show() is called
160 * implicitly in restore.
161 *
162 * With this you can easily restore all top-level windows of your
163 * application.
164 *
165 * If your application uses different kinds of top-level
166 * windows, then you can use KMainWindow::classNameOfToplevel(n)
167 * to determine the exact type before calling the childMW
168 * constructor in the example from above.
169 *
170 * @note You don't need to deal with this function. Use the
171 * kRestoreMainWindows() convenience template function instead!
172 *
173 * @param numberOfInstances The number of KMainWindow instances from the last session.
174 * @param show Whether the KMainWindow instances will be visible by default.
175 *
176 * @returns @c true if the session contained
177 * the same number of instances as the requested number,
178 * @c false if the session contained less instances than the requested number,
179 * in which case no configuration is changed.
180 *
181 * @see kRestoreMainWindows()
182 * @see readProperties()
183 * @see canBeRestored()
184 */
185 bool restore(int numberOfInstances, bool show = true);
186
187 /**
188 * @returns @c true if there is a menubar, @c false otherwise.
189 */
190 bool hasMenuBar();
191
192 /**
193 * @returns The list of members of the KMainWindow class.
194 */
195 static QList<KMainWindow *> memberList();
196
197 /**
198 * @brief This is useful to both call specific toolbars that have been created
199 * or to generate a default one upon call.
200 *
201 * This refers to toolbars created dynamically from the XML UI
202 * framework via KConfig or appnameui.rc.
203 *
204 * If the toolbar does not exist, one will be created.
205 *
206 * @param name The internal name of the toolbar. If no name is
207 * specified, "mainToolBar" is assumed.
208 *
209 * @return A pointer to the toolbar with the specified name.
210 * @see toolBars()
211 **/
212 KToolBar *toolBar(const QString &name = QString());
213
214 /**
215 * @return A list of all toolbars for this window
216 */
217 QList<KToolBar *> toolBars() const;
218
219 /**
220 * @brief This enables autosave of toolbar/menubar/statusbar settings
221 * (and optionally window size).
222 * @param groupName A name that identifies the type of window.
223 * You can have several types of window in the same application.
224 * If no @p groupName is specified, the value defaults to "MainWindow".
225 *
226 * @param saveWindowSize Whether to include the window size
227 * when saving. @c true by default.
228 *
229 * If the *bars were modified when the window is closed,
230 * saveMainWindowSettings( KConfigGroup(KSharedConfig::openConfig(), groupName) ) will be called.
231 *
232 * Typically, you will call setAutoSaveSettings() in your
233 * KMainWindow-inherited class constructor, and it will take care
234 * of restoring and saving automatically.
235 *
236 * By default, this generates an
237 * appnamerc ini file as if using default KConfig constructor or KConfig::SimpleConfig.
238 *
239 * Make sure you call this @em after all your *bars have been created.
240 *
241 * To make sure that KMainWindow properly obtains the default
242 * size of the window you should do the following:
243 * - Remove hardcoded resize() calls in the constructor or main
244 * to let the automatic resizing determine the default window size.
245 * Hardcoded window sizes will be wrong for users that have big fonts,
246 * use different styles, long/small translations, large toolbars, and other factors.
247 * - Put the setAutoSaveSettings() call after all widgets
248 * have been created and placed inside the main window
249 * (for most apps this means QMainWindow::setCentralWidget())
250 * - QWidget-based objects should overload "virtual QSize sizeHint() const;"
251 * to specify a default size.
252 * @see KConfig
253 * @see KSharedConfig
254 * @see saveMainWindowSettings()
255 * @see toolBar()
256 * @see KXmlGuiWindow::setupGUI()
257 */
258 void setAutoSaveSettings(const QString &groupName = QStringLiteral("MainWindow"), bool saveWindowSize = true);
259
260 /**
261 * This is an overloaded function.
262 * This allows the settings to be saved into a different file
263 * that does not correspond to that used for KSharedConfig::openConfig().
264 * @see setAutoSaveSettings(const QString &groupName, bool saveWindowSize)
265 * @see KConfig
266 * @see KSharedConfig
267 * @since 4.1
268 */
269 void setAutoSaveSettings(const KConfigGroup &group, bool saveWindowSize = true);
270
271 /**
272 * @brief Disables the autosave settings feature.
273 * You don't normally need to call this, ever.
274 * @see setAutoSaveSettings()
275 * @see autoSaveSettings()
276 */
277 void resetAutoSaveSettings();
278
279 /**
280 * @return @c true if setAutoSaveSettings() was called,
281 * @c false by default or if resetAutoSaveSettings() was called.
282 * @see setAutoSaveSettings()
283 * @see resetAutoSaveSettings()
284 */
285 bool autoSaveSettings() const;
286
287 /**
288 * @return The group used for autosaving settings.
289 *
290 * Do not mistake this with autoSaveConfigGroup.
291 *
292 * Only meaningful if setAutoSaveSettings(const QString&, bool) was called.
293 *
294 * Do not use this method if setAutoSaveSettings(const KConfigGroup&, bool) was called.
295 *
296 * This can be useful for forcing a save or an apply, e.g. before and after
297 * using KEditToolBar.
298 *
299 * @note Prefer saveAutoSaveSettings() for saving or autoSaveConfigGroup() for loading.
300 *
301 * @see autoSaveSettings()
302 * @see setAutoSaveSettings()
303 * @see saveAutoSaveSettings()
304 * @see resetAutoSaveSettings()
305 * @see autoSaveConfigGroup()
306 */
307 QString autoSaveGroup() const;
308
309 /**
310 * @return The group used for autosaving settings.
311 *
312 * Only meaningful if setAutoSaveSettings(const QString&, bool) was called.
313 *
314 * Do not use this method if setAutoSaveSettings(const KConfigGroup&, bool) was called.
315 *
316 * This can be useful for forcing an apply, e.g. after using KEditToolBar.
317 *
318 * @see setAutoSaveSettings()
319 * @see autoSaveGroup()
320 * @since 4.1
321 */
322 KConfigGroup autoSaveConfigGroup() const;
323
324 /**
325 * @brief Assigns the config group name for the KConfigGroup returned by stateConfigGroup.
326 * @param configGroup The config group to be assigned.
327 * Window size and state are stored in the resulting KConfigGroup when this function is called.
328 * @note If this is used in combination with setAutoSaveSettings, you should call this method first.
329 *
330 * @see KConfigGroup()
331 * @see KSharedConfig::openStateConfig()
332 * @see stateConfigGroup()
333 *
334 * @since 5.88
335 */
336 void setStateConfigGroup(const QString &configGroup);
337
338 /**
339 * @returns The KConfigGroup used to store state data like window sizes or window state.
340 *
341 * The resulting group is invalid if setStateConfig is not called explicitly.
342 *
343 * @see KConfigGroup
344 * @since 5.88
345 */
346 KConfigGroup stateConfigGroup() const;
347
348 /**
349 * @brief Read settings for statusbar, menubar and toolbar from their respective
350 * groups in the config file and apply them.
351 *
352 * @param config Config group to read the settings from.
353 */
354 virtual void applyMainWindowSettings(const KConfigGroup &config);
355
356 /**
357 * @brief Manually save the settings for statusbar, menubar and toolbar to their respective
358 * groups in the KConfigGroup @p config.
359 *
360 * Example:
361 * \code
362 * KConfigGroup group(KSharedConfig::openConfig(), "MainWindow");
363 * saveMainWindowSettings(group);
364 * \endcode
365 *
366 * @param config Config group to save the settings to.
367 * @see setAutoSaveSettings()
368 * @see KConfig
369 * @see KSharedConfig
370 * @see KConfigGroup
371 */
372 void saveMainWindowSettings(KConfigGroup &config);
373
374 /**
375 * @returns The path for the exported window's D-Bus object.
376 * @since 4.0.1
377 */
378 QString dbusName() const;
379
380public Q_SLOTS:
381 /**
382 * @brief Assigns a KDE compliant caption (window title).
383 *
384 * @param caption The string that will be
385 * displayed in the window title, before the application name.
386 *
387 * @note This function does the same as setPlainCaption().
388 *
389 * @note Do not include the application name
390 * in this string. It will be added automatically according to the KDE
391 * standard.
392 *
393 * @see setPlainCaption()
394 */
395 virtual void setCaption(const QString &caption);
396 /**
397 * @brief Makes a KDE compliant caption.
398 * @param caption Your caption.
399 * @param modified Whether the document is modified. This displays
400 * an additional sign in the title bar, usually "**".
401 *
402 * This is an overloaded function.
403 *
404 * @note Do not include the application name
405 * in this string. It will be added automatically according to the KDE
406 * standard.
407 */
408 virtual void setCaption(const QString &caption, bool modified);
409
410 /**
411 * @brief Make a plain caption without any modifications.
412 *
413 * @param caption The string that will be
414 * displayed in the window title, before the application name.
415 *
416 * @note This function does the same as setCaption().
417 *
418 * @note Do not include the application name
419 * in this string. It will be added automatically according to the KDE
420 * standard.
421 *
422 * @see setCaption()
423 */
424 virtual void setPlainCaption(const QString &caption);
425
426 /**
427 * @brief Opens the help page for the application.
428 *
429 * The application name is
430 * used as a key to determine what to display and the system will attempt
431 * to open \<appName\>/index.html.
432 *
433 * This method is intended for use by a help button in the toolbar or
434 * components outside the regular help menu.
435 *
436 * Use helpMenu() when you
437 * want to provide access to the help system from the help menu.
438 *
439 * Example (adding a help button to the first toolbar):
440 *
441 * \code
442 * toolBar()->addAction(QIcon::fromTheme("help-contents"), i18n("Help"),
443 * this, &KMainWindow::appHelpActivated);
444 * \endcode
445 *
446 * @see helpMenu()
447 * @see toolBar()
448 */
449 void appHelpActivated();
450
451 /**
452 * @brief Tell the main window that it should save its settings when being closed.
453 *
454 * This is part of the autosave settings feature.
455 *
456 * For everything related to toolbars this happens automatically,
457 * but you have to call setSettingsDirty() in the slot that toggles
458 * the visibility of the statusbar.
459 *
460 * @see saveAutoSaveSettings()
461 */
462 void setSettingsDirty();
463
464protected:
465 /**
466 * Reimplemented to catch QEvent::Polish in order to adjust the object name
467 * if needed, once all constructor code for the main window has run.
468 * Also reimplemented to catch when a QDockWidget is added or removed.
469 */
470 bool event(QEvent *event) override;
471
472 /**
473 * Reimplemented to open context menus on Shift+F10.
474 */
475 void keyPressEvent(QKeyEvent *keyEvent) override;
476
477 /**
478 * Reimplemented to autosave settings and call queryClose().
479 *
480 * We recommend that you reimplement queryClose() rather than closeEvent().
481 * If you do it anyway, ensure to call the base implementation to keep
482 * the feature of autosaving window settings working.
483 */
484 void closeEvent(QCloseEvent *) override;
485
486 /**
487 * @brief This function is called before the window is closed,
488 * either by the user or indirectly by the session manager.
489 *
490 * This can be used to prompt the user to save unsaved data before the window is closed.
491 *
492 * Example:
493 * \code
494 * switch ( KMessageBox::warningTwoActionsCancel( this,
495 * i18n("Save changes to document foo?"), QString(),
496 * KStandardGuiItem::save(), KStandardGuiItem::discard())) ) {
497 * case KMessageBox::PrimaryAction :
498 * // save document here. If saving fails, return false;
499 * return true;
500 * case KMessageBox::SecondaryAction :
501 * return true;
502 * default: // cancel
503 * return false;
504 * \endcode
505 *
506 * @note Do @em not close the document from within this method,
507 * as it may be called by the session manager before the
508 * session is saved. If the document is closed before the session save occurs,
509 * its location might not be properly saved. In addition, the session shutdown
510 * may be canceled, in which case the document should remain open.
511 *
512 * @return @c true by default, @c false according to the reimplementation.
513 * Returning @c false will cancel the closing operation,
514 * and if KApplication::sessionSaving() is true, it cancels logout.
515 *
516 * @see KApplication::sessionSaving()
517 */
518 virtual bool queryClose();
519
520 /**
521 * @brief Saves your instance-specific properties.
522 *
523 * The function is
524 * invoked when the session manager requests your application
525 * to save its state.
526 *
527 * Reimplement this function in child classes.
528 *
529 * \code
530 * void MainWindow::saveProperties(KConfigGroup &config) {
531 * config.writeEntry("myKey", "newValue");
532 * ...
533 * }
534 * \endcode
535 *
536 * @note No user interaction is allowed
537 * in this function!
538 *
539 */
540 virtual void saveProperties(KConfigGroup &)
541 {
542 }
543
544 /**
545 * @brief Reads your instance-specific properties.
546 *
547 * This function is called indirectly by restore().
548 *
549 * \code
550 * void MainWindow::readProperties(KConfigGroup &config) {
551 * if (config.hasKey("myKey")) {
552 * config.readEntry("myKey", "DefaultValue");
553 * }
554 * ...
555 * }
556 * \endcode
557 *
558 * @see readGlobalProperties()
559 */
560 virtual void readProperties(const KConfigGroup &)
561 {
562 }
563
564 /**
565 * @brief Saves your application-wide properties.
566 *
567 * @param sessionConfig A pointer to the KConfig instance
568 * used to save the session data.
569 *
570 * This function is invoked when the session manager
571 * requests your application to save its state.
572 * It is similar to saveProperties(), but it is only called for
573 * the first main window. This is useful to save global state of your application
574 * that isn't bound to a particular window.
575 *
576 * The default implementation does nothing.
577 *
578 * @see readGlobalProperties()
579 * @see saveProperties()
580 */
581 virtual void saveGlobalProperties(KConfig *sessionConfig);
582
583 /**
584 * @brief Reads your application-wide properties.
585 *
586 * @param sessionConfig A pointer to the KConfig instance
587 * used to load the session data.
588 *
589 * @see saveGlobalProperties()
590 * @see readProperties()
591 *
592 */
593 virtual void readGlobalProperties(KConfig *sessionConfig);
594 void savePropertiesInternal(KConfig *, int);
595 bool readPropertiesInternal(KConfig *, int);
596
597 /**
598 * For inherited classes
599 */
600 bool settingsDirty() const;
601
602protected Q_SLOTS:
603 /**
604 * This slot should only be called in case you reimplement closeEvent() and
605 * if you are using the autosave feature. In all other cases,
606 * setSettingsDirty() should be called instead to benefit from the delayed
607 * saving.
608 *
609 * Example:
610 * \code
611 *
612 * void MyMainWindow::closeEvent( QCloseEvent *e )
613 * {
614 * // Save settings if autosave is enabled, and settings have changed
615 * if ( settingsDirty() && autoSaveSettings() )
616 * saveAutoSaveSettings();
617 * ..
618 * }
619 * \endcode
620 *
621 * @see setAutoSaveSettings()
622 * @see setSettingsDirty()
623 */
624 void saveAutoSaveSettings();
625
626protected:
627 KXMLGUI_NO_EXPORT KMainWindow(KMainWindowPrivate &dd, QWidget *parent, Qt::WindowFlags f);
628
629 std::unique_ptr<KMainWindowPrivate> const d_ptr;
630
631private:
632 Q_DECLARE_PRIVATE(KMainWindow)
633
634 Q_PRIVATE_SLOT(d_func(), void _k_slotSettingsChanged(int))
635 Q_PRIVATE_SLOT(d_func(), void _k_slotSaveAutoSaveSize())
636 Q_PRIVATE_SLOT(d_func(), void _k_slotSaveAutoSavePosition())
637};
638
639/**
640 * @defgroup KXMLGUI_Session KXMLGUI Session Macros and Functions
641 *
642 * @{
643 */
644
645/**
646 * @def KDE_RESTORE_MAIN_WINDOWS_NUM_TEMPLATE_ARGS
647 * Returns the maximal number of arguments that are actually
648 * supported by kRestoreMainWindows().
649 **/
650#define KDE_RESTORE_MAIN_WINDOWS_NUM_TEMPLATE_ARGS 3
651
652/**
653 * @brief Restores the last session. (To be used in your main function).
654 *
655 * These functions work also if you have more than one kind of top-level
656 * widget (each derived from KMainWindow, of course).
657 *
658 * Imagine you have three kinds of top-level widgets: the classes @c childMW1,
659 * @c childMW2 and @c childMW3. Then you can just do:
660 *
661 * \code
662 * int main(int argc, char *argv[])
663 * {
664 * // [...]
665 * if (qApp->isSessionRestored())
666 * kRestoreMainWindows<childMW1, childMW2, childMW3>();
667 * else {
668 * // create default application as usual
669 * }
670 * // [...]
671 * }
672 * \endcode
673 *
674 * kRestoreMainWindows<>() will create (on the heap) as many instances
675 * of your main windows as have existed in the last session and
676 * call KMainWindow::restore() with the correct arguments. Note that
677 * also QWidget::show() is called implicitly.
678 *
679 * Currently, these functions are provided for up to three
680 * template arguments. If you need more, tell us. To help you in
681 * deciding whether or not you can use kRestoreMainWindows, a
682 * define #KDE_RESTORE_MAIN_WINDOWS_NUM_TEMPLATE_ARGS is provided.
683 *
684 * @note Prefer this function over directly calling KMainWindow::restore().
685 *
686 * @tparam T Top-level widget class
687 *
688 * @see KMainWindow::restore()
689 * @see KMainWindow::classNameOfToplevel()
690 **/
691template<typename T>
692inline void kRestoreMainWindows()
693{
694 for (int n = 1; KMainWindow::canBeRestored(numberOfInstances: n); ++n) {
695 const QString className = KMainWindow::classNameOfToplevel(instanceNumber: n);
696 if (className == QLatin1String(T::staticMetaObject.className())) {
697 (new T)->restore(n);
698 }
699 }
700}
701
702/**
703 * @brief Restores the last session.
704 * This is an overloaded function.
705 *
706 * Use this with multiple different top-level widget classes.
707 *
708 * @tparam T0 One top-level widget class
709 * @tparam T1 Explicit other top-level widget class for disambiguation from base template
710 * @tparam Tn Parameter pack to take 0..n further KMainWindows
711 * @see kRestoreMainWindows()
712 */
713template<typename T0, typename T1, typename... Tn>
714inline void kRestoreMainWindows()
715{
716 kRestoreMainWindows<T0>();
717 kRestoreMainWindows<T1, Tn...>();
718}
719/** @} */
720
721#endif
722

source code of kxmlgui/src/kmainwindow.h