From f67b8df3ebdba2d398b9cce686b7c644adffff08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 7 May 2011 00:02:01 +0200 Subject: library split --- src/widgets/kernel/kernel.pri | 246 + src/widgets/kernel/mac.pri | 4 + src/widgets/kernel/qaction.cpp | 1520 +++ src/widgets/kernel/qaction.h | 264 + src/widgets/kernel/qaction_p.h | 144 + src/widgets/kernel/qactiongroup.cpp | 422 + src/widgets/kernel/qactiongroup.h | 112 + src/widgets/kernel/qapplication.cpp | 5687 ++++++++++ src/widgets/kernel/qapplication.h | 422 + src/widgets/kernel/qapplication_p.h | 626 ++ src/widgets/kernel/qapplication_qpa.cpp | 431 + src/widgets/kernel/qbackingstore.cpp | 1665 +++ src/widgets/kernel/qbackingstore_p.h | 278 + src/widgets/kernel/qboxlayout.cpp | 1550 +++ src/widgets/kernel/qboxlayout.h | 173 + src/widgets/kernel/qdesktopwidget.cpp | 76 + src/widgets/kernel/qdesktopwidget.h | 110 + src/widgets/kernel/qdesktopwidget.qdoc | 269 + src/widgets/kernel/qdesktopwidget_qpa.cpp | 174 + src/widgets/kernel/qdesktopwidget_qpa_p.h | 81 + src/widgets/kernel/qformlayout.cpp | 2079 ++++ src/widgets/kernel/qformlayout.h | 163 + src/widgets/kernel/qgesture.cpp | 1118 ++ src/widgets/kernel/qgesture.h | 328 + src/widgets/kernel/qgesture_p.h | 245 + src/widgets/kernel/qgesturemanager.cpp | 721 ++ src/widgets/kernel/qgesturemanager_p.h | 151 + src/widgets/kernel/qgesturerecognizer.cpp | 240 + src/widgets/kernel/qgesturerecognizer.h | 102 + src/widgets/kernel/qgridlayout.cpp | 1889 ++++ src/widgets/kernel/qgridlayout.h | 176 + src/widgets/kernel/qguieventdispatcher_glib.cpp | 224 + src/widgets/kernel/qguieventdispatcher_glib_p.h | 79 + src/widgets/kernel/qguiplatformplugin.cpp | 298 + src/widgets/kernel/qguiplatformplugin_p.h | 126 + src/widgets/kernel/qicon.cpp | 1165 ++ src/widgets/kernel/qicon.h | 143 + src/widgets/kernel/qicon_p.h | 139 + src/widgets/kernel/qiconengine.cpp | 324 + src/widgets/kernel/qiconengine.h | 104 + src/widgets/kernel/qiconengineplugin.cpp | 171 + src/widgets/kernel/qiconengineplugin.h | 104 + src/widgets/kernel/qiconloader.cpp | 573 + src/widgets/kernel/qiconloader_p.h | 192 + src/widgets/kernel/qlayout.cpp | 1632 +++ src/widgets/kernel/qlayout.h | 245 + src/widgets/kernel/qlayout_p.h | 101 + src/widgets/kernel/qlayoutengine.cpp | 436 + src/widgets/kernel/qlayoutengine_p.h | 140 + src/widgets/kernel/qlayoutitem.cpp | 834 ++ src/widgets/kernel/qlayoutitem.h | 182 + src/widgets/kernel/qsizepolicy.h | 244 + src/widgets/kernel/qsizepolicy.qdoc | 529 + src/widgets/kernel/qsoftkeymanager.cpp | 319 + src/widgets/kernel/qsoftkeymanager_common_p.h | 86 + src/widgets/kernel/qsoftkeymanager_p.h | 115 + src/widgets/kernel/qsound.cpp | 367 + src/widgets/kernel/qsound.h | 90 + src/widgets/kernel/qsound_p.h | 100 + src/widgets/kernel/qstackedlayout.cpp | 543 + src/widgets/kernel/qstackedlayout.h | 115 + src/widgets/kernel/qstandardgestures.cpp | 595 + src/widgets/kernel/qstandardgestures_p.h | 117 + src/widgets/kernel/qt_gui_pch.h | 85 + src/widgets/kernel/qtooltip.cpp | 623 ++ src/widgets/kernel/qtooltip.h | 84 + src/widgets/kernel/qwhatsthis.cpp | 777 ++ src/widgets/kernel/qwhatsthis.h | 88 + src/widgets/kernel/qwidget.cpp | 12677 ++++++++++++++++++++++ src/widgets/kernel/qwidget.h | 1091 ++ src/widgets/kernel/qwidget_p.h | 1034 ++ src/widgets/kernel/qwidget_qpa.cpp | 824 ++ src/widgets/kernel/qwidgetaction.cpp | 287 + src/widgets/kernel/qwidgetaction.h | 91 + src/widgets/kernel/qwidgetaction_p.h | 77 + src/widgets/kernel/qwidgetwindow_qpa.cpp | 188 + src/widgets/kernel/qwidgetwindow_qpa_p.h | 83 + src/widgets/kernel/symbian.pri | 7 + src/widgets/kernel/win.pri | 4 + src/widgets/kernel/x11.pri | 4 + 80 files changed, 49922 insertions(+) create mode 100644 src/widgets/kernel/kernel.pri create mode 100644 src/widgets/kernel/mac.pri create mode 100644 src/widgets/kernel/qaction.cpp create mode 100644 src/widgets/kernel/qaction.h create mode 100644 src/widgets/kernel/qaction_p.h create mode 100644 src/widgets/kernel/qactiongroup.cpp create mode 100644 src/widgets/kernel/qactiongroup.h create mode 100644 src/widgets/kernel/qapplication.cpp create mode 100644 src/widgets/kernel/qapplication.h create mode 100644 src/widgets/kernel/qapplication_p.h create mode 100644 src/widgets/kernel/qapplication_qpa.cpp create mode 100644 src/widgets/kernel/qbackingstore.cpp create mode 100644 src/widgets/kernel/qbackingstore_p.h create mode 100644 src/widgets/kernel/qboxlayout.cpp create mode 100644 src/widgets/kernel/qboxlayout.h create mode 100644 src/widgets/kernel/qdesktopwidget.cpp create mode 100644 src/widgets/kernel/qdesktopwidget.h create mode 100644 src/widgets/kernel/qdesktopwidget.qdoc create mode 100644 src/widgets/kernel/qdesktopwidget_qpa.cpp create mode 100644 src/widgets/kernel/qdesktopwidget_qpa_p.h create mode 100644 src/widgets/kernel/qformlayout.cpp create mode 100644 src/widgets/kernel/qformlayout.h create mode 100644 src/widgets/kernel/qgesture.cpp create mode 100644 src/widgets/kernel/qgesture.h create mode 100644 src/widgets/kernel/qgesture_p.h create mode 100644 src/widgets/kernel/qgesturemanager.cpp create mode 100644 src/widgets/kernel/qgesturemanager_p.h create mode 100644 src/widgets/kernel/qgesturerecognizer.cpp create mode 100644 src/widgets/kernel/qgesturerecognizer.h create mode 100644 src/widgets/kernel/qgridlayout.cpp create mode 100644 src/widgets/kernel/qgridlayout.h create mode 100644 src/widgets/kernel/qguieventdispatcher_glib.cpp create mode 100644 src/widgets/kernel/qguieventdispatcher_glib_p.h create mode 100644 src/widgets/kernel/qguiplatformplugin.cpp create mode 100644 src/widgets/kernel/qguiplatformplugin_p.h create mode 100644 src/widgets/kernel/qicon.cpp create mode 100644 src/widgets/kernel/qicon.h create mode 100644 src/widgets/kernel/qicon_p.h create mode 100644 src/widgets/kernel/qiconengine.cpp create mode 100644 src/widgets/kernel/qiconengine.h create mode 100644 src/widgets/kernel/qiconengineplugin.cpp create mode 100644 src/widgets/kernel/qiconengineplugin.h create mode 100644 src/widgets/kernel/qiconloader.cpp create mode 100644 src/widgets/kernel/qiconloader_p.h create mode 100644 src/widgets/kernel/qlayout.cpp create mode 100644 src/widgets/kernel/qlayout.h create mode 100644 src/widgets/kernel/qlayout_p.h create mode 100644 src/widgets/kernel/qlayoutengine.cpp create mode 100644 src/widgets/kernel/qlayoutengine_p.h create mode 100644 src/widgets/kernel/qlayoutitem.cpp create mode 100644 src/widgets/kernel/qlayoutitem.h create mode 100644 src/widgets/kernel/qsizepolicy.h create mode 100644 src/widgets/kernel/qsizepolicy.qdoc create mode 100644 src/widgets/kernel/qsoftkeymanager.cpp create mode 100644 src/widgets/kernel/qsoftkeymanager_common_p.h create mode 100644 src/widgets/kernel/qsoftkeymanager_p.h create mode 100644 src/widgets/kernel/qsound.cpp create mode 100644 src/widgets/kernel/qsound.h create mode 100644 src/widgets/kernel/qsound_p.h create mode 100644 src/widgets/kernel/qstackedlayout.cpp create mode 100644 src/widgets/kernel/qstackedlayout.h create mode 100644 src/widgets/kernel/qstandardgestures.cpp create mode 100644 src/widgets/kernel/qstandardgestures_p.h create mode 100644 src/widgets/kernel/qt_gui_pch.h create mode 100644 src/widgets/kernel/qtooltip.cpp create mode 100644 src/widgets/kernel/qtooltip.h create mode 100644 src/widgets/kernel/qwhatsthis.cpp create mode 100644 src/widgets/kernel/qwhatsthis.h create mode 100644 src/widgets/kernel/qwidget.cpp create mode 100644 src/widgets/kernel/qwidget.h create mode 100644 src/widgets/kernel/qwidget_p.h create mode 100644 src/widgets/kernel/qwidget_qpa.cpp create mode 100644 src/widgets/kernel/qwidgetaction.cpp create mode 100644 src/widgets/kernel/qwidgetaction.h create mode 100644 src/widgets/kernel/qwidgetaction_p.h create mode 100644 src/widgets/kernel/qwidgetwindow_qpa.cpp create mode 100644 src/widgets/kernel/qwidgetwindow_qpa_p.h create mode 100644 src/widgets/kernel/symbian.pri create mode 100644 src/widgets/kernel/win.pri create mode 100644 src/widgets/kernel/x11.pri (limited to 'src/widgets/kernel') diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri new file mode 100644 index 0000000000..d085bff146 --- /dev/null +++ b/src/widgets/kernel/kernel.pri @@ -0,0 +1,246 @@ +# Qt kernel module + +# Only used on platforms with CONFIG += precompile_header +PRECOMPILED_HEADER = kernel/qt_gui_pch.h + + +KERNEL_P= kernel +HEADERS += \ + kernel/qaction.h \ + kernel/qaction_p.h \ + kernel/qactiongroup.h \ + kernel/qapplication.h \ + kernel/qapplication_p.h \ + kernel/qbackingstore_p.h \ + kernel/qboxlayout.h \ + kernel/qdesktopwidget.h \ + kernel/qformlayout.h \ + kernel/qgridlayout.h \ + kernel/qicon.h \ + kernel/qicon_p.h \ + kernel/qiconloader_p.h \ + kernel/qiconengine.h \ + kernel/qiconengineplugin.h \ + kernel/qlayout.h \ + kernel/qlayout_p.h \ + kernel/qlayoutengine_p.h \ + kernel/qlayoutitem.h \ + kernel/qsizepolicy.h \ + kernel/qstackedlayout.h \ + kernel/qtooltip.h \ + kernel/qwhatsthis.h \ + kernel/qwidget.h \ + kernel/qwidget_p.h \ + kernel/qwidgetaction.h \ + kernel/qwidgetaction_p.h \ + kernel/qgesture.h \ + kernel/qgesture_p.h \ + kernel/qstandardgestures_p.h \ + kernel/qgesturerecognizer.h \ + kernel/qgesturemanager_p.h \ + kernel/qsoftkeymanager_p.h \ + kernel/qsoftkeymanager_common_p.h \ + kernel/qguiplatformplugin_p.h + +SOURCES += \ + kernel/qaction.cpp \ + kernel/qactiongroup.cpp \ + kernel/qapplication.cpp \ + kernel/qbackingstore.cpp \ + kernel/qboxlayout.cpp \ + kernel/qformlayout.cpp \ + kernel/qgridlayout.cpp \ + kernel/qicon.cpp \ + kernel/qiconloader.cpp \ + kernel/qiconengine.cpp \ + kernel/qiconengineplugin.cpp \ + kernel/qlayout.cpp \ + kernel/qlayoutengine.cpp \ + kernel/qlayoutitem.cpp \ + kernel/qstackedlayout.cpp \ + kernel/qtooltip.cpp \ + kernel/qwhatsthis.cpp \ + kernel/qwidget.cpp \ + kernel/qwidgetaction.cpp \ + kernel/qgesture.cpp \ + kernel/qstandardgestures.cpp \ + kernel/qgesturerecognizer.cpp \ + kernel/qgesturemanager.cpp \ + kernel/qsoftkeymanager.cpp \ + kernel/qdesktopwidget.cpp \ + kernel/qguiplatformplugin.cpp \ + kernel/qwidgetsvariant.cpp + +win32 { + DEFINES += QT_NO_DIRECTDRAW + + HEADERS += \ + kernel/qwinnativepangesturerecognizer_win_p.h + + SOURCES += \ + kernel/qapplication_win.cpp \ + kernel/qclipboard_win.cpp \ + kernel/qcursor_win.cpp \ + kernel/qdesktopwidget_win.cpp \ + kernel/qdnd_win.cpp \ + kernel/qmime_win.cpp \ + kernel/qsound_win.cpp \ + kernel/qwidget_win.cpp \ + kernel/qole_win.cpp \ + kernel/qkeymapper_win.cpp \ + kernel/qwinnativepangesturerecognizer_win.cpp + + !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib +} + +symbian { + exists($${EPOCROOT}epoc32/include/platform/mw/akntranseffect.h): DEFINES += QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H + + SOURCES += \ + kernel/qapplication_s60.cpp \ + kernel/qeventdispatcher_s60.cpp \ + kernel/qwidget_s60.cpp \ + kernel/qcursor_s60.cpp \ + kernel/qdesktopwidget_s60.cpp \ + kernel/qkeymapper_s60.cpp\ + kernel/qclipboard_s60.cpp\ + kernel/qdnd_s60.cpp \ + kernel/qsound_s60.cpp + + HEADERS += \ + kernel/qt_s60_p.h \ + kernel/qeventdispatcher_s60_p.h + + LIBS += -lbafl -lestor + + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE + INCLUDEPATH += ../3rdparty/s60 + + contains(QT_CONFIG, s60) { + SOURCES += kernel/qsoftkeymanager_s60.cpp + HEADERS += kernel/qsoftkeymanager_s60_p.h + } +} + + +unix:x11 { + INCLUDEPATH += ../3rdparty/xorg + HEADERS += \ + kernel/qx11embed_x11.h \ + kernel/qx11info_x11.h \ + kernel/qkde_p.h + + SOURCES += \ + kernel/qapplication_x11.cpp \ + kernel/qclipboard_x11.cpp \ + kernel/qcursor_x11.cpp \ + kernel/qdnd_x11.cpp \ + kernel/qdesktopwidget_x11.cpp \ + kernel/qmotifdnd_x11.cpp \ + kernel/qsound_x11.cpp \ + kernel/qwidget_x11.cpp \ + kernel/qwidgetcreate_x11.cpp \ + kernel/qx11embed_x11.cpp \ + kernel/qx11info_x11.cpp \ + kernel/qkeymapper_x11.cpp \ + kernel/qkde.cpp + + contains(QT_CONFIG, glib) { + SOURCES += \ + kernel/qguieventdispatcher_glib.cpp + HEADERS += \ + kernel/qguieventdispatcher_glib_p.h + QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB + LIBS_PRIVATE +=$$QT_LIBS_GLIB + } + SOURCES += \ + kernel/qeventdispatcher_x11.cpp + HEADERS += \ + kernel/qeventdispatcher_x11_p.h +} + +!qpa { + HEADERS += \ + kernel/qsound.h \ + kernel/qsound_p.h + + SOURCES += \ + kernel/qsound.cpp +} + +qpa { + HEADERS += \ + kernel/qdesktopwidget_qpa_p.h \ + kernel/qwidgetwindow_qpa_p.h \ + + SOURCES += \ + kernel/qapplication_qpa.cpp \ + kernel/qdesktopwidget_qpa.cpp \ + kernel/qwidget_qpa.cpp \ + kernel/qwidgetwindow_qpa.cpp \ +} + +!qpa:!x11:mac { + SOURCES += \ + kernel/qclipboard_mac.cpp \ + kernel/qmime_mac.cpp \ + kernel/qt_mac.cpp \ + kernel/qkeymapper_mac.cpp + + OBJECTIVE_HEADERS += \ + qcocoawindow_mac_p.h \ + qcocoapanel_mac_p.h \ + qcocoawindowdelegate_mac_p.h \ + qcocoaview_mac_p.h \ + qcocoaapplication_mac_p.h \ + qcocoaapplicationdelegate_mac_p.h \ + qmacgesturerecognizer_mac_p.h \ + qmultitouch_mac_p.h \ + qcocoasharedwindowmethods_mac_p.h \ + qcocoaintrospection_p.h + + OBJECTIVE_SOURCES += \ + kernel/qcursor_mac.mm \ + kernel/qdnd_mac.mm \ + kernel/qsound_mac.mm \ + kernel/qapplication_mac.mm \ + kernel/qwidget_mac.mm \ + kernel/qcocoapanel_mac.mm \ + kernel/qcocoaview_mac.mm \ + kernel/qcocoawindow_mac.mm \ + kernel/qcocoawindowdelegate_mac.mm \ + kernel/qcocoamenuloader_mac.mm \ + kernel/qcocoaapplication_mac.mm \ + kernel/qcocoaapplicationdelegate_mac.mm \ + kernel/qt_cocoa_helpers_mac.mm \ + kernel/qdesktopwidget_mac.mm \ + kernel/qeventdispatcher_mac.mm \ + kernel/qcocoawindowcustomthemeframe_mac.mm \ + kernel/qmacgesturerecognizer_mac.mm \ + kernel/qmultitouch_mac.mm \ + kernel/qcocoaintrospection_mac.mm + + HEADERS += \ + kernel/qt_cocoa_helpers_mac_p.h \ + kernel/qcocoaapplication_mac_p.h \ + kernel/qcocoaapplicationdelegate_mac_p.h \ + kernel/qeventdispatcher_mac_p.h + + MENU_NIB.files = mac/qt_menu.nib + MENU_NIB.path = Resources + MENU_NIB.version = Versions + QMAKE_BUNDLE_DATA += MENU_NIB + RESOURCES += mac/macresources.qrc + + LIBS_PRIVATE += -framework AppKit +} + +wince*: { + HEADERS += \ + ../corelib/kernel/qfunctions_wince.h \ + kernel/qguifunctions_wince.h + + SOURCES += \ + ../corelib/kernel/qfunctions_wince.cpp \ + kernel/qguifunctions_wince.cpp +} diff --git a/src/widgets/kernel/mac.pri b/src/widgets/kernel/mac.pri new file mode 100644 index 0000000000..df457dd166 --- /dev/null +++ b/src/widgets/kernel/mac.pri @@ -0,0 +1,4 @@ +!x11:!qpa:mac { + LIBS_PRIVATE += -framework Carbon -lz + *-mwerks:INCLUDEPATH += compat +} diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp new file mode 100644 index 0000000000..69e9889e08 --- /dev/null +++ b/src/widgets/kernel/qaction.cpp @@ -0,0 +1,1520 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaction.h" +#include "qactiongroup.h" + +#ifndef QT_NO_ACTION +#include "qaction_p.h" +#include "qapplication.h" +#include "qevent.h" +#include "qlist.h" +#include "qdebug.h" +#include +#include +#include + +#define QAPP_CHECK(functionName) \ + if (!qApp) { \ + qWarning("QAction: Initialize QApplication before calling '" functionName "'."); \ + return; \ + } + +QT_BEGIN_NAMESPACE + +/* + internal: guesses a descriptive text from a text suited for a menu entry + */ +static QString qt_strippedText(QString s) +{ + s.remove( QString::fromLatin1("...") ); + int i = 0; + while (i < s.size()) { + ++i; + if (s.at(i-1) != QLatin1Char('&')) + continue; + if (i < s.size() && s.at(i) == QLatin1Char('&')) + ++i; + s.remove(i-1,1); + } + return s.trimmed(); +} + + +QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), + visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), + forceEnabledInSoftkeys(false), menuActionSoftkeys(false), + iconVisibleInMenu(-1), + menuRole(QAction::TextHeuristicRole), softKeyRole(QAction::NoSoftKey), + priority(QAction::NormalPriority) +{ +#ifdef QT3_SUPPORT + static int qt_static_action_id = -1; + param = id = --qt_static_action_id; + act_signal = 0; +#endif +#ifndef QT_NO_SHORTCUT + shortcutId = 0; + shortcutContext = Qt::WindowShortcut; + autorepeat = true; +#endif +} + +QActionPrivate::~QActionPrivate() +{ +} + +bool QActionPrivate::showStatusText(QWidget *widget, const QString &str) +{ +#ifdef QT_NO_STATUSTIP + Q_UNUSED(widget); + Q_UNUSED(str); +#else + if(QObject *object = widget ? widget : parent) { + QStatusTipEvent tip(str); + QApplication::sendEvent(object, &tip); + return true; + } +#endif + return false; +} + +void QActionPrivate::sendDataChanged() +{ + Q_Q(QAction); + QActionEvent e(QEvent::ActionChanged, q); + for (int i = 0; i < widgets.size(); ++i) { + QWidget *w = widgets.at(i); + QApplication::sendEvent(w, &e); + } +#ifndef QT_NO_GRAPHICSVIEW + for (int i = 0; i < graphicsWidgets.size(); ++i) { + QGraphicsWidget *w = graphicsWidgets.at(i); + QApplication::sendEvent(w, &e); + } +#endif + QApplication::sendEvent(q, &e); + + emit q->changed(); +} + +#ifndef QT_NO_SHORTCUT +void QActionPrivate::redoGrab(QShortcutMap &map) +{ + Q_Q(QAction); + if (shortcutId) + map.removeShortcut(shortcutId, q); + if (shortcut.isEmpty()) + return; + shortcutId = map.addShortcut(q, shortcut, shortcutContext); + if (!enabled) + map.setShortcutEnabled(false, shortcutId, q); + if (!autorepeat) + map.setShortcutAutoRepeat(false, shortcutId, q); +} + +void QActionPrivate::redoGrabAlternate(QShortcutMap &map) +{ + Q_Q(QAction); + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) + map.removeShortcut(id, q); + } + alternateShortcutIds.clear(); + if (alternateShortcuts.isEmpty()) + return; + for(int i = 0; i < alternateShortcuts.count(); ++i) { + const QKeySequence& alternate = alternateShortcuts.at(i); + if (!alternate.isEmpty()) + alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext)); + else + alternateShortcutIds.append(0); + } + if (!enabled) { + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); + map.setShortcutEnabled(false, id, q); + } + } + if (!autorepeat) { + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); + map.setShortcutAutoRepeat(false, id, q); + } + } +} + +void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) +{ + Q_Q(QAction); + if (shortcutId) + map.setShortcutEnabled(enable, shortcutId, q); + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) + map.setShortcutEnabled(enable, id, q); + } +} +#endif // QT_NO_SHORTCUT + + +/*! + \class QAction + \brief The QAction class provides an abstract user interface + action that can be inserted into widgets. + + \ingroup mainwindow-classes + + + \omit + * parent and widget are different + * parent does not define context + \endomit + + In applications many common commands can be invoked via menus, + toolbar buttons, and keyboard shortcuts. Since the user expects + each command to be performed in the same way, regardless of the + user interface used, it is useful to represent each command as + an \e action. + + Actions can be added to menus and toolbars, and will + automatically keep them in sync. For example, in a word processor, + if the user presses a Bold toolbar button, the Bold menu item + will automatically be checked. + + Actions can be created as independent objects, but they may + also be created during the construction of menus; the QMenu class + contains convenience functions for creating actions suitable for + use as menu items. + + A QAction may contain an icon, menu text, a shortcut, status text, + "What's This?" text, and a tooltip. Most of these can be set in + the constructor. They can also be set independently with + setIcon(), setText(), setIconText(), setShortcut(), + setStatusTip(), setWhatsThis(), and setToolTip(). For menu items, + it is possible to set an individual font with setFont(). + + Actions are added to widgets using QWidget::addAction() or + QGraphicsWidget::addAction(). Note that an action must be added to a + widget before it can be used; this is also true when the shortcut should + be global (i.e., Qt::ApplicationShortcut as Qt::ShortcutContext). + + Once a QAction has been created it should be added to the relevant + menu and toolbar, then connected to the slot which will perform + the action. For example: + + \snippet examples/mainwindows/application/mainwindow.cpp 19 + \codeline + \snippet examples/mainwindows/application/mainwindow.cpp 28 + \snippet examples/mainwindows/application/mainwindow.cpp 31 + + We recommend that actions are created as children of the window + they are used in. In most cases actions will be children of + the application's main window. + + \sa QMenu, QToolBar, {Application Example} +*/ + +/*! + \fn void QAction::trigger() + + This is a convenience slot that calls activate(Trigger). +*/ + +/*! + \fn void QAction::hover() + + This is a convenience slot that calls activate(Hover). +*/ + +/*! + \enum QAction::MenuRole + + This enum describes how an action should be moved into the application menu on Mac OS X. + + \value NoRole This action should not be put into the application menu + \value TextHeuristicRole This action should be put in the application menu based on the action's text + as described in the QMenuBar documentation. + \value ApplicationSpecificRole This action should be put in the application menu with an application specific role + \value AboutQtRole This action matches handles the "About Qt" menu item. + \value AboutRole This action should be placed where the "About" menu item is in the application menu. The text of + the menu item will be set to "About ". The application name is fetched from the + \c{Info.plist} file in the application's bundle (See \l{Deploying an Application on Mac OS X}). + \value PreferencesRole This action should be placed where the "Preferences..." menu item is in the application menu. + \value QuitRole This action should be placed where the Quit menu item is in the application menu. + + Setting this value only has effect on items that are in the immediate menus + of the menubar, not the submenus of those menus. For example, if you have + File menu in your menubar and the File menu has a submenu, setting the + MenuRole for the actions in that submenu have no effect. They will never be moved. +*/ + +/*! \since 4.6 + + \enum QAction::SoftKeyRole + + This enum describes how an action should be placed in the softkey bar. Currently this enum only + has an effect on the Symbian platform. + + \value NoSoftKey This action should not be used as a softkey + \value PositiveSoftKey This action is used to describe a softkey with a positive or non-destructive + role such as Ok, Select, or Options. + \value NegativeSoftKey This action is used to describe a soft ey with a negative or destructive role + role such as Cancel, Discard, or Close. + \value SelectSoftKey This action is used to describe a role that selects a particular item or widget + in the application. + + Actions with a softkey role defined are only visible in the softkey bar when the widget containing + the action has focus. If no widget currently has focus, the softkey framework will traverse up the + widget parent hierarchy looking for a widget containing softkey actions. + */ + +/*! + Constructs an action with \a parent. If \a parent is an action + group the action will be automatically inserted into the group. +*/ +QAction::QAction(QObject* parent) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + + +/*! + Constructs an action with some \a text and \a parent. If \a + parent is an action group the action will be automatically + inserted into the group. + + The action uses a stripped version of \a text (e.g. "\&Menu + Option..." becomes "Menu Option") as descriptive text for + tool buttons. You can override this by setting a specific + description with setText(). The same text will be used for + tooltips unless you specify a different text using + setToolTip(). + +*/ +QAction::QAction(const QString &text, QObject* parent) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + d->text = text; + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + +/*! + Constructs an action with an \a icon and some \a text and \a + parent. If \a parent is an action group the action will be + automatically inserted into the group. + + The action uses a stripped version of \a text (e.g. "\&Menu + Option..." becomes "Menu Option") as descriptive text for + tool buttons. You can override this by setting a specific + description with setText(). The same text will be used for + tooltips unless you specify a different text using + setToolTip(). +*/ +QAction::QAction(const QIcon &icon, const QString &text, QObject* parent) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + d->icon = icon; + d->text = text; + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + +/*! + \internal +*/ +QAction::QAction(QActionPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QAction); + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + +/*! + Returns the parent widget. +*/ +QWidget *QAction::parentWidget() const +{ + QObject *ret = parent(); + while (ret && !ret->isWidgetType()) + ret = ret->parent(); + return (QWidget*)ret; +} + +/*! + \since 4.2 + Returns a list of widgets this action has been added to. + + \sa QWidget::addAction(), associatedGraphicsWidgets() +*/ +QList QAction::associatedWidgets() const +{ + Q_D(const QAction); + return d->widgets; +} + +#ifndef QT_NO_GRAPHICSVIEW +/*! + \since 4.5 + Returns a list of widgets this action has been added to. + + \sa QWidget::addAction(), associatedWidgets() +*/ +QList QAction::associatedGraphicsWidgets() const +{ + Q_D(const QAction); + return d->graphicsWidgets; +} +#endif + +#ifndef QT_NO_SHORTCUT +/*! + \property QAction::shortcut + \brief the action's primary shortcut key + + Valid keycodes for this property can be found in \l Qt::Key and + \l Qt::Modifier. There is no default shortcut key. +*/ +void QAction::setShortcut(const QKeySequence &shortcut) +{ + QAPP_CHECK("setShortcut"); + + Q_D(QAction); + if (d->shortcut == shortcut) + return; + + d->shortcut = shortcut; + d->redoGrab(qApp->d_func()->shortcutMap); + d->sendDataChanged(); +} + +/*! + \since 4.2 + + Sets \a shortcuts as the list of shortcuts that trigger the + action. The first element of the list is the primary shortcut. + + \sa shortcut +*/ +void QAction::setShortcuts(const QList &shortcuts) +{ + Q_D(QAction); + + QList listCopy = shortcuts; + + QKeySequence primary; + if (!listCopy.isEmpty()) + primary = listCopy.takeFirst(); + + if (d->shortcut == primary && d->alternateShortcuts == listCopy) + return; + + QAPP_CHECK("setShortcuts"); + + d->shortcut = primary; + d->alternateShortcuts = listCopy; + d->redoGrab(qApp->d_func()->shortcutMap); + d->redoGrabAlternate(qApp->d_func()->shortcutMap); + d->sendDataChanged(); +} + +/*! + \since 4.2 + + Sets a platform dependent list of shortcuts based on the \a key. + The result of calling this function will depend on the currently running platform. + Note that more than one shortcut can assigned by this action. + If only the primary shortcut is required, use setShortcut instead. + + \sa QKeySequence::keyBindings() +*/ +void QAction::setShortcuts(QKeySequence::StandardKey key) +{ + QList list = QKeySequence::keyBindings(key); + setShortcuts(list); +} + +/*! + Returns the primary shortcut. + + \sa setShortcuts() +*/ +QKeySequence QAction::shortcut() const +{ + Q_D(const QAction); + return d->shortcut; +} + +/*! + \since 4.2 + + Returns the list of shortcuts, with the primary shortcut as + the first element of the list. + + \sa setShortcuts() +*/ +QList QAction::shortcuts() const +{ + Q_D(const QAction); + QList shortcuts; + if (!d->shortcut.isEmpty()) + shortcuts << d->shortcut; + if (!d->alternateShortcuts.isEmpty()) + shortcuts << d->alternateShortcuts; + return shortcuts; +} + +/*! + \property QAction::shortcutContext + \brief the context for the action's shortcut + + Valid values for this property can be found in \l Qt::ShortcutContext. + The default value is Qt::WindowShortcut. +*/ +void QAction::setShortcutContext(Qt::ShortcutContext context) +{ + Q_D(QAction); + if (d->shortcutContext == context) + return; + QAPP_CHECK("setShortcutContext"); + d->shortcutContext = context; + d->redoGrab(qApp->d_func()->shortcutMap); + d->redoGrabAlternate(qApp->d_func()->shortcutMap); + d->sendDataChanged(); +} + +Qt::ShortcutContext QAction::shortcutContext() const +{ + Q_D(const QAction); + return d->shortcutContext; +} + +/*! + \property QAction::autoRepeat + \brief whether the action can auto repeat + \since 4.2 + + If true, the action will auto repeat when the keyboard shortcut + combination is held down, provided that keyboard auto repeat is + enabled on the system. + The default value is true. +*/ +void QAction::setAutoRepeat(bool on) +{ + Q_D(QAction); + if (d->autorepeat == on) + return; + QAPP_CHECK("setAutoRepeat"); + d->autorepeat = on; + d->redoGrab(qApp->d_func()->shortcutMap); + d->redoGrabAlternate(qApp->d_func()->shortcutMap); + d->sendDataChanged(); +} + +bool QAction::autoRepeat() const +{ + Q_D(const QAction); + return d->autorepeat; +} +#endif // QT_NO_SHORTCUT + +/*! + \property QAction::font + \brief the action's font + + The font property is used to render the text set on the + QAction. The font will can be considered a hint as it will not be + consulted in all cases based upon application and style. + + By default, this property contains the application's default font. + + \sa QAction::setText() QStyle +*/ +void QAction::setFont(const QFont &font) +{ + Q_D(QAction); + if (d->font == font) + return; + + d->fontSet = true; + d->font = font; + d->sendDataChanged(); +} + +QFont QAction::font() const +{ + Q_D(const QAction); + return d->font; +} + +#ifdef QT3_SUPPORT +/*! + Use one of the QAction constructors that doesn't take a \a name + argument and call setObjectName() instead. +*/ +QAction::QAction(QObject* parent, const char* name) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + setObjectName(QString::fromAscii(name)); + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + + +/*! + Use one of the QAction constructors that doesn't take a \a name + argument and call setObjectName() instead. +*/ +QAction::QAction(const QString &text, const QKeySequence &shortcut, QObject* parent, const char* name) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + setObjectName(QString::fromAscii(name)); + d->text = text; + setShortcut(shortcut); + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} + +/*! + Use one of the QAction constructors that doesn't take a \a name + argument and call setObjectName() instead. +*/ +QAction::QAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, + QObject* parent, const char* name) + : QObject(*(new QActionPrivate), parent) +{ + Q_D(QAction); + setObjectName(QString::fromAscii(name)); + d->text = text; + setShortcut(shortcut); + d->icon = icon; + d->group = qobject_cast(parent); + if (d->group) + d->group->addAction(this); +} +#endif + +/*! + Destroys the object and frees allocated resources. +*/ +QAction::~QAction() +{ + Q_D(QAction); + for (int i = d->widgets.size()-1; i >= 0; --i) { + QWidget *w = d->widgets.at(i); + w->removeAction(this); + } +#ifndef QT_NO_GRAPHICSVIEW + for (int i = d->graphicsWidgets.size()-1; i >= 0; --i) { + QGraphicsWidget *w = d->graphicsWidgets.at(i); + w->removeAction(this); + } +#endif + if (d->group) + d->group->removeAction(this); +#ifndef QT_NO_SHORTCUT + if (d->shortcutId && qApp) { + qApp->d_func()->shortcutMap.removeShortcut(d->shortcutId, this); + for(int i = 0; i < d->alternateShortcutIds.count(); ++i) { + const int id = d->alternateShortcutIds.at(i); + qApp->d_func()->shortcutMap.removeShortcut(id, this); + } + } +#endif +} + +/*! + Sets this action group to \a group. The action will be automatically + added to the group's list of actions. + + Actions within the group will be mutually exclusive. + + \sa QActionGroup, QAction::actionGroup() +*/ +void QAction::setActionGroup(QActionGroup *group) +{ + Q_D(QAction); + if(group == d->group) + return; + + if(d->group) + d->group->removeAction(this); + d->group = group; + if(group) + group->addAction(this); +} + +/*! + Returns the action group for this action. If no action group manages + this action then 0 will be returned. + + \sa QActionGroup, QAction::setActionGroup() +*/ +QActionGroup *QAction::actionGroup() const +{ + Q_D(const QAction); + return d->group; +} + + +/*! + \property QAction::icon + \brief the action's icon + + In toolbars, the icon is used as the tool button icon; in menus, + it is displayed to the left of the menu text. There is no default + icon. + + On Symbian the icons which are passed to softkeys, i.e. to actions with + softkey role, need to have pixmap alpha channel correctly set otherwise + drawing artifacts will appear when softkey is pressed down. + + If a null icon (QIcon::isNull() is passed into this function, + the icon of the action is cleared. +*/ +void QAction::setIcon(const QIcon &icon) +{ + Q_D(QAction); + d->icon = icon; + d->sendDataChanged(); +} + +QIcon QAction::icon() const +{ + Q_D(const QAction); + return d->icon; +} + +#ifndef QT_NO_MENU +/*! + Returns the menu contained by this action. Actions that contain + menus can be used to create menu items with submenus, or inserted + into toolbars to create buttons with popup menus. + + \sa QMenu::addAction() +*/ +QMenu *QAction::menu() const +{ + Q_D(const QAction); + return d->menu; +} + +/*! + Sets the menu contained by this action to the specified \a menu. +*/ +void QAction::setMenu(QMenu *menu) +{ + Q_D(QAction); + if (d->menu) + d->menu->d_func()->setOverrideMenuAction(0); //we reset the default action of any previous menu + d->menu = menu; + if (menu) + menu->d_func()->setOverrideMenuAction(this); + d->sendDataChanged(); +} +#endif // QT_NO_MENU + +/*! + If \a b is true then this action will be considered a separator. + + How a separator is represented depends on the widget it is inserted + into. Under most circumstances the text, submenu, and icon will be + ignored for separator actions. + + \sa QAction::isSeparator() +*/ +void QAction::setSeparator(bool b) +{ + Q_D(QAction); + if (d->separator == b) + return; + + d->separator = b; + d->sendDataChanged(); +} + +/*! + Returns true if this action is a separator action; otherwise it + returns false. + + \sa QAction::setSeparator() +*/ +bool QAction::isSeparator() const +{ + Q_D(const QAction); + return d->separator; +} + +/*! + \property QAction::text + \brief the action's descriptive text + + If the action is added to a menu, the menu option will consist of + the icon (if there is one), the text, and the shortcut (if there + is one). If the text is not explicitly set in the constructor, or + by using setText(), the action's description icon text will be + used as text. There is no default text. + + \sa iconText +*/ +void QAction::setText(const QString &text) +{ + Q_D(QAction); + if (d->text == text) + return; + + d->text = text; + d->sendDataChanged(); +} + +QString QAction::text() const +{ + Q_D(const QAction); + QString s = d->text; + if(s.isEmpty()) { + s = d->iconText; + s.replace(QLatin1Char('&'), QLatin1String("&&")); + } + return s; +} + + + + + +/*! + \property QAction::iconText + \brief the action's descriptive icon text + + If QToolBar::toolButtonStyle is set to a value that permits text to + be displayed, the text defined held in this property appears as a + label in the relevant tool button. + + It also serves as the default text in menus and tooltips if the action + has not been defined with setText() or setToolTip(), and will + also be used in toolbar buttons if no icon has been defined using setIcon(). + + If the icon text is not explicitly set, the action's normal text will be + used for the icon text. + + By default, this property contains an empty string. + + \sa setToolTip(), setStatusTip() +*/ +void QAction::setIconText(const QString &text) +{ + Q_D(QAction); + if (d->iconText == text) + return; + + d->iconText = text; + d->sendDataChanged(); +} + +QString QAction::iconText() const +{ + Q_D(const QAction); + if (d->iconText.isEmpty()) + return qt_strippedText(d->text); + return d->iconText; +} + +/*! + \property QAction::toolTip + \brief the action's tooltip + + This text is used for the tooltip. If no tooltip is specified, + the action's text is used. + + By default, this property contains the action's text. + + \sa setStatusTip() setShortcut() +*/ +void QAction::setToolTip(const QString &tooltip) +{ + Q_D(QAction); + if (d->tooltip == tooltip) + return; + + d->tooltip = tooltip; + d->sendDataChanged(); +} + +QString QAction::toolTip() const +{ + Q_D(const QAction); + if (d->tooltip.isEmpty()) { + if (!d->text.isEmpty()) + return qt_strippedText(d->text); + return qt_strippedText(d->iconText); + } + return d->tooltip; +} + +/*! + \property QAction::statusTip + \brief the action's status tip + + The status tip is displayed on all status bars provided by the + action's top-level parent widget. + + By default, this property contains an empty string. + + \sa setToolTip() showStatusText() +*/ +void QAction::setStatusTip(const QString &statustip) +{ + Q_D(QAction); + if (d->statustip == statustip) + return; + + d->statustip = statustip; + d->sendDataChanged(); +} + +QString QAction::statusTip() const +{ + Q_D(const QAction); + return d->statustip; +} + +/*! + \property QAction::whatsThis + \brief the action's "What's This?" help text + + The "What's This?" text is used to provide a brief description of + the action. The text may contain rich text. There is no default + "What's This?" text. + + \sa QWhatsThis Q3StyleSheet +*/ +void QAction::setWhatsThis(const QString &whatsthis) +{ + Q_D(QAction); + if (d->whatsthis == whatsthis) + return; + + d->whatsthis = whatsthis; + d->sendDataChanged(); +} + +QString QAction::whatsThis() const +{ + Q_D(const QAction); + return d->whatsthis; +} + +/*! + \enum QAction::Priority + \since 4.6 + + This enum defines priorities for actions in user interface. + + \value LowPriority The action should not be prioritized in + the user interface. + + \value NormalPriority + + \value HighPriority The action should be prioritized in + the user interface. + + \sa priority +*/ + + +/*! + \property QAction::priority + \since 4.6 + + \brief the actions's priority in the user interface. + + This property can be set to indicate how the action should be prioritized + in the user interface. + + For instance, when toolbars have the Qt::ToolButtonTextBesideIcon + mode set, then actions with LowPriority will not show the text + labels. +*/ +void QAction::setPriority(Priority priority) +{ + Q_D(QAction); + if (d->priority == priority) + return; + + d->priority = priority; + d->sendDataChanged(); +} + +QAction::Priority QAction::priority() const +{ + Q_D(const QAction); + return d->priority; +} + +/*! + \property QAction::checkable + \brief whether the action is a checkable action + + A checkable action is one which has an on/off state. For example, + in a word processor, a Bold toolbar button may be either on or + off. An action which is not a toggle action is a command action; + a command action is simply executed, e.g. file save. + By default, this property is false. + + In some situations, the state of one toggle action should depend + on the state of others. For example, "Left Align", "Center" and + "Right Align" toggle actions are mutually exclusive. To achieve + exclusive toggling, add the relevant toggle actions to a + QActionGroup with the QActionGroup::exclusive property set to + true. + + \sa QAction::setChecked() +*/ +void QAction::setCheckable(bool b) +{ + Q_D(QAction); + if (d->checkable == b) + return; + + d->checkable = b; + d->checked = false; + d->sendDataChanged(); +} + +bool QAction::isCheckable() const +{ + Q_D(const QAction); + return d->checkable; +} + +/*! + \fn void QAction::toggle() + + This is a convenience function for the \l checked property. + Connect to it to change the checked state to its opposite state. +*/ +void QAction::toggle() +{ + Q_D(QAction); + setChecked(!d->checked); +} + +/*! + \property QAction::checked + \brief whether the action is checked. + + Only checkable actions can be checked. By default, this is false + (the action is unchecked). + + \sa checkable +*/ +void QAction::setChecked(bool b) +{ + Q_D(QAction); + if (!d->checkable || d->checked == b) + return; + + QPointer guard(this); + d->checked = b; + d->sendDataChanged(); + if (guard) + emit toggled(b); +} + +bool QAction::isChecked() const +{ + Q_D(const QAction); + return d->checked; +} + +/*! + \fn void QAction::setDisabled(bool b) + + This is a convenience function for the \l enabled property, that + is useful for signals--slots connections. If \a b is true the + action is disabled; otherwise it is enabled. +*/ + +/*! + \property QAction::enabled + \brief whether the action is enabled + + Disabled actions cannot be chosen by the user. They do not + disappear from menus or toolbars, but they are displayed in a way + which indicates that they are unavailable. For example, they might + be displayed using only shades of gray. + + \gui{What's This?} help on disabled actions is still available, provided + that the QAction::whatsThis property is set. + + An action will be disabled when all widgets to which it is added + (with QWidget::addAction()) are disabled or not visible. When an + action is disabled, it is not possible to trigger it through its + shortcut. + + By default, this property is true (actions are enabled). + + \sa text +*/ +void QAction::setEnabled(bool b) +{ + Q_D(QAction); + if (b == d->enabled && b != d->forceDisabled) + return; + d->forceDisabled = !b; + if (b && (!d->visible || (d->group && !d->group->isEnabled()))) + return; + QAPP_CHECK("setEnabled"); + d->enabled = b; +#ifndef QT_NO_SHORTCUT + d->setShortcutEnabled(b, qApp->d_func()->shortcutMap); +#endif + d->sendDataChanged(); +} + +bool QAction::isEnabled() const +{ + Q_D(const QAction); + return d->enabled; +} + +/*! + \property QAction::visible + \brief whether the action can be seen (e.g. in menus and toolbars) + + If \e visible is true the action can be seen (e.g. in menus and + toolbars) and chosen by the user; if \e visible is false the + action cannot be seen or chosen by the user. + + Actions which are not visible are \e not grayed out; they do not + appear at all. + + By default, this property is true (actions are visible). +*/ +void QAction::setVisible(bool b) +{ + Q_D(QAction); + if (b == d->visible && b != d->forceInvisible) + return; + QAPP_CHECK("setVisible"); + d->forceInvisible = !b; + d->visible = b; + d->enabled = b && !d->forceDisabled && (!d->group || d->group->isEnabled()) ; +#ifndef QT_NO_SHORTCUT + d->setShortcutEnabled(d->enabled, qApp->d_func()->shortcutMap); +#endif + d->sendDataChanged(); +} + + +bool QAction::isVisible() const +{ + Q_D(const QAction); + return d->visible; +} + +/*! + \reimp +*/ +bool +QAction::event(QEvent *e) +{ +#ifndef QT_NO_SHORTCUT + if (e->type() == QEvent::Shortcut) { + QShortcutEvent *se = static_cast(e); + Q_ASSERT_X(se->key() == d_func()->shortcut || d_func()->alternateShortcuts.contains(se->key()), + "QAction::event", + "Received shortcut event from incorrect shortcut"); + if (se->isAmbiguous()) + qWarning("QAction::eventFilter: Ambiguous shortcut overload: %s", QString(se->key()).toLatin1().constData()); + else + activate(Trigger); + return true; + } +#endif + return QObject::event(e); +} + +/*! + Returns the user data as set in QAction::setData. + + \sa setData() +*/ +QVariant +QAction::data() const +{ + Q_D(const QAction); + return d->userData; +} + +/*! + \fn void QAction::setData(const QVariant &userData) + + Sets the action's internal data to the given \a userData. + + \sa data() +*/ +void +QAction::setData(const QVariant &data) +{ + Q_D(QAction); + d->userData = data; + d->sendDataChanged(); +} + + +/*! + Updates the relevant status bar for the \a widget specified by sending a + QStatusTipEvent to its parent widget. Returns true if an event was sent; + otherwise returns false. + + If a null widget is specified, the event is sent to the action's parent. + + \sa statusTip +*/ +bool +QAction::showStatusText(QWidget *widget) +{ + return d_func()->showStatusText(widget, statusTip()); +} + +/*! + Sends the relevant signals for ActionEvent \a event. + + Action based widgets use this API to cause the QAction + to emit signals as well as emitting their own. +*/ +void QAction::activate(ActionEvent event) +{ + Q_D(QAction); + if(event == Trigger) { + QObject *guard = this; + QMetaObject::addGuard(&guard); + if(d->checkable) { + // the checked action of an exclusive group cannot be unchecked + if (d->checked && (d->group && d->group->isExclusive() + && d->group->checkedAction() == this)) { + if (guard) + emit triggered(true); + QMetaObject::removeGuard(&guard); + return; + } + setChecked(!d->checked); + } + if (guard) + emit triggered(d->checked); +#ifdef QT3_SUPPORT + if (guard) + emit activated(d->param); +#endif + QMetaObject::removeGuard(&guard); + } else if(event == Hover) { + emit hovered(); + } +} + +/*! + \fn void QAction::triggered(bool checked) + + This signal is emitted when an action is activated by the user; + for example, when the user clicks a menu option, toolbar button, + or presses an action's shortcut key combination, or when trigger() + was called. Notably, it is \e not emitted when setChecked() or + toggle() is called. + + If the action is checkable, \a checked is true if the action is + checked, or false if the action is unchecked. + + \sa QAction::activate(), QAction::toggled(), checked +*/ + +/*! + \fn void QAction::toggled(bool checked) + + This signal is emitted whenever a checkable action changes its + isChecked() status. This can be the result of a user interaction, + or because setChecked() was called. + + \a checked is true if the action is checked, or false if the + action is unchecked. + + \sa QAction::activate(), QAction::triggered(), checked +*/ + +/*! + \fn void QAction::hovered() + + This signal is emitted when an action is highlighted by the user; + for example, when the user pauses with the cursor over a menu option, + toolbar button, or presses an action's shortcut key combination. + + \sa QAction::activate() +*/ + +/*! + \fn void QAction::changed() + + This signal is emitted when an action has changed. If you + are only interested in actions in a given widget, you can + watch for QWidget::actionEvent() sent with an + QEvent::ActionChanged. + + \sa QWidget::actionEvent() +*/ + +/*! + \enum QAction::ActionEvent + + This enum type is used when calling QAction::activate() + + \value Trigger this will cause the QAction::triggered() signal to be emitted. + + \value Hover this will cause the QAction::hovered() signal to be emitted. +*/ + +/*! + \fn void QAction::setMenuText(const QString &text) + + Use setText() instead. +*/ + +/*! + \fn QString QAction::menuText() const + + Use text() instead. +*/ + +/*! + \fn bool QAction::isOn() const + + Use isChecked() instead. +*/ + +/*! + \fn void QAction::setOn(bool b) + + Use setChecked() instead. +*/ + +/*! + \fn bool QAction::isToggleAction() const + + Use isCheckable() instead. +*/ + +/*! + \fn void QAction::setToggleAction(bool b) + + Use setCheckable() instead. +*/ + +/*! + \fn void QAction::setIconSet(const QIcon &i) + + Use setIcon() instead. +*/ + +/*! + \fn bool QAction::addTo(QWidget *w) + + Use QWidget::addAction() instead. + + \oldcode + action->addTo(widget); + \newcode + widget->addAction(action); + \endcode +*/ + +/*! + \fn bool QAction::removeFrom(QWidget *w) + + Use QWidget::removeAction() instead. + + \oldcode + action->removeFrom(widget); + \newcode + widget->removeAction(action); + \endcode +*/ + +/*! + \fn void QAction::setAccel(const QKeySequence &shortcut) + + Use setShortcut() instead. +*/ + +/*! + \fn QIcon QAction::iconSet() const + + Use icon() instead. +*/ + +/*! + \fn QKeySequence QAction::accel() const + + Use shortcut() instead. +*/ + +/*! + \fn void QAction::activated(int i); + + Use triggered() instead. +*/ + + +/*! + \property QAction::menuRole + \brief the action's menu role + \since 4.2 + + This indicates what role the action serves in the application menu on Mac + OS X. By default all action have the TextHeuristicRole, which means that + the action is added based on its text (see QMenuBar for more information). + + The menu role can only be changed before the actions are put into the menu + bar in Mac OS X (usually just before the first application window is + shown). +*/ +void QAction::setMenuRole(MenuRole menuRole) +{ + Q_D(QAction); + if (d->menuRole == menuRole) + return; + + d->menuRole = menuRole; + d->sendDataChanged(); +} + +QAction::MenuRole QAction::menuRole() const +{ + Q_D(const QAction); + return d->menuRole; +} + +/*! + \property QAction::softKeyRole + \brief the action's softkey role + \since 4.6 + + This indicates what type of role this action describes in the softkey framework + on platforms where such a framework is supported. Currently this is only + supported on the Symbian platform. + + The softkey role can be changed any time. +*/ +void QAction::setSoftKeyRole(SoftKeyRole softKeyRole) +{ + Q_D(QAction); + if (d->softKeyRole == softKeyRole) + return; + + d->softKeyRole = softKeyRole; + d->sendDataChanged(); +} + +QAction::SoftKeyRole QAction::softKeyRole() const +{ + Q_D(const QAction); + return d->softKeyRole; +} + +/*! + \property QAction::iconVisibleInMenu + \brief Whether or not an action should show an icon in a menu + \since 4.4 + + In some applications, it may make sense to have actions with icons in the + toolbar, but not in menus. If true, the icon (if valid) is shown in the menu, when it + is false, it is not shown. + + The default is to follow whether the Qt::AA_DontShowIconsInMenus attribute + is set for the application. Explicitly settings this property overrides + the presence (or abscence) of the attribute. + + For example: + \snippet doc/src/snippets/code/src_gui_kernel_qaction.cpp 0 + + \sa QAction::icon QApplication::setAttribute() +*/ +void QAction::setIconVisibleInMenu(bool visible) +{ + Q_D(QAction); + if (d->iconVisibleInMenu == -1 || visible != bool(d->iconVisibleInMenu)) { + int oldValue = d->iconVisibleInMenu; + d->iconVisibleInMenu = visible; + // Only send data changed if we really need to. + if (oldValue != -1 + || (oldValue == -1 + && visible == !QApplication::instance()->testAttribute(Qt::AA_DontShowIconsInMenus))) { + d->sendDataChanged(); + } + } +} + +bool QAction::isIconVisibleInMenu() const +{ + Q_D(const QAction); + if (d->iconVisibleInMenu == -1) { + return !QApplication::instance()->testAttribute(Qt::AA_DontShowIconsInMenus); + } + return d->iconVisibleInMenu; +} + +QT_END_NAMESPACE + +#include "moc_qaction.cpp" + +#endif // QT_NO_ACTION diff --git a/src/widgets/kernel/qaction.h b/src/widgets/kernel/qaction.h new file mode 100644 index 0000000000..856fd92f10 --- /dev/null +++ b/src/widgets/kernel/qaction.h @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACTION_H +#define QACTION_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_ACTION + +class QMenu; +class QActionGroup; +class QActionPrivate; +class QGraphicsWidget; + +class Q_GUI_EXPORT QAction : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QAction) + + Q_ENUMS(MenuRole) + Q_ENUMS(SoftKeyRole) + Q_ENUMS(Priority) + Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed) + Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY changed) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY changed) + Q_PROPERTY(QString iconText READ iconText WRITE setIconText NOTIFY changed) + Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY changed) + Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip NOTIFY changed) + Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis NOTIFY changed) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed) +#ifndef QT_NO_SHORTCUT + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut NOTIFY changed) + Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext NOTIFY changed) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY changed) +#endif + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed) + Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed) + Q_PROPERTY(SoftKeyRole softKeyRole READ softKeyRole WRITE setSoftKeyRole NOTIFY changed) + Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed) + Q_PROPERTY(Priority priority READ priority WRITE setPriority) + +public: + enum MenuRole { NoRole, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, + AboutRole, PreferencesRole, QuitRole }; + enum SoftKeyRole { + NoSoftKey, PositiveSoftKey, NegativeSoftKey, SelectSoftKey }; + enum Priority { LowPriority = 0, + NormalPriority = 128, + HighPriority = 256}; + explicit QAction(QObject* parent); + QAction(const QString &text, QObject* parent); + QAction(const QIcon &icon, const QString &text, QObject* parent); + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QAction(QObject* parent, const char* name); + QT3_SUPPORT_CONSTRUCTOR QAction(const QString &text, const QKeySequence &shortcut, + QObject* parent, const char* name); + QT3_SUPPORT_CONSTRUCTOR QAction(const QIcon &icon, const QString &text, + const QKeySequence &shortcut, + QObject* parent, const char* name); +#endif + ~QAction(); + + void setActionGroup(QActionGroup *group); + QActionGroup *actionGroup() const; + void setIcon(const QIcon &icon); + QIcon icon() const; + + void setText(const QString &text); + QString text() const; + + void setIconText(const QString &text); + QString iconText() const; + + void setToolTip(const QString &tip); + QString toolTip() const; + + void setStatusTip(const QString &statusTip); + QString statusTip() const; + + void setWhatsThis(const QString &what); + QString whatsThis() const; + + void setPriority(Priority priority); + Priority priority() const; + +#ifndef QT_NO_MENU + QMenu *menu() const; + void setMenu(QMenu *menu); +#endif + + void setSeparator(bool b); + bool isSeparator() const; + +#ifndef QT_NO_SHORTCUT + void setShortcut(const QKeySequence &shortcut); + QKeySequence shortcut() const; + + void setShortcuts(const QList &shortcuts); + void setShortcuts(QKeySequence::StandardKey); + QList shortcuts() const; + + void setShortcutContext(Qt::ShortcutContext context); + Qt::ShortcutContext shortcutContext() const; + + void setAutoRepeat(bool); + bool autoRepeat() const; +#endif + + void setFont(const QFont &font); + QFont font() const; + + void setCheckable(bool); + bool isCheckable() const; + + QVariant data() const; + void setData(const QVariant &var); + + bool isChecked() const; + + bool isEnabled() const; + + bool isVisible() const; + + enum ActionEvent { Trigger, Hover }; + void activate(ActionEvent event); + bool showStatusText(QWidget *widget=0); + + void setMenuRole(MenuRole menuRole); + MenuRole menuRole() const; + + void setSoftKeyRole(SoftKeyRole softKeyRole); + SoftKeyRole softKeyRole() const; + + void setIconVisibleInMenu(bool visible); + bool isIconVisibleInMenu() const; + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT void setMenuText(const QString &text) { setText(text); } + inline QT3_SUPPORT QString menuText() const { return text(); } + inline QT3_SUPPORT bool isOn() const { return isChecked(); } + inline QT3_SUPPORT bool isToggleAction() const { return isCheckable(); } + inline QT3_SUPPORT void setToggleAction(bool b) { setCheckable(b); } + inline QT3_SUPPORT void setIconSet(const QIcon &i) { setIcon(i); } + inline QT3_SUPPORT QIcon iconSet() const { return icon(); } + inline QT3_SUPPORT bool addTo(QWidget *w) { w->addAction(this); return true; } + inline QT3_SUPPORT bool removeFrom(QWidget *w) { w->removeAction(this); return true; } + inline QT3_SUPPORT void setAccel(const QKeySequence &shortcut) { setShortcut(shortcut); } + inline QT3_SUPPORT QKeySequence accel() const { return shortcut(); } +#endif + + QWidget *parentWidget() const; + + QList associatedWidgets() const; +#ifndef QT_NO_GRAPHICSVIEW + QList associatedGraphicsWidgets() const; // ### suboptimal +#endif + +protected: + bool event(QEvent *); + QAction(QActionPrivate &dd, QObject *parent); + +public Q_SLOTS: +#ifdef QT3_SUPPORT + inline QT_MOC_COMPAT void setOn(bool b) { setChecked(b); } +#endif + void trigger() { activate(Trigger); } + void hover() { activate(Hover); } + void setChecked(bool); + void toggle(); + void setEnabled(bool); + inline void setDisabled(bool b) { setEnabled(!b); } + void setVisible(bool); + +Q_SIGNALS: + void changed(); + void triggered(bool checked = false); + void hovered(); + void toggled(bool); +#ifdef QT3_SUPPORT + QT_MOC_COMPAT void activated(int = 0); +#endif + +private: + Q_DISABLE_COPY(QAction) + +#ifdef QT3_SUPPORT + friend class QMenuItem; +#endif + friend class QGraphicsWidget; + friend class QWidget; + friend class QActionGroup; + friend class QMenu; + friend class QMenuPrivate; + friend class QMenuBar; + friend class QShortcutMap; + friend class QToolButton; +#ifdef Q_WS_MAC + friend void qt_mac_clear_status_text(QAction *action); +#endif +}; + +QT_BEGIN_INCLUDE_NAMESPACE +#include +QT_END_INCLUDE_NAMESPACE + +#endif // QT_NO_ACTION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QACTION_H diff --git a/src/widgets/kernel/qaction_p.h b/src/widgets/kernel/qaction_p.h new file mode 100644 index 0000000000..f3154f90c1 --- /dev/null +++ b/src/widgets/kernel/qaction_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACTION_P_H +#define QACTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qaction.h" +#include "QtGui/qmenu.h" +#include "private/qgraphicswidget_p.h" +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACTION + +#ifdef QT3_SUPPORT +class QMenuItemEmitter; +#endif + +class QShortcutMap; + +class Q_AUTOTEST_EXPORT QActionPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QAction) +public: + QActionPrivate(); + ~QActionPrivate(); + + static QActionPrivate *get(QAction *q) + { + return q->d_func(); + } + + bool showStatusText(QWidget *w, const QString &str); + + QPointer group; + QString text; + QString iconText; + QIcon icon; + QString tooltip; + QString statustip; + QString whatsthis; +#ifndef QT_NO_SHORTCUT + QKeySequence shortcut; + QList alternateShortcuts; +#endif + QVariant userData; +#ifndef QT_NO_SHORTCUT + int shortcutId; + QList alternateShortcutIds; + Qt::ShortcutContext shortcutContext; + uint autorepeat : 1; +#endif + QFont font; + QPointer menu; + uint enabled : 1, forceDisabled : 1; + uint visible : 1, forceInvisible : 1; + uint checkable : 1; + uint checked : 1; + uint separator : 1; + uint fontSet : 1; + + //for soft keys management + uint forceEnabledInSoftkeys : 1; + uint menuActionSoftkeys : 1; + int iconVisibleInMenu : 3; // Only has values -1, 0, and 1 + + QAction::MenuRole menuRole; + QAction::SoftKeyRole softKeyRole; + QAction::Priority priority; + + QList widgets; +#ifndef QT_NO_GRAPHICSVIEW + QList graphicsWidgets; +#endif +#ifndef QT_NO_SHORTCUT + void redoGrab(QShortcutMap &map); + void redoGrabAlternate(QShortcutMap &map); + void setShortcutEnabled(bool enable, QShortcutMap &map); + + static QShortcutMap *globalMap; +#endif // QT_NO_SHORTCUT + +#ifdef QT3_SUPPORT //for menubar/menu compat + QMenuItemEmitter *act_signal; + int id, param; +#endif + void sendDataChanged(); +}; + +#endif // QT_NO_ACTION + +QT_END_NAMESPACE + +#endif // QACTION_P_H diff --git a/src/widgets/kernel/qactiongroup.cpp b/src/widgets/kernel/qactiongroup.cpp new file mode 100644 index 0000000000..95ea8afab7 --- /dev/null +++ b/src/widgets/kernel/qactiongroup.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qactiongroup.h" + +#ifndef QT_NO_ACTION + +#include "qaction_p.h" +#include "qapplication.h" +#include "qevent.h" +#include "qlist.h" + +QT_BEGIN_NAMESPACE + +class QActionGroupPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QActionGroup) +public: + QActionGroupPrivate() : exclusive(1), enabled(1), visible(1) { } + QList actions; + QPointer current; + uint exclusive : 1; + uint enabled : 1; + uint visible : 1; + +private: + void _q_actionTriggered(); //private slot + void _q_actionChanged(); //private slot + void _q_actionHovered(); //private slot +}; + +void QActionGroupPrivate::_q_actionChanged() +{ + Q_Q(QActionGroup); + QAction *action = qobject_cast(q->sender()); + Q_ASSERT_X(action != 0, "QWidgetGroup::_q_actionChanged", "internal error"); + if(exclusive) { + if (action->isChecked()) { + if (action != current) { + if(current) + current->setChecked(false); + current = action; + } + } else if (action == current) { + current = 0; + } + } +} + +void QActionGroupPrivate::_q_actionTriggered() +{ + Q_Q(QActionGroup); + QAction *action = qobject_cast(q->sender()); + Q_ASSERT_X(action != 0, "QWidgetGroup::_q_actionTriggered", "internal error"); + emit q->triggered(action); + emit q->selected(action); +} + +void QActionGroupPrivate::_q_actionHovered() +{ + Q_Q(QActionGroup); + QAction *action = qobject_cast(q->sender()); + Q_ASSERT_X(action != 0, "QWidgetGroup::_q_actionHovered", "internal error"); + emit q->hovered(action); +} + +/*! + \class QActionGroup + \brief The QActionGroup class groups actions together. + + \ingroup mainwindow-classes + + In some situations it is useful to group actions together. For + example, if you have a \gui{Left Align} action, a \gui{Right + Align} action, a \gui{Justify} action, and a \gui{Center} action, + only one of these actions should be active at any one time. One + simple way of achieving this is to group the actions together in + an action group. + + Here's a example (from the \l{mainwindows/menus}{Menus} example): + + \snippet examples/mainwindows/menus/mainwindow.cpp 6 + + Here we create a new action group. Since the action group is + exclusive by default, only one of the actions in the group is + checked at any one time. + + \img qactiongroup-align.png Alignment options in a QMenu + + A QActionGroup emits an triggered() signal when one of its + actions is chosen. Each action in an action group emits its + triggered() signal as usual. + + As stated above, an action group is \l exclusive by default; it + ensures that only one checkable action is active at any one time. + If you want to group checkable actions without making them + exclusive, you can turn of exclusiveness by calling + setExclusive(false). + + Actions can be added to an action group using addAction(), but it + is usually more convenient to specify a group when creating + actions; this ensures that actions are automatically created with + a parent. Actions can be visually separated from each other by + adding a separator action to the group; create an action and use + QAction's \l {QAction::}{setSeparator()} function to make it + considered a separator. Action groups are added to widgets with + the QWidget::addActions() function. + + \sa QAction +*/ + +/*! + Constructs an action group for the \a parent object. + + The action group is exclusive by default. Call setExclusive(false) + to make the action group non-exclusive. +*/ +QActionGroup::QActionGroup(QObject* parent) : QObject(*new QActionGroupPrivate, parent) +{ +} + +/*! + Destroys the action group. +*/ +QActionGroup::~QActionGroup() +{ +} + +/*! + \fn QAction *QActionGroup::addAction(QAction *action) + + Adds the \a action to this group, and returns it. + + Normally an action is added to a group by creating it with the + group as its parent, so this function is not usually used. + + \sa QAction::setActionGroup() +*/ +QAction *QActionGroup::addAction(QAction* a) +{ + Q_D(QActionGroup); + if(!d->actions.contains(a)) { + d->actions.append(a); + QObject::connect(a, SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); + QObject::connect(a, SIGNAL(changed()), this, SLOT(_q_actionChanged())); + QObject::connect(a, SIGNAL(hovered()), this, SLOT(_q_actionHovered())); + } + if(!a->d_func()->forceDisabled) { + a->setEnabled(d->enabled); + a->d_func()->forceDisabled = false; + } + if(!a->d_func()->forceInvisible) { + a->setVisible(d->visible); + a->d_func()->forceInvisible = false; + } + if(a->isChecked()) + d->current = a; + QActionGroup *oldGroup = a->d_func()->group; + if(oldGroup != this) { + if (oldGroup) + oldGroup->removeAction(a); + a->d_func()->group = this; + } + return a; +} + +/*! + Creates and returns an action with \a text. The newly created + action is a child of this action group. + + Normally an action is added to a group by creating it with the + group as parent, so this function is not usually used. + + \sa QAction::setActionGroup() +*/ +QAction *QActionGroup::addAction(const QString &text) +{ + return new QAction(text, this); +} + +/*! + Creates and returns an action with \a text and an \a icon. The + newly created action is a child of this action group. + + Normally an action is added to a group by creating it with the + group as its parent, so this function is not usually used. + + \sa QAction::setActionGroup() +*/ +QAction *QActionGroup::addAction(const QIcon &icon, const QString &text) +{ + return new QAction(icon, text, this); +} + +/*! + Removes the \a action from this group. The action will have no + parent as a result. + + \sa QAction::setActionGroup() +*/ +void QActionGroup::removeAction(QAction *action) +{ + Q_D(QActionGroup); + if (d->actions.removeAll(action)) { + if (action == d->current) + d->current = 0; + QObject::disconnect(action, SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); + QObject::disconnect(action, SIGNAL(changed()), this, SLOT(_q_actionChanged())); + QObject::disconnect(action, SIGNAL(hovered()), this, SLOT(_q_actionHovered())); + action->d_func()->group = 0; + } +} + +/*! + Returns the list of this groups's actions. This may be empty. +*/ +QList QActionGroup::actions() const +{ + Q_D(const QActionGroup); + return d->actions; +} + +/*! + \property QActionGroup::exclusive + \brief whether the action group does exclusive checking + + If exclusive is true, only one checkable action in the action group + can ever be active at any time. If the user chooses another + checkable action in the group, the one they chose becomes active and + the one that was active becomes inactive. + + \sa QAction::checkable +*/ +void QActionGroup::setExclusive(bool b) +{ + Q_D(QActionGroup); + d->exclusive = b; +} + +bool QActionGroup::isExclusive() const +{ + Q_D(const QActionGroup); + return d->exclusive; +} + +/*! + \fn void QActionGroup::setDisabled(bool b) + + This is a convenience function for the \l enabled property, that + is useful for signals--slots connections. If \a b is true the + action group is disabled; otherwise it is enabled. +*/ + +/*! + \property QActionGroup::enabled + \brief whether the action group is enabled + + Each action in the group will be enabled or disabled unless it + has been explicitly disabled. + + \sa QAction::setEnabled() +*/ +void QActionGroup::setEnabled(bool b) +{ + Q_D(QActionGroup); + d->enabled = b; + for(QList::const_iterator it = d->actions.constBegin(); it != d->actions.constEnd(); ++it) { + if(!(*it)->d_func()->forceDisabled) { + (*it)->setEnabled(b); + (*it)->d_func()->forceDisabled = false; + } + } +} + +bool QActionGroup::isEnabled() const +{ + Q_D(const QActionGroup); + return d->enabled; +} + +/*! + Returns the currently checked action in the group, or 0 if none + are checked. +*/ +QAction *QActionGroup::checkedAction() const +{ + Q_D(const QActionGroup); + return d->current; +} + +/*! + \property QActionGroup::visible + \brief whether the action group is visible + + Each action in the action group will match the visible state of + this group unless it has been explicitly hidden. + + \sa QAction::setEnabled() +*/ +void QActionGroup::setVisible(bool b) +{ + Q_D(QActionGroup); + d->visible = b; + for(QList::Iterator it = d->actions.begin(); it != d->actions.end(); ++it) { + if(!(*it)->d_func()->forceInvisible) { + (*it)->setVisible(b); + (*it)->d_func()->forceInvisible = false; + } + } +} + +bool QActionGroup::isVisible() const +{ + Q_D(const QActionGroup); + return d->visible; +} + +/*! + \fn void QActionGroup::triggered(QAction *action) + + This signal is emitted when the given \a action in the action + group is activated by the user; for example, when the user clicks + a menu option, toolbar button, or presses an action's shortcut key + combination. + + Connect to this signal for command actions. + + \sa QAction::activate() +*/ + +/*! + \fn void QActionGroup::hovered(QAction *action) + + This signal is emitted when the given \a action in the action + group is highlighted by the user; for example, when the user + pauses with the cursor over a menu option, toolbar button, or + presses an action's shortcut key combination. + + \sa QAction::activate() +*/ + +/*! + \fn void QActionGroup::add(QAction* a) + + Use addAction() instead. +*/ + +/*! + \fn void QActionGroup::addSeparator() + + Normally you add a separator to the menus or widgets to which + actions are added, so this function is very rarely needed. + + \oldcode + actionGroup->addSeparator(); + \newcode + QAction *separator = new QAction(this); + separator->setSeparator(true); + actionGroup->addAction(separator); + \endcode +*/ + +/*! + \fn bool QActionGroup::addTo(QWidget *widget) + + \oldcode + actionGroup->addTo(widget); + \newcode + widget->addActions(actionGroup->actions()); + \endcode +*/ + +/*! + \fn void QActionGroup::selected(QAction *action); + + Use triggered() instead. + +*/ + +QT_END_NAMESPACE + +#include "moc_qactiongroup.cpp" + +#endif // QT_NO_ACTION diff --git a/src/widgets/kernel/qactiongroup.h b/src/widgets/kernel/qactiongroup.h new file mode 100644 index 0000000000..88f4fe8eac --- /dev/null +++ b/src/widgets/kernel/qactiongroup.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACTIONGROUP_H +#define QACTIONGROUP_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_ACTION + +class QActionGroupPrivate; + +class Q_GUI_EXPORT QActionGroup : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QActionGroup) + + Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible) + +public: + explicit QActionGroup(QObject* parent); + ~QActionGroup(); + + QAction *addAction(QAction* a); + QAction *addAction(const QString &text); + QAction *addAction(const QIcon &icon, const QString &text); + void removeAction(QAction *a); + QList actions() const; + + QAction *checkedAction() const; + bool isExclusive() const; + bool isEnabled() const; + bool isVisible() const; + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT void add(QAction* a) { addAction(a); } + inline QT3_SUPPORT void addSeparator() + { QAction *act = new QAction(this); act->setSeparator(true); addAction(act); } + inline QT3_SUPPORT bool addTo(QWidget *w) { w->addActions(actions()); return true; } +#endif + +public Q_SLOTS: + void setEnabled(bool); + inline void setDisabled(bool b) { setEnabled(!b); } + void setVisible(bool); + void setExclusive(bool); + +Q_SIGNALS: + void triggered(QAction *); + QT_MOC_COMPAT void selected(QAction *); + void hovered(QAction *); + +private: + Q_DISABLE_COPY(QActionGroup) + Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered()) + Q_PRIVATE_SLOT(d_func(), void _q_actionChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_actionHovered()) +}; + +#endif // QT_NO_ACTION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QACTIONGROUP_H diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp new file mode 100644 index 0000000000..2044cf78ce --- /dev/null +++ b/src/widgets/kernel/qapplication.cpp @@ -0,0 +1,5687 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qabstracteventdispatcher.h" +#include "qaccessible.h" +#include "qapplication.h" +#include "qclipboard.h" +#include "qcursor.h" +#include "qdesktopwidget.h" +#include "qdir.h" +#include "qevent.h" +#include "qfile.h" +#include "qfileinfo.h" +#include "qgraphicsscene.h" +#include "qhash.h" +#include "qset.h" +#include "qlayout.h" +#include "qsessionmanager.h" +#include "qstyle.h" +#include "qstylefactory.h" +#include "qtextcodec.h" +#include "qtranslator.h" +#include "qvariant.h" +#include "qwidget.h" +#include "private/qdnd_p.h" +#include "qcolormap.h" +#include "qdebug.h" +#include "private/qstylesheetstyle_p.h" +#include "private/qstyle_p.h" +#include "qmessagebox.h" +#include + +#include "qinputcontext.h" +#include "private/qkeymapper_p.h" + +#ifdef Q_WS_X11 +#include +#endif + +#if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN) +#include "qinputcontextfactory.h" +#endif + +#include "qguiplatformplugin_p.h" + +#include +#include + +#include + +#include + +#if defined(Q_WS_X11) && !defined(QT_NO_EGL) +#include +#endif + +#include "qapplication_p.h" +#include "private/qevent_p.h" +#include "qwidget_p.h" + +#include "qapplication.h" + +#include "qgesture.h" +#include "private/qgesturemanager_p.h" + +#ifndef QT_NO_LIBRARY +#include "qlibrary.h" +#endif + +#ifdef Q_WS_WINCE +#include "qdatetime.h" +#include "qguifunctions_wince.h" +extern bool qt_wince_is_smartphone(); //qguifunctions_wince.cpp +extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp +extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp +#endif + +#include "qdatetime.h" + +#ifdef QT_MAC_USE_COCOA +#include +#endif + +//#define ALIEN_DEBUG + +#if defined(Q_OS_SYMBIAN) +#include "qt_s60_p.h" +#endif + +static void initResources() +{ +#if defined(Q_WS_WINCE) + Q_INIT_RESOURCE_EXTERN(qstyle_wince) + Q_INIT_RESOURCE(qstyle_wince); +#elif defined(Q_OS_SYMBIAN) + Q_INIT_RESOURCE_EXTERN(qstyle_s60) + Q_INIT_RESOURCE(qstyle_s60); +#else + Q_INIT_RESOURCE_EXTERN(qstyle) + Q_INIT_RESOURCE(qstyle); +#endif + Q_INIT_RESOURCE_EXTERN(qmessagebox) + Q_INIT_RESOURCE(qmessagebox); +#if !defined(QT_NO_PRINTDIALOG) + Q_INIT_RESOURCE_EXTERN(qprintdialog) + Q_INIT_RESOURCE(qprintdialog); +#endif + +} + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT void qt_call_post_routines(); + +QApplication::Type qt_appType=QApplication::Tty; +QApplicationPrivate *QApplicationPrivate::self = 0; + +QInputContext *QApplicationPrivate::inputContext = 0; + +bool QApplicationPrivate::quitOnLastWindowClosed = true; + +#ifdef Q_WS_WINCE +int QApplicationPrivate::autoMaximizeThreshold = -1; +bool QApplicationPrivate::autoSipEnabled = false; +#else +bool QApplicationPrivate::autoSipEnabled = true; +#endif + +QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type, int flags) + : QApplicationPrivateBase(argc, argv, flags) +{ + application_type = type; + qt_appType = type; + +#ifndef QT_NO_SESSIONMANAGER + is_session_restored = false; +#endif + + quitOnLastWindowClosed = true; + +#ifdef QT3_SUPPORT + qt_compat_used = 0; + qt_compat_resolved = 0; + qt_tryAccelEvent = 0; + qt_tryComposeUnicode = 0; + qt_dispatchAccelEvent = 0; +#endif +#if defined(Q_WS_QWS) && !defined(QT_NO_DIRECTPAINTER) + directPainters = 0; +#endif + +#ifndef QT_NO_GESTURES + gestureManager = 0; + gestureWidget = 0; +#endif // QT_NO_GESTURES + +#if defined(Q_WS_X11) || defined(Q_WS_WIN) + move_cursor = 0; + copy_cursor = 0; + link_cursor = 0; +#endif +#if defined(Q_WS_WIN) + ignore_cursor = 0; +#endif + + if (!self) + self = this; +} + +QApplicationPrivate::~QApplicationPrivate() +{ + if (self == this) + self = 0; +} + +/*! + \class QApplication + \brief The QApplication class manages the GUI application's control + flow and main settings. + + QApplication contains the main event loop, where all events from the window + system and other sources are processed and dispatched. It also handles the + application's initialization, finalization, and provides session + management. In addition, QApplication handles most of the system-wide and + application-wide settings. + + For any GUI application using Qt, there is precisely \bold one QApplication + object, no matter whether the application has 0, 1, 2 or more windows at + any given time. For non-GUI Qt applications, use QCoreApplication instead, + as it does not depend on the \l QtGui library. + + The QApplication object is accessible through the instance() function that + returns a pointer equivalent to the global qApp pointer. + + QApplication's main areas of responsibility are: + \list + \o It initializes the application with the user's desktop settings + such as palette(), font() and doubleClickInterval(). It keeps + track of these properties in case the user changes the desktop + globally, for example through some kind of control panel. + + \o It performs event handling, meaning that it receives events + from the underlying window system and dispatches them to the + relevant widgets. By using sendEvent() and postEvent() you can + send your own events to widgets. + + \o It parses common command line arguments and sets its internal + state accordingly. See the \l{QApplication::QApplication()} + {constructor documentation} below for more details. + + \o It defines the application's look and feel, which is + encapsulated in a QStyle object. This can be changed at runtime + with setStyle(). + + \o It specifies how the application is to allocate colors. See + setColorSpec() for details. + + \o It provides localization of strings that are visible to the + user via translate(). + + \o It provides some magical objects like the desktop() and the + clipboard(). + + \o It knows about the application's windows. You can ask which + widget is at a certain position using widgetAt(), get a list of + topLevelWidgets() and closeAllWindows(), etc. + + \o It manages the application's mouse cursor handling, see + setOverrideCursor() + + \o On the X window system, it provides functions to flush and sync + the communication stream, see flushX() and syncX(). + + \o It provides support for sophisticated \l{Session Management} + {session management}. This makes it possible for applications + to terminate gracefully when the user logs out, to cancel a + shutdown process if termination isn't possible and even to + preserve the entire application's state for a future session. + See isSessionRestored(), sessionId() and commitData() and + saveState() for details. + \endlist + + Since the QApplication object does so much initialization, it \e{must} be + created before any other objects related to the user interface are created. + QApplication also deals with common command line arguments. Hence, it is + usually a good idea to create it \e before any interpretation or + modification of \c argv is done in the application itself. + + \table + \header + \o{2,1} Groups of functions + + \row + \o System settings + \o desktopSettingsAware(), + setDesktopSettingsAware(), + cursorFlashTime(), + setCursorFlashTime(), + doubleClickInterval(), + setDoubleClickInterval(), + setKeyboardInputInterval(), + wheelScrollLines(), + setWheelScrollLines(), + palette(), + setPalette(), + font(), + setFont(), + fontMetrics(). + + \row + \o Event handling + \o exec(), + processEvents(), + exit(), + quit(). + sendEvent(), + postEvent(), + sendPostedEvents(), + removePostedEvents(), + hasPendingEvents(), + notify(), + macEventFilter(), + qwsEventFilter(), + x11EventFilter(), + x11ProcessEvent(), + winEventFilter(). + + \row + \o GUI Styles + \o style(), + setStyle(). + + \row + \o Color usage + \o colorSpec(), + setColorSpec(), + qwsSetCustomColors(). + + \row + \o Text handling + \o installTranslator(), + removeTranslator() + translate(). + + \row + \o Widgets + \o allWidgets(), + topLevelWidgets(), + desktop(), + activePopupWidget(), + activeModalWidget(), + clipboard(), + focusWidget(), + activeWindow(), + widgetAt(). + + \row + \o Advanced cursor handling + \o overrideCursor(), + setOverrideCursor(), + restoreOverrideCursor(). + + \row + \o X Window System synchronization + \o flushX(), + syncX(). + + \row + \o Session management + \o isSessionRestored(), + sessionId(), + commitData(), + saveState(). + + \row + \o Miscellaneous + \o closeAllWindows(), + startingUp(), + closingDown(), + type(). + \endtable + + \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop, QSettings +*/ + +/*! + \enum QApplication::Type + + \value Tty a console application + \value GuiClient a GUI client application + \value GuiServer a GUI server application (for Qt for Embedded Linux) +*/ + +/*! + \enum QApplication::ColorSpec + + \value NormalColor the default color allocation policy + \value CustomColor the same as NormalColor for X11; allocates colors + to a palette on demand under Windows + \value ManyColor the right choice for applications that use thousands of + colors + + See setColorSpec() for full details. +*/ + +/*! + \fn QWidget *QApplication::topLevelAt(const QPoint &point) + + Returns the top-level widget at the given \a point; returns 0 if + there is no such widget. +*/ + +/*! + \fn QWidget *QApplication::topLevelAt(int x, int y) + + \overload + + Returns the top-level widget at the point (\a{x}, \a{y}); returns + 0 if there is no such widget. +*/ + + +/* + The qt_init() and qt_cleanup() functions are implemented in the + qapplication_xyz.cpp file. +*/ + +void qt_init(QApplicationPrivate *priv, int type +#ifdef Q_WS_X11 + , Display *display = 0, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0 +#endif + ); +void qt_cleanup(); + +Qt::MouseButtons QApplicationPrivate::mouse_buttons = Qt::NoButton; +Qt::KeyboardModifiers QApplicationPrivate::modifier_buttons = Qt::NoModifier; + +QStyle *QApplicationPrivate::app_style = 0; // default application style +QString QApplicationPrivate::styleOverride; // style override + +#ifndef QT_NO_STYLE_STYLESHEET +QString QApplicationPrivate::styleSheet; // default application stylesheet +#endif +QPointer QApplicationPrivate::leaveAfterRelease = 0; + +int QApplicationPrivate::app_cspec = QApplication::NormalColor; +QPalette *QApplicationPrivate::sys_pal = 0; // default system palette +QPalette *QApplicationPrivate::set_pal = 0; // default palette set by programmer + +#ifndef Q_WS_QPA +Q_GLOBAL_STATIC(QMutex, applicationFontMutex) +QFont *QApplicationPrivate::app_font = 0; // default application font +#endif +QFont *QApplicationPrivate::sys_font = 0; // default system font +QFont *QApplicationPrivate::set_font = 0; // default font set by programmer + +QIcon *QApplicationPrivate::app_icon = 0; +QWidget *QApplicationPrivate::main_widget = 0; // main application widget +QWidget *QApplicationPrivate::focus_widget = 0; // has keyboard input focus +QWidget *QApplicationPrivate::hidden_focus_widget = 0; // will get keyboard input focus after show() +QWidget *QApplicationPrivate::active_window = 0; // toplevel with keyboard focus +bool QApplicationPrivate::obey_desktop_settings = true; // use winsys resources +int QApplicationPrivate::cursor_flash_time = 1000; // text caret flash time +int QApplicationPrivate::mouse_double_click_time = 400; // mouse dbl click limit +int QApplicationPrivate::keyboard_input_time = 400; // keyboard input interval +#ifndef QT_NO_WHEELEVENT +int QApplicationPrivate::wheel_scroll_lines; // number of lines to scroll +#endif +bool qt_is_gui_used; +bool Q_GUI_EXPORT qt_tab_all_widgets = true; +bool qt_in_tab_key_event = false; +int qt_antialiasing_threshold = -1; +static int drag_time = 500; +#ifndef QT_GUI_DRAG_DISTANCE +#define QT_GUI_DRAG_DISTANCE 4 +#endif +#ifdef Q_OS_SYMBIAN +// The screens are a bit too small to for your thumb when using only 4 pixels drag distance. +static int drag_distance = 12; //XXX move to qplatformdefs.h +#else +static int drag_distance = QT_GUI_DRAG_DISTANCE; +#endif +QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut +bool QApplicationPrivate::animate_ui = true; +bool QApplicationPrivate::animate_menu = false; +bool QApplicationPrivate::fade_menu = false; +bool QApplicationPrivate::animate_combo = false; +bool QApplicationPrivate::animate_tooltip = false; +bool QApplicationPrivate::fade_tooltip = false; +bool QApplicationPrivate::animate_toolbox = false; +bool QApplicationPrivate::widgetCount = false; +bool QApplicationPrivate::load_testability = false; +QString QApplicationPrivate::qmljs_debug_arguments; +#ifdef QT_KEYPAD_NAVIGATION +# ifdef Q_OS_SYMBIAN +Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional; +# else +Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadTabOrder; +# endif +QWidget *QApplicationPrivate::oldEditFocus = 0; +#endif + +bool qt_tabletChokeMouse = false; + +inline bool QApplicationPrivate::isAlien(QWidget *widget) +{ + if (!widget) + return false; +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) + return !widget->isWindow() +# ifdef Q_BACKINGSTORE_SUBSURFACES + && !(widget->d_func()->maybeTopData() && widget->d_func()->maybeTopData()->windowSurface) +# endif + ; +#else + return !widget->internalWinId(); +#endif +} + +// ######## move to QApplicationPrivate +// Default application palettes and fonts (per widget type) +Q_GLOBAL_STATIC(PaletteHash, app_palettes) +PaletteHash *qt_app_palettes_hash() +{ + return app_palettes(); +} + +Q_GLOBAL_STATIC(FontHash, app_fonts) +FontHash *qt_app_fonts_hash() +{ + return app_fonts(); +} + +QWidgetList *QApplicationPrivate::popupWidgets = 0; // has keyboard input focus + +QDesktopWidget *qt_desktopWidget = 0; // root window widgets +#if !defined(Q_WS_QPA) && !defined(QT_NO_CLIPBOARD) +QClipboard *qt_clipboard = 0; // global clipboard object +#endif +QWidgetList * qt_modal_stack=0; // stack of modal widgets + +/*! + \internal +*/ +void QApplicationPrivate::process_cmdline() +{ + // process platform-indep command line + if (!qt_is_gui_used || !argc) + return; + + int i, j; + + j = 1; + for (i=1; i= 0) { + session_key = session_id.mid(p +1); + session_id = session_id.left(p); + } + is_session_restored = true; + } +#endif +#ifndef QT_NO_STYLE_STYLESHEET + } else if (arg == "-stylesheet" && i < argc -1) { + styleSheet = QLatin1String("file:///"); + styleSheet.append(QString::fromLocal8Bit(argv[++i])); + } else if (arg.indexOf("-stylesheet=") != -1) { + styleSheet = QLatin1String("file:///"); + styleSheet.append(QString::fromLocal8Bit(arg.right(arg.length() - 12))); +#endif + } else if (qstrcmp(arg, "-widgetcount") == 0) { + widgetCount = true; + } else if (qstrcmp(arg, "-testability") == 0) { + load_testability = true; + } else { + argv[j++] = argv[i]; + } + if (!s.isEmpty()) { + if (app_style) { + delete app_style; + app_style = 0; + } + styleOverride = s; + } + } + + if(j < argc) { + argv[j] = 0; + argc = j; + } +} + +/*! + Initializes the window system and constructs an application object with + \a argc command line arguments in \a argv. + + \warning The data referred to by \a argc and \a argv must stay valid for + the entire lifetime of the QApplication object. In addition, \a argc must + be greater than zero and \a argv must contain at least one valid character + string. + + The global \c qApp pointer refers to this application object. Only one + application object should be created. + + This application object must be constructed before any \l{QPaintDevice} + {paint devices} (including widgets, pixmaps, bitmaps etc.). + + \note \a argc and \a argv might be changed as Qt removes command line + arguments that it recognizes. + + Qt debugging options (not available if Qt was compiled without the QT_DEBUG + flag defined): + \list + \o -nograb, tells Qt that it must never grab the mouse or the + keyboard. + \o -dograb (only under X11), running under a debugger can cause an + implicit -nograb, use -dograb to override. + \o -sync (only under X11), switches to synchronous mode for + debugging. + \endlist + + See \l{Debugging Techniques} for a more detailed explanation. + + All Qt programs automatically support the following command line options: + \list + \o -style= \e style, sets the application GUI style. Possible values + are \c motif, \c windows, and \c platinum. If you compiled Qt with + additional styles or have additional styles as plugins these will + be available to the \c -style command line option. + \o -style \e style, is the same as listed above. + \o -stylesheet= \e stylesheet, sets the application \l styleSheet. The + value must be a path to a file that contains the Style Sheet. + \note Relative URLs in the Style Sheet file are relative to the + Style Sheet file's path. + \o -stylesheet \e stylesheet, is the same as listed above. + \o -session= \e session, restores the application from an earlier + \l{Session Management}{session}. + \o -session \e session, is the same as listed above. + \o -widgetcount, prints debug message at the end about number of + widgets left undestroyed and maximum number of widgets existed at + the same time + \o -reverse, sets the application's layout direction to + Qt::RightToLeft + \o -qmljsdebugger=, activates the QML/JS debugger with a specified port. + The value must be of format port:1234[,block], where block is optional + and will make the application wait until a debugger connects to it. + \endlist + + The X11 version of Qt supports some traditional X11 command line options: + \list + \o -display \e display, sets the X display (default is $DISPLAY). + \o -geometry \e geometry, sets the client geometry of the first window + that is shown. + \o -fn or \c -font \e font, defines the application font. The font + should be specified using an X logical font description. Note that + this option is ignored when Qt is built with fontconfig support enabled. + \o -bg or \c -background \e color, sets the default background color + and an application palette (light and dark shades are calculated). + \o -fg or \c -foreground \e color, sets the default foreground color. + \o -btn or \c -button \e color, sets the default button color. + \o -name \e name, sets the application name. + \o -title \e title, sets the application title. + \o -visual \c TrueColor, forces the application to use a TrueColor + visual on an 8-bit display. + \o -ncols \e count, limits the number of colors allocated in the color + cube on an 8-bit display, if the application is using the + QApplication::ManyColor color specification. If \e count is 216 + then a 6x6x6 color cube is used (i.e. 6 levels of red, 6 of green, + and 6 of blue); for other values, a cube approximately proportional + to a 2x3x1 cube is used. + \o -cmap, causes the application to install a private color map on an + 8-bit display. + \o -im, sets the input method server (equivalent to setting the + XMODIFIERS environment variable) + \o -inputstyle, defines how the input is inserted into the given + widget, e.g., \c onTheSpot makes the input appear directly in the + widget, while \c overTheSpot makes the input appear in a box + floating over the widget and is not inserted until the editing is + done. + \endlist + + \section1 X11 Notes + + If QApplication fails to open the X11 display, it will terminate + the process. This behavior is consistent with most X11 + applications. + + \sa arguments() +*/ + +QApplication::QApplication(int &argc, char **argv) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GuiClient, 0x040000)) +{ Q_D(QApplication); d->construct(); } + +QApplication::QApplication(int &argc, char **argv, int _internal) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GuiClient, _internal)) +{ Q_D(QApplication); d->construct(); } + + +/*! + Constructs an application object with \a argc command line arguments in + \a argv. If \a GUIenabled is true, a GUI application is constructed, + otherwise a non-GUI (console) application is created. + + \warning The data referred to by \a argc and \a argv must stay valid for + the entire lifetime of the QApplication object. In addition, \a argc must + be greater than zero and \a argv must contain at least one valid character + string. + + Set \a GUIenabled to false for programs without a graphical user interface + that should be able to run without a window system. + + On X11, the window system is initialized if \a GUIenabled is true. If + \a GUIenabled is false, the application does not connect to the X server. + On Windows and Mac OS, currently the window system is always initialized, + regardless of the value of GUIenabled. This may change in future versions + of Qt. + + The following example shows how to create an application that uses a + graphical interface when available. + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 0 +*/ + +QApplication::QApplication(int &argc, char **argv, bool GUIenabled ) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GUIenabled ? GuiClient : Tty, 0x040000)) +{ Q_D(QApplication); d->construct(); } + +QApplication::QApplication(int &argc, char **argv, bool GUIenabled , int _internal) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GUIenabled ? GuiClient : Tty, _internal)) +{ Q_D(QApplication); d->construct();} + + + +/*! + Constructs an application object with \a argc command line arguments in + \a argv. + + \warning The data referred to by \a argc and \a argv must stay valid for + the entire lifetime of the QApplication object. In addition, \a argc must + be greater than zero and \a argv must contain at least one valid character + string. + + With Qt for Embedded Linux, passing QApplication::GuiServer for \a type + makes this application the server (equivalent to running with the + \c -qws option). +*/ +QApplication::QApplication(int &argc, char **argv, Type type) + : QApplicationBase(*new QApplicationPrivate(argc, argv, type, 0x040000)) +{ Q_D(QApplication); d->construct(); } + +QApplication::QApplication(int &argc, char **argv, Type type , int _internal) + : QApplicationBase(*new QApplicationPrivate(argc, argv, type, _internal)) +{ Q_D(QApplication); d->construct(); } + +#if defined(Q_WS_X11) && !defined(QT_NO_EGL) +static int qt_matchLibraryName(dl_phdr_info *info, size_t, void *data) +{ + const char *name = static_cast(data); + return strstr(info->dlpi_name, name) != 0; +} +#endif + +/*! + \internal +*/ +void QApplicationPrivate::construct( +#ifdef Q_WS_X11 + Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap +#endif + ) +{ + initResources(); + + qt_is_gui_used = (qt_appType != QApplication::Tty); + process_cmdline(); + + // Must be called before initialize() + qt_init(this, qt_appType +#ifdef Q_WS_X11 + , dpy, visual, cmap +#endif + ); + initialize(); + eventDispatcher->startingUp(); + +#ifdef QT_EVAL + extern void qt_gui_eval_init(uint); + qt_gui_eval_init(application_type); +#endif + +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) + symbianInit(); +#endif + +#ifndef QT_NO_LIBRARY + if(load_testability) { + QLibrary testLib(QLatin1String("qttestability")); + if (testLib.load()) { + typedef void (*TasInitialize)(void); + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); +#ifdef Q_OS_SYMBIAN + // resolving method by name does not work on Symbian OS so need to use ordinal + if(!initFunction) { + initFunction = (TasInitialize)testLib.resolve("1"); + } +#endif + if (initFunction) { + initFunction(); + } else { + qCritical("Library qttestability resolve failed!"); + } + } else { + qCritical("Library qttestability load failed!"); + } + } + + //make sure the plugin is loaded + if (qt_is_gui_used) + qt_guiPlatformPlugin(); +#endif +} + +#if defined(Q_WS_X11) +// ### a string literal is a cont char* +// ### using it as a char* is wrong and could lead to segfaults +// ### if aargv is modified someday +// ########## make it work with argc == argv == 0 +static int aargc = 1; +static char *aargv[] = { (char*)"unknown", 0 }; + +/*! + \fn QApplication::QApplication(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap) + + Creates an application, given an already open display \a display. If + \a visual and \a colormap are non-zero, the application will use those + values as the default Visual and Colormap contexts. + + \warning Qt only supports TrueColor visuals at depths higher than 8 + bits-per-pixel. + + This function is only available on X11. +*/ +QApplication::QApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap) + : QApplicationBase(*new QApplicationPrivate(aargc, aargv, GuiClient, 0x040000)) +{ + if (! dpy) + qWarning("QApplication: Invalid Display* argument"); + Q_D(QApplication); + d->construct(dpy, visual, colormap); +} + +QApplication::QApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap, int _internal) + : QApplicationBase(*new QApplicationPrivate(aargc, aargv, GuiClient, _internal)) +{ + if (! dpy) + qWarning("QApplication: Invalid Display* argument"); + Q_D(QApplication); + d->construct(dpy, visual, colormap); + QApplicationPrivate::app_compile_version = _internal; +} + +/*! + \fn QApplication::QApplication(Display *display, int &argc, char **argv, + Qt::HANDLE visual, Qt::HANDLE colormap) + + Creates an application, given an already open \a display and using \a argc + command line arguments in \a argv. If \a visual and \a colormap are + non-zero, the application will use those values as the default Visual + and Colormap contexts. + + \warning Qt only supports TrueColor visuals at depths higher than 8 + bits-per-pixel. + + This function is only available on X11. +*/ +QApplication::QApplication(Display *dpy, int &argc, char **argv, + Qt::HANDLE visual, Qt::HANDLE colormap) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GuiClient, 0x040000)) +{ + if (! dpy) + qWarning("QApplication: Invalid Display* argument"); + Q_D(QApplication); + d->construct(dpy, visual, colormap); +} + +QApplication::QApplication(Display *dpy, int &argc, char **argv, + Qt::HANDLE visual, Qt::HANDLE colormap, int _internal) + : QApplicationBase(*new QApplicationPrivate(argc, argv, GuiClient, _internal)) +{ + if (! dpy) + qWarning("QApplication: Invalid Display* argument"); + Q_D(QApplication); + d->construct(dpy, visual, colormap); + QApplicationPrivate::app_compile_version = _internal; +} + +#endif // Q_WS_X11 + +extern void qInitDrawhelperAsm(); +extern void qInitImageConversions(); +extern int qRegisterGuiVariant(); +extern int qUnregisterGuiVariant(); +#ifndef QT_NO_STATEMACHINE +extern int qRegisterGuiStateMachine(); +extern int qUnregisterGuiStateMachine(); +#endif + +/*! + \fn void QApplicationPrivate::initialize() + + Initializes the QApplication object, called from the constructors. +*/ +void QApplicationPrivate::initialize() +{ + QWidgetPrivate::mapper = new QWidgetMapper; + QWidgetPrivate::allWidgets = new QWidgetSet; + + if (qt_appType != QApplication::Tty) + (void) QApplication::style(); // trigger creation of application style + // trigger registering of QVariant's GUI types + qRegisterGuiVariant(); +#ifndef QT_NO_STATEMACHINE + // trigger registering of QStateMachine's GUI types + qRegisterGuiStateMachine(); +#endif + + is_app_running = true; // no longer starting up + + Q_Q(QApplication); +#ifndef QT_NO_SESSIONMANAGER + // connect to the session manager + session_manager = new QSessionManager(q, session_id, session_key); +#endif + + if (qgetenv("QT_USE_NATIVE_WINDOWS").toInt() > 0) + q->setAttribute(Qt::AA_NativeWindows); + +#ifdef Q_WS_WINCE +#ifdef QT_AUTO_MAXIMIZE_THRESHOLD + autoMaximizeThreshold = QT_AUTO_MAXIMIZE_THRESHOLD; +#else + if (qt_wince_is_mobile()) + autoMaximizeThreshold = 50; + else + autoMaximizeThreshold = -1; +#endif //QT_AUTO_MAXIMIZE_THRESHOLD +#endif //Q_WS_WINCE + + // Set up which span functions should be used in raster engine... + qInitDrawhelperAsm(); + // and QImage conversion functions + qInitImageConversions(); + +#ifndef QT_NO_WHEELEVENT + QApplicationPrivate::wheel_scroll_lines = 3; +#endif + + if (qt_is_gui_used) + initializeMultitouch(); +} + +/*! + Returns the type of application (\l Tty, GuiClient, or + GuiServer). The type is set when constructing the QApplication + object. +*/ +QApplication::Type QApplication::type() +{ + return qt_appType; +} + +/***************************************************************************** + Functions returning the active popup and modal widgets. + *****************************************************************************/ + +/*! + Returns the active popup widget. + + A popup widget is a special top-level widget that sets the \c + Qt::WType_Popup widget flag, e.g. the QMenu widget. When the application + opens a popup widget, all events are sent to the popup. Normal widgets and + modal widgets cannot be accessed before the popup widget is closed. + + Only other popup widgets may be opened when a popup widget is shown. The + popup widgets are organized in a stack. This function returns the active + popup widget at the top of the stack. + + \sa activeModalWidget(), topLevelWidgets() +*/ + +QWidget *QApplication::activePopupWidget() +{ + return QApplicationPrivate::popupWidgets && !QApplicationPrivate::popupWidgets->isEmpty() ? + QApplicationPrivate::popupWidgets->last() : 0; +} + + +/*! + Returns the active modal widget. + + A modal widget is a special top-level widget which is a subclass of QDialog + that specifies the modal parameter of the constructor as true. A modal + widget must be closed before the user can continue with other parts of the + program. + + Modal widgets are organized in a stack. This function returns the active + modal widget at the top of the stack. + + \sa activePopupWidget(), topLevelWidgets() +*/ + +QWidget *QApplication::activeModalWidget() +{ + return qt_modal_stack && !qt_modal_stack->isEmpty() ? qt_modal_stack->first() : 0; +} + +/*! + Cleans up any window system resources that were allocated by this + application. Sets the global variable \c qApp to 0. +*/ + +QApplication::~QApplication() +{ + Q_D(QApplication); + +#if !defined(Q_WS_QPA) && !defined(QT_NO_CLIPBOARD) + // flush clipboard contents + if (qt_clipboard) { + QEvent event(QEvent::Clipboard); + QApplication::sendEvent(qt_clipboard, &event); + } +#endif + + //### this should probable be done even later + qt_call_post_routines(); + + // kill timers before closing down the dispatcher + d->toolTipWakeUp.stop(); + d->toolTipFallAsleep.stop(); + +#if !defined(Q_WS_QPA) + d->eventDispatcher->closingDown(); + d->eventDispatcher = 0; +#endif + QApplicationPrivate::is_app_closing = true; + QApplicationPrivate::is_app_running = false; + + delete QWidgetPrivate::mapper; + QWidgetPrivate::mapper = 0; + + // delete all widgets + if (QWidgetPrivate::allWidgets) { + QWidgetSet *mySet = QWidgetPrivate::allWidgets; + QWidgetPrivate::allWidgets = 0; + for (QWidgetSet::ConstIterator it = mySet->constBegin(); it != mySet->constEnd(); ++it) { + register QWidget *w = *it; + if (!w->parent()) // window + w->destroy(true, true); + } + delete mySet; + } + + delete qt_desktopWidget; + qt_desktopWidget = 0; + +#if !defined(Q_WS_QPA) && !defined(QT_NO_CLIPBOARD) + delete qt_clipboard; + qt_clipboard = 0; +#endif + +#if defined(Q_WS_X11) || defined(Q_WS_WIN) + delete d->move_cursor; d->move_cursor = 0; + delete d->copy_cursor; d->copy_cursor = 0; + delete d->link_cursor; d->link_cursor = 0; +#endif +#if defined(Q_WS_WIN) + delete d->ignore_cursor; d->ignore_cursor = 0; +#endif + + delete QApplicationPrivate::app_pal; + QApplicationPrivate::app_pal = 0; + delete QApplicationPrivate::sys_pal; + QApplicationPrivate::sys_pal = 0; + delete QApplicationPrivate::set_pal; + QApplicationPrivate::set_pal = 0; + app_palettes()->clear(); + +#ifndef Q_WS_QPA + { + QMutexLocker locker(applicationFontMutex()); + delete QApplicationPrivate::app_font; + QApplicationPrivate::app_font = 0; + } +#endif + + delete QApplicationPrivate::sys_font; + QApplicationPrivate::sys_font = 0; + delete QApplicationPrivate::set_font; + QApplicationPrivate::set_font = 0; + app_fonts()->clear(); + + delete QApplicationPrivate::app_style; + QApplicationPrivate::app_style = 0; + delete QApplicationPrivate::app_icon; + QApplicationPrivate::app_icon = 0; + +#ifndef QT_NO_DRAGANDDROP + if (qt_is_gui_used) + delete QDragManager::self(); +#endif + + d->cleanupMultitouch(); + + qt_cleanup(); + + if (QApplicationPrivate::widgetCount) + qDebug("Widgets left: %i Max widgets: %i \n", QWidgetPrivate::instanceCounter, QWidgetPrivate::maxInstances); +#ifndef QT_NO_SESSIONMANAGER + delete d->session_manager; + d->session_manager = 0; +#endif //QT_NO_SESSIONMANAGER + + QApplicationPrivate::obey_desktop_settings = true; + QApplicationPrivate::cursor_flash_time = 1000; + QApplicationPrivate::mouse_double_click_time = 400; + QApplicationPrivate::keyboard_input_time = 400; + + drag_time = 500; + drag_distance = 4; + QApplicationPrivate::app_strut = QSize(0, 0); + QApplicationPrivate::animate_ui = true; + QApplicationPrivate::animate_menu = false; + QApplicationPrivate::fade_menu = false; + QApplicationPrivate::animate_combo = false; + QApplicationPrivate::animate_tooltip = false; + QApplicationPrivate::fade_tooltip = false; + QApplicationPrivate::widgetCount = false; + +#ifndef QT_NO_STATEMACHINE + // trigger unregistering of QStateMachine's GUI types + qUnregisterGuiStateMachine(); +#endif + // trigger unregistering of QVariant's GUI types + qUnregisterGuiVariant(); +} + + +/*! + \fn QWidget *QApplication::widgetAt(const QPoint &point) + + Returns the widget at global screen position \a point, or 0 if there is no + Qt widget there. + + This function can be slow. + + \sa QCursor::pos(), QWidget::grabMouse(), QWidget::grabKeyboard() +*/ +QWidget *QApplication::widgetAt(const QPoint &p) +{ + QWidget *window = QApplication::topLevelAt(p); + if (!window) + return 0; + + QWidget *child = 0; + + if (!window->testAttribute(Qt::WA_TransparentForMouseEvents)) + child = window->childAt(window->mapFromGlobal(p)); + + if (child) + return child; + + if (window->testAttribute(Qt::WA_TransparentForMouseEvents)) { + //shoot a hole in the widget and try once again, + //suboptimal on Qt for Embedded Linux where we do + //know the stacking order of the toplevels. + int x = p.x(); + int y = p.y(); + QRegion oldmask = window->mask(); + QPoint wpoint = window->mapFromGlobal(QPoint(x, y)); + QRegion newmask = (oldmask.isEmpty() ? QRegion(window->rect()) : oldmask) + - QRegion(wpoint.x(), wpoint.y(), 1, 1); + window->setMask(newmask); + QWidget *recurse = 0; + if (QApplication::topLevelAt(p) != window) // verify recursion will terminate + recurse = widgetAt(x, y); + if (oldmask.isEmpty()) + window->clearMask(); + else + window->setMask(oldmask); + return recurse; + } + return window; +} + +/*! + \fn QWidget *QApplication::widgetAt(int x, int y) + + \overload + + Returns the widget at global screen position (\a x, \a y), or 0 if there is + no Qt widget there. +*/ + +/*! + \fn void QApplication::setArgs(int argc, char **argv) + \internal +*/ + + + +/*! + \internal +*/ +bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) +{ + if ((event->type() == QEvent::UpdateRequest +#ifdef QT3_SUPPORT + || event->type() == QEvent::LayoutHint +#endif + || event->type() == QEvent::LayoutRequest + || event->type() == QEvent::Resize + || event->type() == QEvent::Move + || event->type() == QEvent::LanguageChange + || event->type() == QEvent::UpdateSoftKeys + || event->type() == QEvent::InputMethod)) { + for (int i = 0; i < postedEvents->size(); ++i) { + const QPostEvent &cur = postedEvents->at(i); + if (cur.receiver != receiver || cur.event == 0 || cur.event->type() != event->type()) + continue; + if (cur.event->type() == QEvent::LayoutRequest +#ifdef QT3_SUPPORT + || cur.event->type() == QEvent::LayoutHint +#endif + || cur.event->type() == QEvent::UpdateRequest) { + ; + } else if (cur.event->type() == QEvent::Resize) { + ((QResizeEvent *)(cur.event))->s = ((QResizeEvent *)event)->s; + } else if (cur.event->type() == QEvent::Move) { + ((QMoveEvent *)(cur.event))->p = ((QMoveEvent *)event)->p; + } else if (cur.event->type() == QEvent::LanguageChange) { + ; + } else if (cur.event->type() == QEvent::UpdateSoftKeys) { + ; + } else if ( cur.event->type() == QEvent::InputMethod ) { + *(QInputMethodEvent *)(cur.event) = *(QInputMethodEvent *)event; + } else { + continue; + } + delete event; + return true; + } + return false; + } + return QApplicationBase::compressEvent(event, receiver, postedEvents); +} + +/*! + \property QApplication::styleSheet + \brief the application style sheet + \since 4.2 + + By default, this property returns an empty string unless the user specifies + the \c{-stylesheet} option on the command line when running the application. + + \sa QWidget::setStyle(), {Qt Style Sheets} +*/ + +/*! + \property QApplication::autoMaximizeThreshold + \since 4.4 + \brief defines a threshold for auto maximizing widgets + + \bold{The auto maximize threshold is only available as part of Qt for + Windows CE.} + + This property defines a threshold for the size of a window as a percentage + of the screen size. If the minimum size hint of a window exceeds the + threshold, calling show() will cause the window to be maximized + automatically. + + Setting the threshold to 100 or greater means that the widget will always + be maximized. Alternatively, setting the threshold to 50 means that the + widget will be maximized only if the vertical minimum size hint is at least + 50% of the vertical screen size. + + Setting the threshold to -1 disables the feature. + + On Windows CE the default is -1 (i.e., it is disabled). + On Windows Mobile the default is 40. +*/ + +/*! + \property QApplication::autoSipEnabled + \since 4.5 + \brief toggles automatic SIP (software input panel) visibility + + Set this property to \c true to automatically display the SIP when entering + widgets that accept keyboard input. This property only affects widgets with + the WA_InputMethodEnabled attribute set, and is typically used to launch + a virtual keyboard on devices which have very few or no keys. + + \bold{ The property only has an effect on platforms which use software input + panels, such as Windows CE and Symbian.} + + The default is platform dependent. +*/ + +#ifdef Q_WS_WINCE +void QApplication::setAutoMaximizeThreshold(const int threshold) +{ + QApplicationPrivate::autoMaximizeThreshold = threshold; +} + +int QApplication::autoMaximizeThreshold() const +{ + return QApplicationPrivate::autoMaximizeThreshold; +} +#endif + +void QApplication::setAutoSipEnabled(const bool enabled) +{ + QApplicationPrivate::autoSipEnabled = enabled; +} + +bool QApplication::autoSipEnabled() const +{ + return QApplicationPrivate::autoSipEnabled; +} + +#ifndef QT_NO_STYLE_STYLESHEET + +QString QApplication::styleSheet() const +{ + return QApplicationPrivate::styleSheet; +} + +void QApplication::setStyleSheet(const QString& styleSheet) +{ + QApplicationPrivate::styleSheet = styleSheet; + QStyleSheetStyle *proxy = qobject_cast(QApplicationPrivate::app_style); + if (styleSheet.isEmpty()) { // application style sheet removed + if (!proxy) + return; // there was no stylesheet before + setStyle(proxy->base); + } else if (proxy) { // style sheet update, just repolish + proxy->repolish(qApp); + } else { // stylesheet set the first time + QStyleSheetStyle *newProxy = new QStyleSheetStyle(QApplicationPrivate::app_style); + QApplicationPrivate::app_style->setParent(newProxy); + setStyle(newProxy); + } +} + +#endif // QT_NO_STYLE_STYLESHEET + +/*! + Returns the application's style object. + + \sa setStyle(), QStyle +*/ +QStyle *QApplication::style() +{ + if (QApplicationPrivate::app_style) + return QApplicationPrivate::app_style; + if (!qt_is_gui_used) { + Q_ASSERT(!"No style available in non-gui applications!"); + return 0; + } + + if (!QApplicationPrivate::app_style) { + // Compile-time search for default style + // + QString style; +#ifdef QT_BUILD_INTERNAL + QString envStyle = QString::fromLocal8Bit(qgetenv("QT_STYLE_OVERRIDE")); +#else + QString envStyle; +#endif + if (!QApplicationPrivate::styleOverride.isEmpty()) { + style = QApplicationPrivate::styleOverride; + } else if (!envStyle.isEmpty()) { + style = envStyle; + } else { + style = QApplicationPrivate::desktopStyleKey(); + } + + QStyle *&app_style = QApplicationPrivate::app_style; + app_style = QStyleFactory::create(style); + if (!app_style) { + QStringList styles = QStyleFactory::keys(); + for (int i = 0; i < styles.size(); ++i) { + if ((app_style = QStyleFactory::create(styles.at(i)))) + break; + } + } + if (!app_style) { + Q_ASSERT(!"No styles available!"); + return 0; + } + } + // take ownership of the style + QApplicationPrivate::app_style->setParent(qApp); + + if (!QApplicationPrivate::sys_pal) + QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette()); + if (QApplicationPrivate::set_pal) // repolish set palette with the new style + QApplication::setPalette(*QApplicationPrivate::set_pal); + +#ifndef QT_NO_STYLE_STYLESHEET + if (!QApplicationPrivate::styleSheet.isEmpty()) { + qApp->setStyleSheet(QApplicationPrivate::styleSheet); + } else +#endif + QApplicationPrivate::app_style->polish(qApp); + + return QApplicationPrivate::app_style; +} + +/*! + Sets the application's GUI style to \a style. Ownership of the style object + is transferred to QApplication, so QApplication will delete the style + object on application exit or when a new style is set and the old style is + still the parent of the application object. + + Example usage: + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 1 + + When switching application styles, the color palette is set back to the + initial colors or the system defaults. This is necessary since certain + styles have to adapt the color palette to be fully style-guide compliant. + + Setting the style before a palette has been se, i.e., before creating + QApplication, will cause the application to use QStyle::standardPalette() + for the palette. + + \warning Qt style sheets are currently not supported for custom QStyle + subclasses. We plan to address this in some future release. + + \sa style(), QStyle, setPalette(), desktopSettingsAware() +*/ +void QApplication::setStyle(QStyle *style) +{ + if (!style || style == QApplicationPrivate::app_style) + return; + + QWidgetList all = allWidgets(); + + // clean up the old style + if (QApplicationPrivate::app_style) { + if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { + for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) { + register QWidget *w = *it; + if (!(w->windowType() == Qt::Desktop) && // except desktop + w->testAttribute(Qt::WA_WState_Polished)) { // has been polished + QApplicationPrivate::app_style->unpolish(w); + } + } + } + QApplicationPrivate::app_style->unpolish(qApp); + } + + QStyle *old = QApplicationPrivate::app_style; // save + +#ifndef QT_NO_STYLE_STYLESHEET + if (!QApplicationPrivate::styleSheet.isEmpty() && !qobject_cast(style)) { + // we have a stylesheet already and a new style is being set + QStyleSheetStyle *newProxy = new QStyleSheetStyle(style); + style->setParent(newProxy); + QApplicationPrivate::app_style = newProxy; + } else +#endif // QT_NO_STYLE_STYLESHEET + QApplicationPrivate::app_style = style; + QApplicationPrivate::app_style->setParent(qApp); // take ownership + + // take care of possible palette requirements of certain gui + // styles. Do it before polishing the application since the style + // might call QApplication::setPalette() itself + if (QApplicationPrivate::set_pal) { + QApplication::setPalette(*QApplicationPrivate::set_pal); + } else if (QApplicationPrivate::sys_pal) { + QApplicationPrivate::initializeWidgetPaletteHash(); + QApplicationPrivate::setPalette_helper(*QApplicationPrivate::sys_pal, /*className=*/0, /*clearWidgetPaletteHash=*/false); + } else if (!QApplicationPrivate::sys_pal) { + // Initialize the sys_pal if it hasn't happened yet... + QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette()); + } + + // initialize the application with the new style + QApplicationPrivate::app_style->polish(qApp); + + // re-polish existing widgets if necessary + if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { + for (QWidgetList::ConstIterator it1 = all.constBegin(); it1 != all.constEnd(); ++it1) { + register QWidget *w = *it1; + if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) { + if (w->style() == QApplicationPrivate::app_style) + QApplicationPrivate::app_style->polish(w); // repolish +#ifndef QT_NO_STYLE_STYLESHEET + else + w->setStyleSheet(w->styleSheet()); // touch +#endif + } + } + + for (QWidgetList::ConstIterator it2 = all.constBegin(); it2 != all.constEnd(); ++it2) { + register QWidget *w = *it2; + if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) { + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(w, &e); +#ifdef QT3_SUPPORT + if (old) + w->styleChange(*old); +#endif + w->update(); + } + } + } + +#ifndef QT_NO_STYLE_STYLESHEET + if (QStyleSheetStyle *oldProxy = qobject_cast(old)) { + oldProxy->deref(); + } else +#endif + if (old && old->parent() == qApp) { + delete old; + } + + if (QApplicationPrivate::focus_widget) { + QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason); + QApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in); + QApplicationPrivate::focus_widget->update(); + } +} + +/*! + \overload + + Requests a QStyle object for \a style from the QStyleFactory. + + The string must be one of the QStyleFactory::keys(), typically one of + "windows", "motif", "cde", "plastique", "windowsxp", or "macintosh". Style + names are case insensitive. + + Returns 0 if an unknown \a style is passed, otherwise the QStyle object + returned is set as the application's GUI style. + + \warning To ensure that the application's style is set correctly, it is + best to call this function before the QApplication constructor, if + possible. +*/ +QStyle* QApplication::setStyle(const QString& style) +{ + QStyle *s = QStyleFactory::create(style); + if (!s) + return 0; + + setStyle(s); + return s; +} + +/*! + Returns the color specification. + + \sa QApplication::setColorSpec() +*/ + +int QApplication::colorSpec() +{ + return QApplicationPrivate::app_cspec; +} + +/*! + Sets the color specification for the application to \a spec. + + The color specification controls how the application allocates colors when + run on a display with a limited amount of colors, e.g. 8 bit / 256 color + displays. + + The color specification must be set before you create the QApplication + object. + + The options are: + \list + \o QApplication::NormalColor. This is the default color allocation + strategy. Use this option if your application uses buttons, menus, + texts and pixmaps with few colors. With this option, the + application uses system global colors. This works fine for most + applications under X11, but on the Windows platform, it may cause + dithering of non-standard colors. + \o QApplication::CustomColor. Use this option if your application + needs a small number of custom colors. On X11, this option is the + same as NormalColor. On Windows, Qt creates a Windows palette, and + allocates colors to it on demand. + \o QApplication::ManyColor. Use this option if your application is + very color hungry, e.g., it requires thousands of colors. \br + Under X11 the effect is: + \list + \o For 256-color displays which have at best a 256 color true + color visual, the default visual is used, and colors are + allocated from a color cube. The color cube is the 6x6x6 + (216 color) "Web palette" (the red, green, and blue + components always have one of the following values: 0x00, + 0x33, 0x66, 0x99, 0xCC, or 0xFF), but the number of colors + can be changed by the \e -ncols option. The user can force + the application to use the true color visual with the + \l{QApplication::QApplication()}{-visual} option. + \o For 256-color displays which have a true color visual with + more than 256 colors, use that visual. Silicon Graphics X + servers this feature, for example. They provide an 8 bit + visual by default but can deliver true color when asked. + \endlist + On Windows, Qt creates a Windows palette, and fills it with a color + cube. + \endlist + + Be aware that the CustomColor and ManyColor choices may lead to colormap + flashing: The foreground application gets (most) of the available colors, + while the background windows will look less attractive. + + Example: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 2 + + \sa colorSpec() +*/ + +void QApplication::setColorSpec(int spec) +{ + if (qApp) + qWarning("QApplication::setColorSpec: This function must be " + "called before the QApplication object is created"); + QApplicationPrivate::app_cspec = spec; +} + +/*! + \property QApplication::globalStrut + \brief the minimum size that any GUI element that the user can interact + with should have + + For example, no button should be resized to be smaller than the global + strut size. The strut size should be considered when reimplementing GUI + controls that may be used on touch-screens or similar I/O devices. + + Example: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 3 + + By default, this property contains a QSize object with zero width and height. +*/ +QSize QApplication::globalStrut() +{ + return QApplicationPrivate::app_strut; +} + +void QApplication::setGlobalStrut(const QSize& strut) +{ + QApplicationPrivate::app_strut = strut; +} + + +/*! + \fn QPalette QApplication::palette(const QWidget* widget) + \overload + + If a \a widget is passed, the default palette for the widget's class is + returned. This may or may not be the application palette. In most cases + there is no special palette for certain types of widgets, but one notable + exception is the popup menu under Windows, if the user has defined a + special background color for menus in the display settings. + + \sa setPalette(), QWidget::palette() +*/ +QPalette QApplication::palette(const QWidget* w) +{ + PaletteHash *hash = app_palettes(); + if (w && hash && hash->size()) { + QHash::ConstIterator it = hash->constFind(w->metaObject()->className()); + if (it != hash->constEnd()) + return *it; + for (it = hash->constBegin(); it != hash->constEnd(); ++it) { + if (w->inherits(it.key())) + return it.value(); + } + } + return palette(); +} + +/*! + \overload + + Returns the palette for widgets of the given \a className. + + \sa setPalette(), QWidget::palette() +*/ +QPalette QApplication::palette(const char *className) +{ + if (!QApplicationPrivate::app_pal) + palette(); + PaletteHash *hash = app_palettes(); + if (className && hash && hash->size()) { + QHash::ConstIterator it = hash->constFind(className); + if (it != hash->constEnd()) + return *it; + } + return *QApplicationPrivate::app_pal; +} + +void QApplicationPrivate::setPalette_helper(const QPalette &palette, const char* className, bool clearWidgetPaletteHash) +{ + QPalette pal = palette; + + if (QApplicationPrivate::app_style) + QApplicationPrivate::app_style->polish(pal); // NB: non-const reference + + bool all = false; + PaletteHash *hash = app_palettes(); + if (!className) { + if (QApplicationPrivate::app_pal && pal.isCopyOf(*QApplicationPrivate::app_pal)) + return; + if (!QApplicationPrivate::app_pal) + QApplicationPrivate::app_pal = new QPalette(pal); + else + *QApplicationPrivate::app_pal = pal; + if (hash && hash->size()) { + all = true; + if (clearWidgetPaletteHash) + hash->clear(); + } + } else if (hash) { + hash->insert(className, pal); + } + + if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { + // Send ApplicationPaletteChange to qApp itself, and to the widgets. + QEvent e(QEvent::ApplicationPaletteChange); + QApplication::sendEvent(QApplication::instance(), &e); + + QWidgetList wids = QApplication::allWidgets(); + for (QWidgetList::ConstIterator it = wids.constBegin(); it != wids.constEnd(); ++it) { + register QWidget *w = *it; + if (all || (!className && w->isWindow()) || w->inherits(className)) // matching class + QApplication::sendEvent(w, &e); + } + + // Send to all scenes as well. +#ifndef QT_NO_GRAPHICSVIEW + QList &scenes = qApp->d_func()->scene_list; + for (QList::ConstIterator it = scenes.constBegin(); + it != scenes.constEnd(); ++it) { + QApplication::sendEvent(*it, &e); + } +#endif //QT_NO_GRAPHICSVIEW + } + if (!className && (!QApplicationPrivate::sys_pal || !palette.isCopyOf(*QApplicationPrivate::sys_pal))) { + if (!QApplicationPrivate::set_pal) + QApplicationPrivate::set_pal = new QPalette(palette); + else + *QApplicationPrivate::set_pal = palette; + } +} + +/*! + Changes the default application palette to \a palette. + + If \a className is passed, the change applies only to widgets that inherit + \a className (as reported by QObject::inherits()). If \a className is left + 0, the change affects all widgets, thus overriding any previously set class + specific palettes. + + The palette may be changed according to the current GUI style in + QStyle::polish(). + + \warning Do not use this function in conjunction with \l{Qt Style Sheets}. + When using style sheets, the palette of a widget can be customized using + the "color", "background-color", "selection-color", + "selection-background-color" and "alternate-background-color". + + \note Some styles do not use the palette for all drawing, for instance, if + they make use of native theme engines. This is the case for the Windows XP, + Windows Vista, and Mac OS X styles. + + \sa QWidget::setPalette(), palette(), QStyle::polish() +*/ + +void QApplication::setPalette(const QPalette &palette, const char* className) +{ + QApplicationPrivate::setPalette_helper(palette, className, /*clearWidgetPaletteHash=*/ true); +} + + + +void QApplicationPrivate::setSystemPalette(const QPalette &pal) +{ + QPalette adjusted; + +#if 0 + // adjust the system palette to avoid dithering + QColormap cmap = QColormap::instance(); + if (cmap.depths() > 4 && cmap.depths() < 24) { + for (int g = 0; g < QPalette::NColorGroups; g++) + for (int i = 0; i < QPalette::NColorRoles; i++) { + QColor color = pal.color((QPalette::ColorGroup)g, (QPalette::ColorRole)i); + color = cmap.colorAt(cmap.pixel(color)); + adjusted.setColor((QPalette::ColorGroup)g, (QPalette::ColorRole) i, color); + } + } +#else + adjusted = pal; +#endif + + if (!sys_pal) + sys_pal = new QPalette(adjusted); + else + *sys_pal = adjusted; + + + if (!QApplicationPrivate::set_pal) + QApplication::setPalette(*sys_pal); +} + +/*! + Returns the default application font. + + \sa fontMetrics(), QWidget::font() +*/ +QFont QApplication::font() +{ +#ifndef Q_WS_QPA + QMutexLocker locker(applicationFontMutex()); + if (!QApplicationPrivate::app_font) + QApplicationPrivate::app_font = new QFont(QLatin1String("Helvetica")); + return *QApplicationPrivate::app_font; +#else + return QGuiApplication::font(); +#endif +} + +/*! + \overload + + Returns the default font for the \a widget. + + \sa fontMetrics(), QWidget::setFont() +*/ + +QFont QApplication::font(const QWidget *widget) +{ + FontHash *hash = app_fonts(); + +#ifdef Q_WS_MAC + // short circuit for small and mini controls + if (widget->testAttribute(Qt::WA_MacSmallSize)) { + return hash->value("QSmallFont"); + } else if (widget->testAttribute(Qt::WA_MacMiniSize)) { + return hash->value("QMiniFont"); + } +#endif + if (widget && hash && hash->size()) { + QHash::ConstIterator it = + hash->constFind(widget->metaObject()->className()); + if (it != hash->constEnd()) + return it.value(); + for (it = hash->constBegin(); it != hash->constEnd(); ++it) { + if (widget->inherits(it.key())) + return it.value(); + } + } + return font(); +} + +/*! + \overload + + Returns the font for widgets of the given \a className. + + \sa setFont(), QWidget::font() +*/ +QFont QApplication::font(const char *className) +{ + FontHash *hash = app_fonts(); + if (className && hash && hash->size()) { + QHash::ConstIterator it = hash->constFind(className); + if (it != hash->constEnd()) + return *it; + } + return font(); +} + + +/*! + Changes the default application font to \a font. If \a className is passed, + the change applies only to classes that inherit \a className (as reported + by QObject::inherits()). + + On application start-up, the default font depends on the window system. It + can vary depending on both the window system version and the locale. This + function lets you override the default font; but overriding may be a bad + idea because, for example, some locales need extra large fonts to support + their special characters. + + \warning Do not use this function in conjunction with \l{Qt Style Sheets}. + The font of an application can be customized using the "font" style sheet + property. To set a bold font for all QPushButtons, set the application + styleSheet() as "QPushButton { font: bold }" + + \sa font(), fontMetrics(), QWidget::setFont() +*/ + +void QApplication::setFont(const QFont &font, const char *className) +{ + bool all = false; + FontHash *hash = app_fonts(); + if (!className) { +#ifndef Q_WS_QPA + QMutexLocker locker(applicationFontMutex()); + if (!QApplicationPrivate::app_font) + QApplicationPrivate::app_font = new QFont(font); + else + *QApplicationPrivate::app_font = font; +#else + QGuiApplication::setFont(font); +#endif + if (hash && hash->size()) { + all = true; + hash->clear(); + } + } else if (hash) { + hash->insert(className, font); + } + if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { + // Send ApplicationFontChange to qApp itself, and to the widgets. + QEvent e(QEvent::ApplicationFontChange); + QApplication::sendEvent(QApplication::instance(), &e); + + QWidgetList wids = QApplication::allWidgets(); + for (QWidgetList::ConstIterator it = wids.constBegin(); it != wids.constEnd(); ++it) { + register QWidget *w = *it; + if (all || (!className && w->isWindow()) || w->inherits(className)) // matching class + sendEvent(w, &e); + } + +#ifndef QT_NO_GRAPHICSVIEW + // Send to all scenes as well. + QList &scenes = qApp->d_func()->scene_list; + for (QList::ConstIterator it = scenes.constBegin(); + it != scenes.constEnd(); ++it) { + QApplication::sendEvent(*it, &e); + } +#endif //QT_NO_GRAPHICSVIEW + } + if (!className && (!QApplicationPrivate::sys_font || !font.isCopyOf(*QApplicationPrivate::sys_font))) { + if (!QApplicationPrivate::set_font) + QApplicationPrivate::set_font = new QFont(font); + else + *QApplicationPrivate::set_font = font; + } +} + +/*! \internal +*/ +void QApplicationPrivate::setSystemFont(const QFont &font) +{ + if (!sys_font) + sys_font = new QFont(font); + else + *sys_font = font; + + if (!QApplicationPrivate::set_font) + QApplication::setFont(*sys_font); +} + +/*! \internal +*/ +QString QApplicationPrivate::desktopStyleKey() +{ + return qt_guiPlatformPlugin()->styleName(); +} + +/*! + \property QApplication::windowIcon + \brief the default window icon + + \sa QWidget::setWindowIcon(), {Setting the Application Icon} +*/ +QIcon QApplication::windowIcon() +{ + return QApplicationPrivate::app_icon ? *QApplicationPrivate::app_icon : QIcon(); +} + +void QApplication::setWindowIcon(const QIcon &icon) +{ + if (!QApplicationPrivate::app_icon) + QApplicationPrivate::app_icon = new QIcon(); + *QApplicationPrivate::app_icon = icon; + if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) { +#ifdef Q_WS_MAC + void qt_mac_set_app_icon(const QPixmap &); //qapplication_mac.cpp + QSize size = QApplicationPrivate::app_icon->actualSize(QSize(128, 128)); + qt_mac_set_app_icon(QApplicationPrivate::app_icon->pixmap(size)); +#endif + QEvent e(QEvent::ApplicationWindowIconChange); + QWidgetList all = QApplication::allWidgets(); + for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) { + register QWidget *w = *it; + if (w->isWindow()) + sendEvent(w, &e); + } + } +} + +/*! + Returns a list of the top-level widgets (windows) in the application. + + \note Some of the top-level widgets may be hidden, for example a tooltip if + no tooltip is currently shown. + + Example: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 4 + + \sa allWidgets(), QWidget::isWindow(), QWidget::isHidden() +*/ +QWidgetList QApplication::topLevelWidgets() +{ + QWidgetList list; + QWidgetList all = allWidgets(); + + for (QWidgetList::ConstIterator it = all.constBegin(); it != all.constEnd(); ++it) { + QWidget *w = *it; + if (w->isWindow() && w->windowType() != Qt::Desktop) + list.append(w); + } + return list; +} + +/*! + Returns a list of all the widgets in the application. + + The list is empty (QList::isEmpty()) if there are no widgets. + + \note Some of the widgets may be hidden. + + Example: + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 5 + + \sa topLevelWidgets(), QWidget::isVisible() +*/ + +QWidgetList QApplication::allWidgets() +{ + if (QWidgetPrivate::allWidgets) + return QWidgetPrivate::allWidgets->toList(); + return QWidgetList(); +} + +/*! + Returns the application widget that has the keyboard input focus, or 0 if + no widget in this application has the focus. + + \sa QWidget::setFocus(), QWidget::hasFocus(), activeWindow(), focusChanged() +*/ + +QWidget *QApplication::focusWidget() +{ + return QApplicationPrivate::focus_widget; +} + +void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) +{ +#ifndef QT_NO_GRAPHICSVIEW + if (focus && focus->window()->graphicsProxyWidget()) + return; +#endif + + hidden_focus_widget = 0; + + if (focus != focus_widget) { + if (focus && focus->isHidden()) { + hidden_focus_widget = focus; + return; + } + + if (focus && (reason == Qt::BacktabFocusReason || reason == Qt::TabFocusReason) + && qt_in_tab_key_event) + focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + else if (focus && reason == Qt::ShortcutFocusReason) { + focus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + } + QWidget *prev = focus_widget; + focus_widget = focus; +#ifndef QT_NO_IM + if (prev && ((reason != Qt::PopupFocusReason && reason != Qt::MenuBarFocusReason + && prev->testAttribute(Qt::WA_InputMethodEnabled)) + // Do reset the input context, in case the new focus widget won't accept keyboard input + // or it is not created fully yet. + || (focus_widget && (!focus_widget->testAttribute(Qt::WA_InputMethodEnabled) + || !focus_widget->testAttribute(Qt::WA_WState_Created))))) { + QInputContext *qic = prev->inputContext(); + if(qic) { + qic->reset(); + qic->setFocusWidget(0); + } + } +#endif //QT_NO_IM + + if(focus_widget) + focus_widget->d_func()->setFocus_sys(); + + if (reason != Qt::NoFocusReason) { + + //send events + if (prev) { +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if (prev->hasEditFocus() && reason != Qt::PopupFocusReason +#ifdef Q_OS_SYMBIAN + && reason != Qt::ActiveWindowFocusReason +#endif + ) + prev->setEditFocus(false); + } +#endif +#ifndef QT_NO_IM + if (focus) { + QInputContext *prevIc; + prevIc = prev->inputContext(); + if (prevIc && prevIc != focus->inputContext()) { + QEvent closeSIPEvent(QEvent::CloseSoftwareInputPanel); + QApplication::sendEvent(prev, &closeSIPEvent); + } + } +#endif + QFocusEvent out(QEvent::FocusOut, reason); + QPointer that = prev; + QApplication::sendEvent(prev, &out); + if (that) + QApplication::sendEvent(that->style(), &out); + } + if(focus && QApplicationPrivate::focus_widget == focus) { +#ifndef QT_NO_IM + if (focus->testAttribute(Qt::WA_InputMethodEnabled)) { + QInputContext *qic = focus->inputContext(); + if (qic && focus->testAttribute(Qt::WA_WState_Created) + && focus->isEnabled()) + qic->setFocusWidget(focus); + } +#endif //QT_NO_IM + QFocusEvent in(QEvent::FocusIn, reason); + QPointer that = focus; + QApplication::sendEvent(focus, &in); + if (that) + QApplication::sendEvent(that->style(), &in); + } + emit qApp->focusChanged(prev, focus_widget); + } + } +} + + +/*! + Returns the application top-level window that has the keyboard input focus, + or 0 if no application window has the focus. There might be an + activeWindow() even if there is no focusWidget(), for example if no widget + in that window accepts key events. + + \sa QWidget::setFocus(), QWidget::hasFocus(), focusWidget() +*/ + +QWidget *QApplication::activeWindow() +{ + return QApplicationPrivate::active_window; +} + +/*! + Returns display (screen) font metrics for the application font. + + \sa font(), setFont(), QWidget::fontMetrics(), QPainter::fontMetrics() +*/ + +QFontMetrics QApplication::fontMetrics() +{ + return desktop()->fontMetrics(); +} + + +/*! + Closes all top-level windows. + + This function is particularly useful for applications with many top-level + windows. It could, for example, be connected to a \gui{Exit} entry in the + \gui{File} menu: + + \snippet examples/mainwindows/mdi/mainwindow.cpp 0 + + The windows are closed in random order, until one window does not accept + the close event. The application quits when the last window was + successfully closed; this can be turned off by setting + \l quitOnLastWindowClosed to false. + + \sa quitOnLastWindowClosed, lastWindowClosed(), QWidget::close(), + QWidget::closeEvent(), lastWindowClosed(), quit(), topLevelWidgets(), + QWidget::isWindow() +*/ +void QApplication::closeAllWindows() +{ + bool did_close = true; + QWidget *w; + while ((w = activeModalWidget()) && did_close) { + if (!w->isVisible() || w->data->is_closing) + break; + did_close = w->close(); + } + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; did_close && i < list.size(); ++i) { + w = list.at(i); + if (w->isVisible() + && w->windowType() != Qt::Desktop + && !w->data->is_closing) { + did_close = w->close(); + list = QApplication::topLevelWidgets(); + i = -1; + } + } +} + +/*! + Displays a simple message box about Qt. The message includes the version + number of Qt being used by the application. + + This is useful for inclusion in the \gui Help menu of an application, as + shown in the \l{mainwindows/menus}{Menus} example. + + This function is a convenience slot for QMessageBox::aboutQt(). +*/ +void QApplication::aboutQt() +{ +#ifndef QT_NO_MESSAGEBOX + QMessageBox::aboutQt( +#ifdef Q_WS_MAC + 0 +#else + activeWindow() +#endif // Q_WS_MAC + ); +#endif // QT_NO_MESSAGEBOX +} + + +/*! + \fn void QApplication::lastWindowClosed() + + This signal is emitted from QApplication::exec() when the last visible + primary window (i.e. window with no parent) with the Qt::WA_QuitOnClose + attribute set is closed. + + By default, + + \list + \o this attribute is set for all widgets except transient windows such + as splash screens, tool windows, and popup menus + + \o QApplication implicitly quits when this signal is emitted. + \endlist + + This feature can be turned off by setting \l quitOnLastWindowClosed to + false. + + \sa QWidget::close() +*/ + +/*! + \since 4.1 + \fn void QApplication::focusChanged(QWidget *old, QWidget *now) + + This signal is emitted when the widget that has keyboard focus changed from + \a old to \a now, i.e., because the user pressed the tab-key, clicked into + a widget or changed the active window. Both \a old and \a now can be the + null-pointer. + + The signal is emitted after both widget have been notified about the change + through QFocusEvent. + + \sa QWidget::setFocus(), QWidget::clearFocus(), Qt::FocusReason +*/ + + +#ifndef QT_NO_TRANSLATION +#if defined(Q_WS_MAC) +static const char *application_menu_strings[] = { + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") + }; +QString qt_mac_applicationmenu_string(int type) +{ + QString menuString = QString::fromLatin1(application_menu_strings[type]); + QString translated = qApp->translate("QMenuBar", application_menu_strings[type]); + if (translated != menuString) + return translated; + else + return qApp->translate("MAC_APPLICATION_MENU", + application_menu_strings[type]); +} +#endif +#endif + +/*!\reimp + +*/ +bool QApplication::event(QEvent *e) +{ + Q_D(QApplication); + if(e->type() == QEvent::Close) { +#if defined(Q_OS_SYMBIAN) + // In order to have proper application-exit effects on Symbian, certain + // native APIs have to be called _before_ closing/destroying the widgets. + bool effectStarted = qt_beginFullScreenEffect(); +#endif + QCloseEvent *ce = static_cast(e); + ce->accept(); + closeAllWindows(); + + QWidgetList list = topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (w->isVisible() && !(w->windowType() == Qt::Desktop) && !(w->windowType() == Qt::Popup) && + (!(w->windowType() == Qt::Dialog) || !w->parentWidget())) { + ce->ignore(); + break; + } + } + if (ce->isAccepted()) { + return true; + } else { +#if defined(Q_OS_SYMBIAN) + if (effectStarted) + qt_abortFullScreenEffect(); +#endif + } +#ifndef Q_OS_WIN + } else if (e->type() == QEvent::LocaleChange) { + // on Windows the event propagation is taken care by the + // WM_SETTINGCHANGE event handler. + QWidgetList list = topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (!(w->windowType() == Qt::Desktop)) { + if (!w->testAttribute(Qt::WA_SetLocale)) + w->d_func()->setLocale_helper(QLocale(), true); + } + } +#endif + } else if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast(e); + Q_ASSERT(te != 0); + if (te->timerId() == d->toolTipWakeUp.timerId()) { + d->toolTipWakeUp.stop(); + if (d->toolTipWidget) { + QWidget *w = d->toolTipWidget->window(); + // show tooltip if WA_AlwaysShowToolTips is set, or if + // any ancestor of d->toolTipWidget is the active + // window + bool showToolTip = w->testAttribute(Qt::WA_AlwaysShowToolTips); + while (w && !showToolTip) { + showToolTip = w->isActiveWindow(); + w = w->parentWidget(); + w = w ? w->window() : 0; + } + if (showToolTip) { + QHelpEvent e(QEvent::ToolTip, d->toolTipPos, d->toolTipGlobalPos); + QApplication::sendEvent(d->toolTipWidget, &e); + if (e.isAccepted()) + d->toolTipFallAsleep.start(2000, this); + } + } + } else if (te->timerId() == d->toolTipFallAsleep.timerId()) { + d->toolTipFallAsleep.stop(); + } + } + return QApplicationBase::event(e); + + if(e->type() == QEvent::LanguageChange) { +#if defined(QT_MAC_USE_COCOA) + qt_mac_post_retranslateAppMenu(); +#endif + QWidgetList list = topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (!(w->windowType() == Qt::Desktop)) + postEvent(w, new QEvent(QEvent::LanguageChange)); + } + } + +} +#if !defined(Q_WS_X11) + +// The doc and X implementation of this function is in qapplication_x11.cpp + +void QApplication::syncX() {} // do nothing + +#endif + +void QApplicationPrivate::notifyLayoutDirectionChange() +{ + Q_Q(QApplication); + QWidgetList list = q->topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + QEvent ev(QEvent::ApplicationLayoutDirectionChange); + q->sendEvent(w, &ev); + } +} + + +/*! + \fn Qt::WindowsVersion QApplication::winVersion() + + Use \l QSysInfo::WindowsVersion instead. +*/ + +/*! + \fn void QApplication::setActiveWindow(QWidget* active) + + Sets the active window to the \a active widget in response to a system + event. The function is called from the platform specific event handlers. + + \warning This function does \e not set the keyboard focus to the active + widget. Call QWidget::activateWindow() instead. + + It sets the activeWindow() and focusWidget() attributes and sends proper + \l{QEvent::WindowActivate}{WindowActivate}/\l{QEvent::WindowDeactivate} + {WindowDeactivate} and \l{QEvent::FocusIn}{FocusIn}/\l{QEvent::FocusOut} + {FocusOut} events to all appropriate widgets. The window will then be + painted in active state (e.g. cursors in line edits will blink), and it + will have tool tips enabled. + + \sa activeWindow(), QWidget::activateWindow() +*/ +void QApplication::setActiveWindow(QWidget* act) +{ + QWidget* window = act?act->window():0; + + if (QApplicationPrivate::active_window == window) + return; + +#ifndef QT_NO_GRAPHICSVIEW + if (window && window->graphicsProxyWidget()) { + // Activate the proxy's view->viewport() ? + return; + } +#endif + + QWidgetList toBeActivated; + QWidgetList toBeDeactivated; + + if (QApplicationPrivate::active_window) { + if (style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, QApplicationPrivate::active_window)) { + QWidgetList list = topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (w->isVisible() && w->isActiveWindow()) + toBeDeactivated.append(w); + } + } else { + toBeDeactivated.append(QApplicationPrivate::active_window); + } + } + +#if !defined(Q_WS_MAC) + QWidget *previousActiveWindow = QApplicationPrivate::active_window; +#endif + QApplicationPrivate::active_window = window; + + if (QApplicationPrivate::active_window) { + if (style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, QApplicationPrivate::active_window)) { + QWidgetList list = topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (w->isVisible() && w->isActiveWindow()) + toBeActivated.append(w); + } + } else { + toBeActivated.append(QApplicationPrivate::active_window); + } + + } + + // first the activation/deactivation events + QEvent activationChange(QEvent::ActivationChange); + QEvent windowActivate(QEvent::WindowActivate); + QEvent windowDeactivate(QEvent::WindowDeactivate); + +#if !defined(Q_WS_MAC) + if (!previousActiveWindow) { + QEvent appActivate(QEvent::ApplicationActivate); + sendSpontaneousEvent(qApp, &appActivate); + } +#endif + + for (int i = 0; i < toBeActivated.size(); ++i) { + QWidget *w = toBeActivated.at(i); + sendSpontaneousEvent(w, &windowActivate); + sendSpontaneousEvent(w, &activationChange); + } + +#ifdef QT_MAC_USE_COCOA + // In case the user clicked on a child window, we need to + // reestablish the stacking order of the window so + // it pops in front of other child windows in cocoa: + qt_cocoaStackChildWindowOnTopOfOtherChildren(window); +#endif + + for(int i = 0; i < toBeDeactivated.size(); ++i) { + QWidget *w = toBeDeactivated.at(i); + sendSpontaneousEvent(w, &windowDeactivate); + sendSpontaneousEvent(w, &activationChange); + } + +#if !defined(Q_WS_MAC) + if (!QApplicationPrivate::active_window) { + QEvent appDeactivate(QEvent::ApplicationDeactivate); + sendSpontaneousEvent(qApp, &appDeactivate); + } +#endif + + if (QApplicationPrivate::popupWidgets == 0) { // !inPopupMode() + // then focus events + if (!QApplicationPrivate::active_window && QApplicationPrivate::focus_widget) { + QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason); + } else if (QApplicationPrivate::active_window) { + QWidget *w = QApplicationPrivate::active_window->focusWidget(); + if (w && w->isVisible() /*&& w->focusPolicy() != QWidget::NoFocus*/) + w->setFocus(Qt::ActiveWindowFocusReason); + else { + w = QApplicationPrivate::focusNextPrevChild_helper(QApplicationPrivate::active_window, true); + if (w) { + w->setFocus(Qt::ActiveWindowFocusReason); + } else { + // If the focus widget is not in the activate_window, clear the focus + w = QApplicationPrivate::focus_widget; + if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus) + QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason); + else if (!QApplicationPrivate::active_window->isAncestorOf(w)) + QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason); + } + } + } + } +} + +/*!internal + * Helper function that returns the new focus widget, but does not set the focus reason. + * Returns 0 if a new focus widget could not be found. + * Shared with QGraphicsProxyWidgetPrivate::findFocusChild() +*/ +QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next) +{ + uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus; + + QWidget *f = toplevel->focusWidget(); + if (!f) + f = toplevel; + + QWidget *w = f; + QWidget *test = f->d_func()->focus_next; + while (test && test != f) { + if ((test->focusPolicy() & focus_flag) == focus_flag + && !(test->d_func()->extra && test->d_func()->extra->focus_proxy) + && test->isVisibleTo(toplevel) && test->isEnabled() + && !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test)) + && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))) { + w = test; + if (next) + break; + } + test = test->d_func()->focus_next; + } + if (w == f) { + if (qt_in_tab_key_event) { + w->window()->setAttribute(Qt::WA_KeyboardFocusChange); + w->update(); + } + return 0; + } + return w; +} + +/*! + \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) + \internal + + Creates the proper Enter/Leave event when widget \a enter is entered and + widget \a leave is left. + */ +void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { +#if 0 + if (leave) { + QEvent e(QEvent::Leave); + QApplication::sendEvent(leave, & e); + } + if (enter) { + QEvent e(QEvent::Enter); + QApplication::sendEvent(enter, & e); + } + return; +#endif + + QWidget* w ; + if ((!enter && !leave) || (enter == leave)) + return; +#ifdef ALIEN_DEBUG + qDebug() << "QApplicationPrivate::dispatchEnterLeave, ENTER:" << enter << "LEAVE:" << leave; +#endif + QWidgetList leaveList; + QWidgetList enterList; + + bool sameWindow = leave && enter && leave->window() == enter->window(); + if (leave && !sameWindow) { + w = leave; + do { + leaveList.append(w); + } while (!w->isWindow() && (w = w->parentWidget())); + } + if (enter && !sameWindow) { + w = enter; + do { + enterList.prepend(w); + } while (!w->isWindow() && (w = w->parentWidget())); + } + if (sameWindow) { + int enterDepth = 0; + int leaveDepth = 0; + w = enter; + while (!w->isWindow() && (w = w->parentWidget())) + enterDepth++; + w = leave; + while (!w->isWindow() && (w = w->parentWidget())) + leaveDepth++; + QWidget* wenter = enter; + QWidget* wleave = leave; + while (enterDepth > leaveDepth) { + wenter = wenter->parentWidget(); + enterDepth--; + } + while (leaveDepth > enterDepth) { + wleave = wleave->parentWidget(); + leaveDepth--; + } + while (!wenter->isWindow() && wenter != wleave) { + wenter = wenter->parentWidget(); + wleave = wleave->parentWidget(); + } + + w = leave; + while (w != wleave) { + leaveList.append(w); + w = w->parentWidget(); + } + w = enter; + while (w != wenter) { + enterList.prepend(w); + w = w->parentWidget(); + } + } + + QEvent leaveEvent(QEvent::Leave); + for (int i = 0; i < leaveList.size(); ++i) { + w = leaveList.at(i); + if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) + if (leaveAfterRelease == w) + leaveAfterRelease = 0; +#endif + QApplication::sendEvent(w, &leaveEvent); + if (w->testAttribute(Qt::WA_Hover) && + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { + Q_ASSERT(instance()); + QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos)); + qApp->d_func()->notify_helper(w, &he); + } + } + } + QPoint posEnter = QCursor::pos(); + QEvent enterEvent(QEvent::Enter); + for (int i = 0; i < enterList.size(); ++i) { + w = enterList.at(i); + if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { + QApplication::sendEvent(w, &enterEvent); + if (w->testAttribute(Qt::WA_Hover) && + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { + QHoverEvent he(QEvent::HoverEnter, w->mapFromGlobal(posEnter), QPoint(-1, -1)); + qApp->d_func()->notify_helper(w, &he); + } + } + } + +#ifndef QT_NO_CURSOR + // Update cursor for alien/graphics widgets. + + const bool enterOnAlien = (enter && (isAlien(enter) || enter->testAttribute(Qt::WA_DontShowOnScreen))); +#if defined(Q_WS_X11) || defined(Q_WS_QPA) + //Whenever we leave an alien widget on X11, we need to reset its nativeParentWidget()'s cursor. + // This is not required on Windows as the cursor is reset on every single mouse move. + QWidget *parentOfLeavingCursor = 0; + for (int i = 0; i < leaveList.size(); ++i) { + w = leaveList.at(i); + if (!isAlien(w)) + break; + if (w->testAttribute(Qt::WA_SetCursor)) { + QWidget *parent = w->parentWidget(); + while (parent && parent->d_func()->data.in_destructor) + parent = parent->parentWidget(); + parentOfLeavingCursor = parent; + //continue looping, we need to find the downest alien widget with a cursor. + // (downest on the screen) + } + } + //check that we will not call qt_x11_enforce_cursor twice with the same native widget + if (parentOfLeavingCursor && (!enterOnAlien + || parentOfLeavingCursor->effectiveWinId() != enter->effectiveWinId())) { +#ifndef QT_NO_GRAPHICSVIEW + if (!parentOfLeavingCursor->window()->graphicsProxyWidget()) +#endif + { +#if defined(Q_WS_X11) + qt_x11_enforce_cursor(parentOfLeavingCursor,true); +#elif defined(Q_WS_QPA) + if (enter == QApplication::desktop()) { + qt_qpa_set_cursor(enter, true); + } else { + qt_qpa_set_cursor(parentOfLeavingCursor, true); + } +#endif + } + } +#endif + if (enterOnAlien) { + QWidget *cursorWidget = enter; + while (!cursorWidget->isWindow() && !cursorWidget->isEnabled()) + cursorWidget = cursorWidget->parentWidget(); + + if (!cursorWidget) + return; + +#ifndef QT_NO_GRAPHICSVIEW + if (cursorWidget->window()->graphicsProxyWidget()) { + QWidgetPrivate::nearestGraphicsProxyWidget(cursorWidget)->setCursor(cursorWidget->cursor()); + } else +#endif + { +#if defined(Q_WS_WIN) + qt_win_set_cursor(cursorWidget, true); +#elif defined(Q_WS_X11) + qt_x11_enforce_cursor(cursorWidget, true); +#elif defined(Q_OS_SYMBIAN) + qt_symbian_set_cursor(cursorWidget, true); +#elif defined(Q_WS_QPA) + qt_qpa_set_cursor(cursorWidget, true); +#endif + } + } +#endif +} + +/* exported for the benefit of testing tools */ +Q_GUI_EXPORT bool qt_tryModalHelper(QWidget *widget, QWidget **rettop) +{ + return QApplicationPrivate::tryModalHelper(widget, rettop); +} + +/*! \internal + Returns true if \a widget is blocked by a modal window. + */ +bool QApplicationPrivate::isBlockedByModal(QWidget *widget) +{ + widget = widget->window(); + if (!modalState()) + return false; + if (QApplication::activePopupWidget() == widget) + return false; + +#if 0 + for (int i = 0; i < qt_modal_stack->size(); ++i) { + QWidget *modalWidget = qt_modal_stack->at(i); + + { + // check if the active modal widget is our widget or a parent of our widget + QWidget *w = widget; + while (w) { + if (w == modalWidget) + return false; + w = w->parentWidget(); + } +#ifdef Q_WS_WIN + if ((widget->testAttribute(Qt::WA_WState_Created) || widget->data->winid) + && (modalWidget->testAttribute(Qt::WA_WState_Created) || modalWidget->data->winid) + && IsChild(modalWidget->data->winid, widget->data->winid)) + return false; +#endif + } + + Qt::WindowModality windowModality = modalWidget->windowModality(); + if (windowModality == Qt::NonModal) { + // determine the modality type if it hasn't been set on the + // modalWidget, this normally happens when waiting for a + // native dialog. use WindowModal if we are the child of a + // group leader; otherwise use ApplicationModal. + QWidget *m = modalWidget; + while (m && !m->testAttribute(Qt::WA_GroupLeader)) { + m = m->parentWidget(); + if (m) + m = m->window(); + } + windowModality = (m && m->testAttribute(Qt::WA_GroupLeader)) + ? Qt::WindowModal + : Qt::ApplicationModal; + } + + switch (windowModality) { + case Qt::ApplicationModal: + { + QWidget *groupLeaderForWidget = widget; + while (groupLeaderForWidget && !groupLeaderForWidget->testAttribute(Qt::WA_GroupLeader)) + groupLeaderForWidget = groupLeaderForWidget->parentWidget(); + + if (groupLeaderForWidget) { + // if \a widget has WA_GroupLeader, it can only be blocked by ApplicationModal children + QWidget *m = modalWidget; + while (m && m != groupLeaderForWidget && !m->testAttribute(Qt::WA_GroupLeader)) + m = m->parentWidget(); + if (m == groupLeaderForWidget) + return true; + } else if (modalWidget != widget) { + return true; + } + break; + } + case Qt::WindowModal: + { + QWidget *w = widget; + do { + QWidget *m = modalWidget; + do { + if (m == w) + return true; + m = m->parentWidget(); + if (m) + m = m->window(); + } while (m); + w = w->parentWidget(); + if (w) + w = w->window(); + } while (w); + break; + } + default: + Q_ASSERT_X(false, "QApplication", "internal error, a modal widget cannot be modeless"); + break; + } + } +#endif + return false; +} + +/*!\internal + */ +void QApplicationPrivate::enterModal(QWidget *widget) +{ + QSet blocked; + QList windows = QApplication::topLevelWidgets(); + for (int i = 0; i < windows.count(); ++i) { + QWidget *window = windows.at(i); + if (window->windowType() != Qt::Tool && isBlockedByModal(window)) + blocked.insert(window); + } + + enterModal_sys(widget); + + windows = QApplication::topLevelWidgets(); + QEvent e(QEvent::WindowBlocked); + for (int i = 0; i < windows.count(); ++i) { + QWidget *window = windows.at(i); + if (!blocked.contains(window) && window->windowType() != Qt::Tool && isBlockedByModal(window)) + QApplication::sendEvent(window, &e); + } +} + +/*!\internal + */ +void QApplicationPrivate::leaveModal(QWidget *widget) +{ + QSet blocked; + QList windows = QApplication::topLevelWidgets(); + for (int i = 0; i < windows.count(); ++i) { + QWidget *window = windows.at(i); + if (window->windowType() != Qt::Tool && isBlockedByModal(window)) + blocked.insert(window); + } + + leaveModal_sys(widget); + + windows = QApplication::topLevelWidgets(); + QEvent e(QEvent::WindowUnblocked); + for (int i = 0; i < windows.count(); ++i) { + QWidget *window = windows.at(i); + if(blocked.contains(window) && window->windowType() != Qt::Tool && !isBlockedByModal(window)) + QApplication::sendEvent(window, &e); + } +} + + + +/*!\internal + + Called from qapplication_\e{platform}.cpp, returns true + if the widget should accept the event. + */ +bool QApplicationPrivate::tryModalHelper(QWidget *widget, QWidget **rettop) +{ + QWidget *top = QApplication::activeModalWidget(); + if (rettop) + *rettop = top; + + // the active popup widget always gets the input event + if (QApplication::activePopupWidget()) + return true; + +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + top = QApplicationPrivate::tryModalHelper_sys(top); + if (rettop) + *rettop = top; +#endif + + return !isBlockedByModal(widget->window()); +} + +/* + \internal +*/ +QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint &globalPos, + QPoint &pos, QEvent::Type type, + Qt::MouseButtons buttons, QWidget *buttonDown, + QWidget *alienWidget) +{ + Q_ASSERT(candidate); + + QWidget *mouseGrabber = QWidget::mouseGrabber(); + if (((type == QEvent::MouseMove && buttons) || (type == QEvent::MouseButtonRelease)) + && !buttonDown && !mouseGrabber) { + return 0; + } + + if (alienWidget && alienWidget->internalWinId()) + alienWidget = 0; + + QWidget *receiver = candidate; + + if (!mouseGrabber) + mouseGrabber = (buttonDown && !isBlockedByModal(buttonDown)) ? buttonDown : alienWidget; + + if (mouseGrabber && mouseGrabber != candidate) { + receiver = mouseGrabber; + pos = receiver->mapFromGlobal(globalPos); +#ifdef ALIEN_DEBUG + qDebug() << " ** receiver adjusted to:" << receiver << "pos:" << pos; +#endif + } + + return receiver; + +} + +/* + \internal +*/ +bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, + QWidget *alienWidget, QWidget *nativeWidget, + QWidget **buttonDown, QPointer &lastMouseReceiver, + bool spontaneous) +{ + Q_ASSERT(receiver); + Q_ASSERT(event); + Q_ASSERT(nativeWidget); + Q_ASSERT(buttonDown); + + if (alienWidget && !isAlien(alienWidget)) + alienWidget = 0; + + QPointer receiverGuard = receiver; + QPointer nativeGuard = nativeWidget; + QPointer alienGuard = alienWidget; + QPointer activePopupWidget = QApplication::activePopupWidget(); + + const bool graphicsWidget = nativeWidget->testAttribute(Qt::WA_DontShowOnScreen); + + if (*buttonDown) { + if (!graphicsWidget) { + // Register the widget that shall receive a leave event + // after the last button is released. + if ((alienWidget || !receiver->internalWinId()) && !leaveAfterRelease && !QWidget::mouseGrabber()) + leaveAfterRelease = *buttonDown; + if (event->type() == QEvent::MouseButtonRelease && !event->buttons()) + *buttonDown = 0; + } + } else if (lastMouseReceiver) { + // Dispatch enter/leave if we move: + // 1) from an alien widget to another alien widget or + // from a native widget to an alien widget (first OR case) + // 2) from an alien widget to a native widget (second OR case) + if ((alienWidget && alienWidget != lastMouseReceiver) + || (isAlien(lastMouseReceiver) && !alienWidget)) { + if (activePopupWidget) { + if (!QWidget::mouseGrabber()) + dispatchEnterLeave(alienWidget ? alienWidget : nativeWidget, lastMouseReceiver); + } else { + dispatchEnterLeave(receiver, lastMouseReceiver); + } + + } + } + +#ifdef ALIEN_DEBUG + qDebug() << "QApplicationPrivate::sendMouseEvent: receiver:" << receiver + << "pos:" << event->pos() << "alien" << alienWidget << "button down" + << *buttonDown << "last" << lastMouseReceiver << "leave after release" + << leaveAfterRelease; +#endif + + // We need this quard in case someone opens a modal dialog / popup. If that's the case + // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. + const bool wasLeaveAfterRelease = leaveAfterRelease != 0; + bool result; + if (spontaneous) + result = QApplication::sendSpontaneousEvent(receiver, event); + else + result = QApplication::sendEvent(receiver, event); + + if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease + && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { + // Dispatch enter/leave if: + // 1) the mouse grabber is an alien widget + // 2) the button is released on an alien widget + QWidget *enter = 0; + if (nativeGuard) + enter = alienGuard ? alienWidget : nativeWidget; + else // The receiver is typically deleted on mouse release with drag'n'drop. + enter = QApplication::widgetAt(event->globalPos()); + dispatchEnterLeave(enter, leaveAfterRelease); + leaveAfterRelease = 0; + lastMouseReceiver = enter; + } else if (!wasLeaveAfterRelease) { + if (activePopupWidget) { + if (!QWidget::mouseGrabber()) + lastMouseReceiver = alienGuard ? alienWidget : (nativeGuard ? nativeWidget : 0); + } else { + lastMouseReceiver = receiverGuard ? receiver : QApplication::widgetAt(event->globalPos()); + } + } + + return result; +} + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) +/* + This function should only be called when the widget changes visibility, i.e. + when the \a widget is shown, hidden or deleted. This function does nothing + if the widget is a top-level or native, i.e. not an alien widget. In that + case enter/leave events are genereated by the underlying windowing system. +*/ +extern QPointer qt_last_mouse_receiver; +extern QWidget *qt_button_down; +void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) +{ +#ifndef QT_NO_CURSOR +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) + if (!widget || widget->isWindow()) + return; +#else + if (!widget || widget->internalWinId() || widget->isWindow()) + return; +#endif + const bool widgetInShow = widget->isVisible() && !widget->data->in_destructor; + if (!widgetInShow && widget != qt_last_mouse_receiver) + return; // Widget was not under the cursor when it was hidden/deleted. + + if (widgetInShow && widget->parentWidget()->data->in_show) + return; // Ingore recursive show. + + QWidget *mouseGrabber = QWidget::mouseGrabber(); + if (mouseGrabber && mouseGrabber != widget) + return; // Someone else has the grab; enter/leave should not occur. + + QWidget *tlw = widget->window(); + if (tlw->data->in_destructor || tlw->data->is_closing) + return; // Closing down the business. + + if (widgetInShow && (!qt_last_mouse_receiver || qt_last_mouse_receiver->window() != tlw)) + return; // Mouse cursor not inside the widget's top-level. + + const QPoint globalPos(QCursor::pos()); + QPoint pos = tlw->mapFromGlobal(globalPos); + + // Find the current widget under the mouse. If this function was called from + // the widget's destructor, we have to make sure childAt() doesn't take into + // account widgets that are about to be destructed. + QWidget *widgetUnderCursor = tlw->d_func()->childAt_helper(pos, widget->data->in_destructor); + if (!widgetUnderCursor) + widgetUnderCursor = tlw; + else + pos = widgetUnderCursor->mapFrom(tlw, pos); + + if (widgetInShow && widgetUnderCursor != widget && !widget->isAncestorOf(widgetUnderCursor)) + return; // Mouse cursor not inside the widget or any of its children. + + if (widget->data->in_destructor && qt_button_down == widget) + qt_button_down = 0; + + // Send enter/leave events followed by a mouse move on the entered widget. + QMouseEvent e(QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); + sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver); +#endif // QT_NO_CURSOR +} +#endif // Q_WS_WIN || Q_WS_X11 || Q_WS_MAC + +/*! + Returns the desktop widget (also called the root window). + + The desktop may be composed of multiple screens, so it would be incorrect, + for example, to attempt to \e center some widget in the desktop's geometry. + QDesktopWidget has various functions for obtaining useful geometries upon + the desktop, such as QDesktopWidget::screenGeometry() and + QDesktopWidget::availableGeometry(). + + On X11, it is also possible to draw on the desktop. +*/ +QDesktopWidget *QApplication::desktop() +{ + if (!qt_desktopWidget || // not created yet + !(qt_desktopWidget->windowType() == Qt::Desktop)) { // reparented away + qt_desktopWidget = new QDesktopWidget(); + } + return qt_desktopWidget; +} + +#if !defined(Q_WS_QPA) && !defined(QT_NO_CLIPBOARD) +/*! + Returns a pointer to the application global clipboard. + + \note The QApplication object should already be constructed before + accessing the clipboard. +*/ +QClipboard *QApplication::clipboard() +{ + if (qt_clipboard == 0) { + if (!qApp) { + qWarning("QApplication: Must construct a QApplication before accessing a QClipboard"); + return 0; + } + qt_clipboard = new QClipboard(0); + } + return qt_clipboard; +} +#endif // Q_WS_QPA && QT_NO_CLIPBOARD +/*! + Sets whether Qt should use the system's standard colors, fonts, etc., to + \a on. By default, this is true. + + This function must be called before creating the QApplication object, like + this: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 6 + + \sa desktopSettingsAware() +*/ +void QApplication::setDesktopSettingsAware(bool on) +{ + QApplicationPrivate::obey_desktop_settings = on; +} + +/*! + Returns true if Qt is set to use the system's standard colors, fonts, etc.; + otherwise returns false. The default is true. + + \sa setDesktopSettingsAware() +*/ +bool QApplication::desktopSettingsAware() +{ + return QApplicationPrivate::obey_desktop_settings; +} + +/*! + Returns the current state of the modifier keys on the keyboard. The current + state is updated sychronously as the event queue is emptied of events that + will spontaneously change the keyboard state (QEvent::KeyPress and + QEvent::KeyRelease events). + + It should be noted this may not reflect the actual keys held on the input + device at the time of calling but rather the modifiers as last reported in + one of the above events. If no keys are being held Qt::NoModifier is + returned. + + \sa mouseButtons() +*/ + +Qt::KeyboardModifiers QApplication::keyboardModifiers() +{ + return QApplicationPrivate::modifier_buttons; +} + +/*! + Returns the current state of the buttons on the mouse. The current state is + updated syncronously as the event queue is emptied of events that will + spontaneously change the mouse state (QEvent::MouseButtonPress and + QEvent::MouseButtonRelease events). + + It should be noted this may not reflect the actual buttons held on the + input device at the time of calling but rather the mouse buttons as last + reported in one of the above events. If no mouse buttons are being held + Qt::NoButton is returned. + + \sa keyboardModifiers() +*/ + +Qt::MouseButtons QApplication::mouseButtons() +{ + return QApplicationPrivate::mouse_buttons; +} + +/*! + \fn bool QApplication::isSessionRestored() const + + Returns true if the application has been restored from an earlier + \l{Session Management}{session}; otherwise returns false. + + \sa sessionId(), commitData(), saveState() +*/ + + +/*! + \fn QString QApplication::sessionId() const + + Returns the current \l{Session Management}{session's} identifier. + + If the application has been restored from an earlier session, this + identifier is the same as it was in that previous session. The session + identifier is guaranteed to be unique both for different applications + and for different instances of the same application. + + \sa isSessionRestored(), sessionKey(), commitData(), saveState() +*/ + +/*! + \fn QString QApplication::sessionKey() const + + Returns the session key in the current \l{Session Management}{session}. + + If the application has been restored from an earlier session, this key is + the same as it was when the previous session ended. + + The session key changes with every call of commitData() or saveState(). + + \sa isSessionRestored(), sessionId(), commitData(), saveState() +*/ +#ifndef QT_NO_SESSIONMANAGER +bool QApplication::isSessionRestored() const +{ + Q_D(const QApplication); + return d->is_session_restored; +} + +QString QApplication::sessionId() const +{ + Q_D(const QApplication); + return d->session_id; +} + +QString QApplication::sessionKey() const +{ + Q_D(const QApplication); + return d->session_key; +} +#endif + + + +/*! + \since 4.2 + \fn void QApplication::commitDataRequest(QSessionManager &manager) + + This signal deals with \l{Session Management}{session management}. It is + emitted when the QSessionManager wants the application to commit all its + data. + + Usually this means saving all open files, after getting permission from + the user. Furthermore you may want to provide a means by which the user + can cancel the shutdown. + + You should not exit the application within this signal. Instead, + the session manager may or may not do this afterwards, depending on the + context. + + \warning Within this signal, no user interaction is possible, \e + unless you ask the \a manager for explicit permission. See + QSessionManager::allowsInteraction() and + QSessionManager::allowsErrorInteraction() for details and example + usage. + + \note You should use Qt::DirectConnection when connecting to this signal. + + \sa isSessionRestored(), sessionId(), saveState(), {Session Management} +*/ + +/*! + This function deals with \l{Session Management}{session management}. It is + invoked when the QSessionManager wants the application to commit all its + data. + + Usually this means saving all open files, after getting permission from the + user. Furthermore you may want to provide a means by which the user can + cancel the shutdown. + + You should not exit the application within this function. Instead, the + session manager may or may not do this afterwards, depending on the + context. + + \warning Within this function, no user interaction is possible, \e + unless you ask the \a manager for explicit permission. See + QSessionManager::allowsInteraction() and + QSessionManager::allowsErrorInteraction() for details and example + usage. + + The default implementation requests interaction and sends a close event to + all visible top-level widgets. If any event was rejected, the shutdown is + canceled. + + \sa isSessionRestored(), sessionId(), saveState(), {Session Management} +*/ +#ifndef QT_NO_SESSIONMANAGER +void QApplication::commitData(QSessionManager& manager ) +{ + emit commitDataRequest(manager); + if (manager.allowsInteraction()) { + QWidgetList done; + QWidgetList list = QApplication::topLevelWidgets(); + bool cancelled = false; + for (int i = 0; !cancelled && i < list.size(); ++i) { + QWidget* w = list.at(i); + if (w->isVisible() && !done.contains(w)) { + cancelled = !w->close(); + if (!cancelled) + done.append(w); + list = QApplication::topLevelWidgets(); + i = -1; + } + } + if (cancelled) + manager.cancel(); + } +} + +/*! + \since 4.2 + \fn void QApplication::saveStateRequest(QSessionManager &manager) + + This signal deals with \l{Session Management}{session management}. It is + invoked when the \l{QSessionManager}{session manager} wants the application + to preserve its state for a future session. + + For example, a text editor would create a temporary file that includes the + current contents of its edit buffers, the location of the cursor and other + aspects of the current editing session. + + You should never exit the application within this signal. Instead, the + session manager may or may not do this afterwards, depending on the + context. Futhermore, most session managers will very likely request a saved + state immediately after the application has been started. This permits the + session manager to learn about the application's restart policy. + + \warning Within this function, no user interaction is possible, \e + unless you ask the \a manager for explicit permission. See + QSessionManager::allowsInteraction() and + QSessionManager::allowsErrorInteraction() for details. + + \note You should use Qt::DirectConnection when connecting to this signal. + + \sa isSessionRestored(), sessionId(), commitData(), {Session Management} +*/ + +/*! + This function deals with \l{Session Management}{session management}. It is + invoked when the \l{QSessionManager}{session manager} wants the application + to preserve its state for a future session. + + For example, a text editor would create a temporary file that includes the + current contents of its edit buffers, the location of the cursor and other + aspects of the current editing session. + + You should never exit the application within this function. Instead, the + session manager may or may not do this afterwards, depending on the + context. Futhermore, most session managers will very likely request a saved + state immediately after the application has been started. This permits the + session manager to learn about the application's restart policy. + + \warning Within this function, no user interaction is possible, \e + unless you ask the \a manager for explicit permission. See + QSessionManager::allowsInteraction() and + QSessionManager::allowsErrorInteraction() for details. + + \sa isSessionRestored(), sessionId(), commitData(), {Session Management} +*/ + +void QApplication::saveState(QSessionManager &manager) +{ + emit saveStateRequest(manager); +} +#endif //QT_NO_SESSIONMANAGER +/* + Sets the time after which a drag should start to \a ms ms. + + \sa startDragTime() +*/ + +void QApplication::setStartDragTime(int ms) +{ + drag_time = ms; +} + +/*! + \property QApplication::startDragTime + \brief the time in milliseconds that a mouse button must be held down + before a drag and drop operation will begin + + If you support drag and drop in your application, and want to start a drag + and drop operation after the user has held down a mouse button for a + certain amount of time, you should use this property's value as the delay. + + Qt also uses this delay internally, e.g. in QTextEdit and QLineEdit, for + starting a drag. + + The default value is 500 ms. + + \sa startDragDistance(), {Drag and Drop} +*/ + +int QApplication::startDragTime() +{ + return drag_time; +} + +/* + Sets the distance after which a drag should start to \a l pixels. + + \sa startDragDistance() +*/ + +void QApplication::setStartDragDistance(int l) +{ + drag_distance = l; +} + +/*! + \property QApplication::startDragDistance + + If you support drag and drop in your application, and want to start a drag + and drop operation after the user has moved the cursor a certain distance + with a button held down, you should use this property's value as the + minimum distance required. + + For example, if the mouse position of the click is stored in \c startPos + and the current position (e.g. in the mouse move event) is \c currentPos, + you can find out if a drag should be started with code like this: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 7 + + Qt uses this value internally, e.g. in QFileDialog. + + The default value is 4 pixels. + + \sa startDragTime() QPoint::manhattanLength() {Drag and Drop} +*/ + +int QApplication::startDragDistance() +{ + return drag_distance; +} + +/*! + \fn void QApplication::setReverseLayout(bool reverse) + + Use setLayoutDirection() instead. +*/ + +/*! + \fn void QApplication::reverseLayout() + + Use layoutDirection() instead. +*/ + + +/*! + \obsolete + + Strips out vertical alignment flags and transforms an alignment \a align + of Qt::AlignLeft into Qt::AlignLeft or Qt::AlignRight according to the + language used. +*/ + +#ifdef QT3_SUPPORT +Qt::Alignment QApplication::horizontalAlignment(Qt::Alignment align) +{ + return QGuiApplicationPrivate::visualAlignment(layoutDirection(), align); +} +#endif + +/*! + Enters the main event loop and waits until exit() is called, then returns + the value that was set to exit() (which is 0 if exit() is called via + quit()). + + It is necessary to call this function to start event handling. The main + event loop receives events from the window system and dispatches these to + the application widgets. + + Generally, no user interaction can take place before calling exec(). As a + special case, modal widgets like QMessageBox can be used before calling + exec(), because modal widgets call exec() to start a local event loop. + + To make your application perform idle processing, i.e., executing a special + function whenever there are no pending events, use a QTimer with 0 timeout. + More advanced idle processing schemes can be achieved using processEvents(). + + We recommend that you connect clean-up code to the + \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your + application's \c{main()} function. This is because, on some platforms the + QApplication::exec() call may not return. For example, on the Windows + platform, when the user logs off, the system terminates the process after Qt + closes all top-level windows. Hence, there is \e{no guarantee} that the + application will have time to exit its event loop and execute code at the + end of the \c{main()} function, after the QApplication::exec() call. + + \sa quitOnLastWindowClosed, quit(), exit(), processEvents(), + QCoreApplication::exec() +*/ +int QApplication::exec() +{ +#ifndef QT_NO_ACCESSIBILITY + QAccessible::setRootObject(qApp); +#endif + return QApplicationBase::exec(); +} + +/*! \reimp + */ +bool QApplication::notify(QObject *receiver, QEvent *e) +{ + Q_D(QApplication); + // no events are delivered after ~QCoreApplication() has started + if (QApplicationPrivate::is_app_closing) + return true; + + if (receiver == 0) { // serious error + qWarning("QApplication::notify: Unexpected null receiver"); + return true; + } + +#ifndef QT_NO_DEBUG + d->checkReceiverThread(receiver); +#endif + + // capture the current mouse/keyboard state + if(e->spontaneous()) { + if (e->type() == QEvent::KeyPress + || e->type() == QEvent::KeyRelease) { + QKeyEvent *ke = static_cast(e); + QApplicationPrivate::modifier_buttons = ke->modifiers(); + } else if(e->type() == QEvent::MouseButtonPress + || e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(e); + QApplicationPrivate::modifier_buttons = me->modifiers(); + if(me->type() == QEvent::MouseButtonPress) + QApplicationPrivate::mouse_buttons |= me->button(); + else + QApplicationPrivate::mouse_buttons &= ~me->button(); + } +#if !defined(QT_NO_WHEELEVENT) || !defined(QT_NO_TABLETEVENT) + else if (false +# ifndef QT_NO_WHEELEVENT + || e->type() == QEvent::Wheel +# endif +# ifndef QT_NO_TABLETEVENT + || e->type() == QEvent::TabletMove + || e->type() == QEvent::TabletPress + || e->type() == QEvent::TabletRelease +# endif + ) { + QInputEvent *ie = static_cast(e); + QApplicationPrivate::modifier_buttons = ie->modifiers(); + } +#endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT + } + +#ifndef QT_NO_GESTURES + // walk through parents and check for gestures + if (d->gestureManager) { + switch (e->type()) { + case QEvent::Paint: + case QEvent::MetaCall: + case QEvent::DeferredDelete: + case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave: + case QEvent::Drop: case QEvent::DragResponse: + case QEvent::ChildAdded: case QEvent::ChildPolished: +#ifdef QT3_SUPPORT + case QEvent::ChildInsertedRequest: + case QEvent::ChildInserted: + case QEvent::LayoutHint: +#endif + case QEvent::ChildRemoved: + case QEvent::UpdateRequest: + case QEvent::UpdateLater: + case QEvent::AccessibilityPrepare: + case QEvent::LocaleChange: + case QEvent::Style: + case QEvent::IconDrag: + case QEvent::StyleChange: + case QEvent::AccessibilityHelp: + case QEvent::AccessibilityDescription: + case QEvent::GraphicsSceneDragEnter: + case QEvent::GraphicsSceneDragMove: + case QEvent::GraphicsSceneDragLeave: + case QEvent::GraphicsSceneDrop: + case QEvent::DynamicPropertyChange: + case QEvent::NetworkReplyUpdated: + break; + default: + if (receiver->isWidgetType()) { + if (d->gestureManager->filterEvent(static_cast(receiver), e)) + return true; + } else { + // a special case for events that go to QGesture objects. + // We pass the object to the gesture manager and it'll figure + // out if it's QGesture or not. + if (d->gestureManager->filterEvent(receiver, e)) + return true; + } + } + } +#endif // QT_NO_GESTURES + + // User input and window activation makes tooltips sleep + switch (e->type()) { + case QEvent::Wheel: + case QEvent::ActivationChange: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusOut: + case QEvent::FocusIn: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + d->toolTipFallAsleep.stop(); + // fall-through + case QEvent::Leave: + d->toolTipWakeUp.stop(); + default: + break; + } + + bool res = false; + if (!receiver->isWidgetType()) { + res = d->notify_helper(receiver, e); + } else switch (e->type()) { +#if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT) + case QEvent::Accel: + { + if (d->use_compat()) { + QKeyEvent* key = static_cast(e); + res = d->notify_helper(receiver, e); + + if (!res && !key->isAccepted()) + res = d->qt_dispatchAccelEvent(static_cast(receiver), key); + + // next lines are for compatibility with Qt <= 3.0.x: old + // QAccel was listening on toplevel widgets + if (!res && !key->isAccepted() && !static_cast(receiver)->isWindow()) + res = d->notify_helper(static_cast(receiver)->window(), e); + } + break; + } +#endif //QT3_SUPPORT && !QT_NO_SHORTCUT + case QEvent::ShortcutOverride: + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + bool isWidget = receiver->isWidgetType(); + bool isGraphicsWidget = false; +#ifndef QT_NO_GRAPHICSVIEW + isGraphicsWidget = !isWidget && qobject_cast(receiver); +#endif + if (!isWidget && !isGraphicsWidget) { + res = d->notify_helper(receiver, e); + break; + } + + QKeyEvent* key = static_cast(e); +#if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT) + if (d->use_compat() && d->qt_tryComposeUnicode(static_cast(receiver), key)) + break; +#endif + if (key->type()==QEvent::KeyPress) { +#ifndef QT_NO_SHORTCUT + // Try looking for a Shortcut before sending key events + if ((res = qApp->d_func()->shortcutMap.tryShortcutEvent(receiver, key))) + return res; +#endif + qt_in_tab_key_event = (key->key() == Qt::Key_Backtab + || key->key() == Qt::Key_Tab + || key->key() == Qt::Key_Left + || key->key() == Qt::Key_Up + || key->key() == Qt::Key_Right + || key->key() == Qt::Key_Down); + } + bool def = key->isAccepted(); + QPointer pr = receiver; + while (receiver) { + if (def) + key->accept(); + else + key->ignore(); + res = d->notify_helper(receiver, e); + QWidget *w = isWidget ? static_cast(receiver) : 0; +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsWidget *gw = isGraphicsWidget ? static_cast(receiver) : 0; +#endif + + if ((res && key->isAccepted()) + /* + QLineEdit will emit a signal on Key_Return, but + ignore the event, and sometimes the connected + slot deletes the QLineEdit (common in itemview + delegates), so we have to check if the widget + was destroyed even if the event was ignored (to + prevent a crash) + + note that we don't have to reset pw while + propagating (because the original receiver will + be destroyed if one of its ancestors is) + */ + || !pr + || (isWidget && (w->isWindow() || !w->parentWidget())) +#ifndef QT_NO_GRAPHICSVIEW + || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget())) +#endif + ) { + break; + } + +#ifndef QT_NO_GRAPHICSVIEW + receiver = w ? (QObject *)w->parentWidget() : (QObject *)gw->parentWidget(); +#else + receiver = w->parentWidget(); +#endif + } + qt_in_tab_key_event = false; + } + break; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + { + QWidget* w = static_cast(receiver); + + QMouseEvent* mouse = static_cast(e); + QPoint relpos = mouse->pos(); + + if (e->spontaneous()) { +#ifndef QT_NO_IM + QInputContext *ic = w->inputContext(); + if (ic + && w->testAttribute(Qt::WA_InputMethodEnabled) + && ic->filterEvent(mouse)) + return true; +#endif + + if (e->type() == QEvent::MouseButtonPress) { + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::ClickFocus, + Qt::MouseFocusReason); + } + + // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms + // like Mac OS X (probably others too), can optimize their views by not + // dispatching mouse move events. We have attributes to control hover, + // and mouse tracking, but as long as we are deciding to implement this + // feature without choice of opting-in or out, you ALWAYS have to have + // tracking enabled. Therefore, the other properties give a false sense of + // performance enhancement. + if (e->type() == QEvent::MouseMove && mouse->buttons() == 0) { + d->toolTipWidget = w; + d->toolTipPos = relpos; + d->toolTipGlobalPos = mouse->globalPos(); + d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive()?20:700, this); + } + } + + bool eventAccepted = mouse->isAccepted(); + + QPointer pw = w; + while (w) { + QMouseEvent me(mouse->type(), relpos, mouse->globalPos(), mouse->button(), mouse->buttons(), + mouse->modifiers()); + me.spont = mouse->spontaneous(); + // throw away any mouse-tracking-only mouse events + if (!w->hasMouseTracking() + && mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) { + // but still send them through all application event filters (normally done by notify_helper) + for (int i = 0; i < d->eventFilters.size(); ++i) { + register QObject *obj = d->eventFilters.at(i); + if (!obj) + continue; + if (obj->d_func()->threadData != w->d_func()->threadData) { + qWarning("QApplication: Object event filter cannot be in a different thread."); + continue; + } + if (obj->eventFilter(w, w == receiver ? mouse : &me)) + break; + } + res = true; + } else { + w->setAttribute(Qt::WA_NoMouseReplay, false); + res = d->notify_helper(w, w == receiver ? mouse : &me); + e->spont = false; + } + eventAccepted = (w == receiver ? mouse : &me)->isAccepted(); + if (res && eventAccepted) + break; + if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + break; + relpos += w->pos(); + w = w->parentWidget(); + } + + mouse->setAccepted(eventAccepted); + + if (e->type() == QEvent::MouseMove) { + if (!pw) + break; + + w = static_cast(receiver); + relpos = mouse->pos(); + QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos); + while (w) { + if (w->testAttribute(Qt::WA_Hover) && + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { + QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff); + d->notify_helper(w, &he); + } + if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + break; + relpos += w->pos(); + w = w->parentWidget(); + } + } + + d->hoverGlobalPos = mouse->globalPos(); + } + break; +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: + { + QWidget* w = static_cast(receiver); + QWheelEvent* wheel = static_cast(e); + QPoint relpos = wheel->pos(); + bool eventAccepted = wheel->isAccepted(); + + if (e->spontaneous()) { + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::WheelFocus, + Qt::MouseFocusReason); + } + + while (w) { + QWheelEvent we(relpos, wheel->globalPos(), wheel->delta(), wheel->buttons(), + wheel->modifiers(), wheel->orientation()); + we.spont = wheel->spontaneous(); + res = d->notify_helper(w, w == receiver ? wheel : &we); + eventAccepted = ((w == receiver) ? wheel : &we)->isAccepted(); + e->spont = false; + if ((res && eventAccepted) + || w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + break; + + relpos += w->pos(); + w = w->parentWidget(); + } + wheel->setAccepted(eventAccepted); + } + break; +#endif +#ifndef QT_NO_CONTEXTMENU + case QEvent::ContextMenu: + { + QWidget* w = static_cast(receiver); + QContextMenuEvent *context = static_cast(e); + QPoint relpos = context->pos(); + bool eventAccepted = context->isAccepted(); + while (w) { + QContextMenuEvent ce(context->reason(), relpos, context->globalPos(), context->modifiers()); + ce.spont = e->spontaneous(); + res = d->notify_helper(w, w == receiver ? context : &ce); + eventAccepted = ((w == receiver) ? context : &ce)->isAccepted(); + e->spont = false; + + if ((res && eventAccepted) + || w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + break; + + relpos += w->pos(); + w = w->parentWidget(); + } + context->setAccepted(eventAccepted); + } + break; +#endif // QT_NO_CONTEXTMENU +#ifndef QT_NO_TABLETEVENT + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + { + QWidget *w = static_cast(receiver); + QTabletEvent *tablet = static_cast(e); + QPoint relpos = tablet->pos(); + bool eventAccepted = tablet->isAccepted(); + while (w) { + QTabletEvent te(tablet->type(), relpos, tablet->globalPos(), + tablet->hiResGlobalPos(), tablet->device(), tablet->pointerType(), + tablet->pressure(), tablet->xTilt(), tablet->yTilt(), + tablet->tangentialPressure(), tablet->rotation(), tablet->z(), + tablet->modifiers(), tablet->uniqueId()); + te.spont = e->spontaneous(); + res = d->notify_helper(w, w == receiver ? tablet : &te); + eventAccepted = ((w == receiver) ? tablet : &te)->isAccepted(); + e->spont = false; + if ((res && eventAccepted) + || w->isWindow() + || w->testAttribute(Qt::WA_NoMousePropagation)) + break; + + relpos += w->pos(); + w = w->parentWidget(); + } + tablet->setAccepted(eventAccepted); + qt_tabletChokeMouse = tablet->isAccepted(); + } + break; +#endif // QT_NO_TABLETEVENT + +#if !defined(QT_NO_TOOLTIP) || !defined(QT_NO_WHATSTHIS) + case QEvent::ToolTip: + case QEvent::WhatsThis: + case QEvent::QueryWhatsThis: + { + QWidget* w = static_cast(receiver); + QHelpEvent *help = static_cast(e); + QPoint relpos = help->pos(); + bool eventAccepted = help->isAccepted(); + while (w) { + QHelpEvent he(help->type(), relpos, help->globalPos()); + he.spont = e->spontaneous(); + res = d->notify_helper(w, w == receiver ? help : &he); + e->spont = false; + eventAccepted = (w == receiver ? help : &he)->isAccepted(); + if ((res && eventAccepted) || w->isWindow()) + break; + + relpos += w->pos(); + w = w->parentWidget(); + } + help->setAccepted(eventAccepted); + } + break; +#endif +#if !defined(QT_NO_STATUSTIP) || !defined(QT_NO_WHATSTHIS) + case QEvent::StatusTip: + case QEvent::WhatsThisClicked: + { + QWidget *w = static_cast(receiver); + while (w) { + res = d->notify_helper(w, e); + if ((res && e->isAccepted()) || w->isWindow()) + break; + w = w->parentWidget(); + } + } + break; +#endif + +#ifndef QT_NO_DRAGANDDROP + case QEvent::DragEnter: { + QWidget* w = static_cast(receiver); + QDragEnterEvent *dragEvent = static_cast(e); +#ifdef Q_WS_MAC + // HIView has a slight difference in how it delivers events to children and parents + // It will not give a leave to a child's parent when it enters a child. + QWidget *currentTarget = QDragManager::self()->currentTarget(); + if (currentTarget) { + // Assume currentTarget did not get a leave + QDragLeaveEvent event; + QApplication::sendEvent(currentTarget, &event); + } +#endif +#ifndef QT_NO_GRAPHICSVIEW + // QGraphicsProxyWidget handles its own propagation, + // and we must not change QDragManagers currentTarget. + QWExtra *extra = w->window()->d_func()->extra; + if (extra && extra->proxyWidget) { + res = d->notify_helper(w, dragEvent); + break; + } +#endif + while (w) { + if (w->isEnabled() && w->acceptDrops()) { + res = d->notify_helper(w, dragEvent); + if (res && dragEvent->isAccepted()) { + QDragManager::self()->setCurrentTarget(w); + break; + } + } + if (w->isWindow()) + break; + dragEvent->p = w->mapToParent(dragEvent->p); + w = w->parentWidget(); + } + } + break; + case QEvent::DragMove: + case QEvent::Drop: + case QEvent::DragLeave: { + QWidget* w = static_cast(receiver); +#ifndef QT_NO_GRAPHICSVIEW + // QGraphicsProxyWidget handles its own propagation, + // and we must not change QDragManagers currentTarget. + QWExtra *extra = w->window()->d_func()->extra; + bool isProxyWidget = extra && extra->proxyWidget; + if (!isProxyWidget) +#endif + w = QDragManager::self()->currentTarget(); + + if (!w) { +#ifdef Q_WS_MAC + // HIView has a slight difference in how it delivers events to children and parents + // It will not give an enter to a child's parent when it leaves the child. + if (e->type() == QEvent::DragLeave) + break; + // Assume that w did not get an enter. + QDropEvent *dropEvent = static_cast(e); + QDragEnterEvent dragEnterEvent(dropEvent->pos(), dropEvent->possibleActions(), + dropEvent->mimeData(), dropEvent->mouseButtons(), + dropEvent->keyboardModifiers()); + QApplication::sendEvent(receiver, &dragEnterEvent); + w = QDragManager::self()->currentTarget(); + if (!w) +#endif + break; + } + if (e->type() == QEvent::DragMove || e->type() == QEvent::Drop) { + QDropEvent *dragEvent = static_cast(e); + QWidget *origReciver = static_cast(receiver); + while (origReciver && w != origReciver) { + dragEvent->p = origReciver->mapToParent(dragEvent->p); + origReciver = origReciver->parentWidget(); + } + } + res = d->notify_helper(w, e); + if (e->type() != QEvent::DragMove +#ifndef QT_NO_GRAPHICSVIEW + && !isProxyWidget +#endif + ) + QDragManager::self()->setCurrentTarget(0, e->type() == QEvent::Drop); + } + break; +#endif + case QEvent::TouchBegin: + // Note: TouchUpdate and TouchEnd events are never propagated + { + QWidget *widget = static_cast(receiver); + QTouchEvent *touchEvent = static_cast(e); + bool eventAccepted = touchEvent->isAccepted(); + if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) { + // give the widget focus if the focus policy allows it + QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, + Qt::ClickFocus, + Qt::MouseFocusReason); + } + + while (widget) { + // first, try to deliver the touch event + bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + touchEvent->setWidget(widget); + touchEvent->setAccepted(acceptTouchEvents); + QWeakPointer p = widget; + res = acceptTouchEvents && d->notify_helper(widget, touchEvent); + eventAccepted = touchEvent->isAccepted(); + if (p.isNull()) { + // widget was deleted + widget = 0; + } else { + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + } + touchEvent->spont = false; + if (res && eventAccepted) { + // the first widget to accept the TouchBegin gets an implicit grab. + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); + d->widgetForTouchPointId[touchPoint.id()] = widget; + } + break; + } else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + break; + } + QPoint offset = widget->pos(); + widget = widget->parentWidget(); + touchEvent->setWidget(widget); + for (int i = 0; i < touchEvent->_touchPoints.size(); ++i) { + QTouchEvent::TouchPoint &pt = touchEvent->_touchPoints[i]; + QRectF rect = pt.rect(); + rect.moveCenter(offset); + pt.d->rect = rect; + pt.d->startPos = pt.startPos() + offset; + pt.d->lastPos = pt.lastPos() + offset; + } + } + + touchEvent->setAccepted(eventAccepted); + break; + } + case QEvent::RequestSoftwareInputPanel: + case QEvent::CloseSoftwareInputPanel: +#ifndef QT_NO_IM + if (receiver->isWidgetType()) { + QWidget *w = static_cast(receiver); + QInputContext *ic = w->inputContext(); + if (ic && ic->filterEvent(e)) { + break; + } + } +#endif + res = d->notify_helper(receiver, e); + break; + +#ifndef QT_NO_GESTURES + case QEvent::NativeGesture: + { + // only propagate the first gesture event (after the GID_BEGIN) + QWidget *w = static_cast(receiver); + while (w) { + e->ignore(); + res = d->notify_helper(w, e); + if ((res && e->isAccepted()) || w->isWindow()) + break; + w = w->parentWidget(); + } + break; + } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (receiver->isWidgetType()) { + QWidget *w = static_cast(receiver); + QGestureEvent *gestureEvent = static_cast(e); + QList allGestures = gestureEvent->gestures(); + + bool eventAccepted = gestureEvent->isAccepted(); + bool wasAccepted = eventAccepted; + while (w) { + // send only gestures the widget expects + QList gestures; + QWidgetPrivate *wd = w->d_func(); + for (int i = 0; i < allGestures.size();) { + QGesture *g = allGestures.at(i); + Qt::GestureType type = g->gestureType(); + QMap::iterator contextit = + wd->gestureContext.find(type); + bool deliver = contextit != wd->gestureContext.end() && + (g->state() == Qt::GestureStarted || w == receiver || + (contextit.value() & Qt::ReceivePartialGestures)); + if (deliver) { + allGestures.removeAt(i); + gestures.append(g); + } else { + ++i; + } + } + if (!gestures.isEmpty()) { // we have gestures for this w + QGestureEvent ge(gestures); + ge.t = gestureEvent->t; + ge.spont = gestureEvent->spont; + ge.m_accept = wasAccepted; + ge.d_func()->accepted = gestureEvent->d_func()->accepted; + res = d->notify_helper(w, &ge); + gestureEvent->spont = false; + eventAccepted = ge.isAccepted(); + for (int i = 0; i < gestures.size(); ++i) { + QGesture *g = gestures.at(i); + // Ignore res [event return value] because handling of multiple gestures + // packed into a single QEvent depends on not consuming the event + if (eventAccepted || ge.isAccepted(g)) { + // if the gesture was accepted, mark the target widget for it + gestureEvent->d_func()->targetWidgets[g->gestureType()] = w; + gestureEvent->setAccepted(g, true); + } else { + // if the gesture was explicitly ignored by the application, + // put it back so a parent can get it + allGestures.append(g); + } + } + } + if (allGestures.isEmpty()) // everything delivered + break; + if (w->isWindow()) + break; + w = w->parentWidget(); + } + foreach (QGesture *g, allGestures) + gestureEvent->setAccepted(g, false); + gestureEvent->m_accept = false; // to make sure we check individual gestures + } else { + res = d->notify_helper(receiver, e); + } + break; + } +#endif // QT_NO_GESTURES +#ifdef QT_MAC_USE_COCOA + case QEvent::Enter: + if (receiver->isWidgetType()) { + QWidget *w = static_cast(receiver); + if (w->testAttribute(Qt::WA_AcceptTouchEvents)) + qt_widget_private(w)->registerTouchWindow(true); + } + res = d->notify_helper(receiver, e); + break; + case QEvent::Leave: + if (receiver->isWidgetType()) { + QWidget *w = static_cast(receiver); + if (w->testAttribute(Qt::WA_AcceptTouchEvents)) + qt_widget_private(w)->registerTouchWindow(false); + } + res = d->notify_helper(receiver, e); + break; +#endif + default: + res = d->notify_helper(receiver, e); + break; + } + + return res; +} + +bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) +{ + // send to all application event filters + if (sendThroughApplicationEventFilters(receiver, e)) + return true; + + if (receiver->isWidgetType()) { + QWidget *widget = static_cast(receiver); + +#if !defined(Q_WS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR)) + // toggle HasMouse widget state on enter and leave + if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) && + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window())) + widget->setAttribute(Qt::WA_UnderMouse, true); + else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) + widget->setAttribute(Qt::WA_UnderMouse, false); +#endif + + if (QLayout *layout=widget->d_func()->layout) { + layout->widgetEvent(e); + } + } + + // send to all receiver event filters + if (sendThroughObjectEventFilters(receiver, e)) + return true; + + // deliver the event + bool consumed = receiver->event(e); + e->spont = false; + return consumed; +} + + +/*! + \class QSessionManager + \brief The QSessionManager class provides access to the session manager. + + A session manager in a desktop environment (in which Qt GUI applications + live) keeps track of a session, which is a group of running applications, + each of which has a particular state. The state of an application contains + (most notably) the documents the application has open and the position and + size of its windows. + + The session manager is used to save the session, e.g., when the machine is + shut down, and to restore a session, e.g., when the machine is started up. + We recommend that you use QSettings to save an application's settings, + for example, window positions, recently used files, etc. When the + application is restarted by the session manager, you can restore the + settings. + + QSessionManager provides an interface between the application and the + session manager so that the program can work well with the session manager. + In Qt, session management requests for action are handled by the two + virtual functions QApplication::commitData() and QApplication::saveState(). + Both provide a reference to a session manager object as argument, to allow + the application to communicate with the session manager. The session + manager can only be accessed through these functions. + + No user interaction is possible \e unless the application gets explicit + permission from the session manager. You ask for permission by calling + allowsInteraction() or, if it is really urgent, allowsErrorInteraction(). + Qt does not enforce this, but the session manager may. + + You can try to abort the shutdown process by calling cancel(). The default + commitData() function does this if some top-level window rejected its + closeEvent(). + + For sophisticated session managers provided on Unix/X11, QSessionManager + offers further possibilities to fine-tune an application's session + management behavior: setRestartCommand(), setDiscardCommand(), + setRestartHint(), setProperty(), requestPhase2(). See the respective + function descriptions for further details. + + \sa QApplication, {Session Management} +*/ + +/*! \enum QSessionManager::RestartHint + + This enum type defines the circumstances under which this application wants + to be restarted by the session manager. The current values are: + + \value RestartIfRunning If the application is still running when the + session is shut down, it wants to be restarted + at the start of the next session. + + \value RestartAnyway The application wants to be started at the + start of the next session, no matter what. + (This is useful for utilities that run just + after startup and then quit.) + + \value RestartImmediately The application wants to be started immediately + whenever it is not running. + + \value RestartNever The application does not want to be restarted + automatically. + + The default hint is \c RestartIfRunning. +*/ + + +/*! + \fn QString QSessionManager::sessionId() const + + Returns the identifier of the current session. + + If the application has been restored from an earlier session, this + identifier is the same as it was in the earlier session. + + \sa sessionKey(), QApplication::sessionId() +*/ + +/*! + \fn QString QSessionManager::sessionKey() const + + Returns the session key in the current session. + + If the application has been restored from an earlier session, this key is + the same as it was when the previous session ended. + + The session key changes with every call of commitData() or saveState(). + + \sa sessionId(), QApplication::sessionKey() +*/ + +/*! + \fn void* QSessionManager::handle() const + + \internal +*/ + +/*! + \fn bool QSessionManager::allowsInteraction() + + Asks the session manager for permission to interact with the user. Returns + true if interaction is permitted; otherwise returns false. + + The rationale behind this mechanism is to make it possible to synchronize + user interaction during a shutdown. Advanced session managers may ask all + applications simultaneously to commit their data, resulting in a much + faster shutdown. + + When the interaction is completed we strongly recommend releasing the user + interaction semaphore with a call to release(). This way, other + applications may get the chance to interact with the user while your + application is still busy saving data. (The semaphore is implicitly + released when the application exits.) + + If the user decides to cancel the shutdown process during the interaction + phase, you must tell the session manager that this has happened by calling + cancel(). + + Here's an example of how an application's QApplication::commitData() might + be implemented: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 8 + + If an error occurred within the application while saving its data, you may + want to try allowsErrorInteraction() instead. + + \sa QApplication::commitData(), release(), cancel() +*/ + + +/*! + \fn bool QSessionManager::allowsErrorInteraction() + + Returns true if error interaction is permitted; otherwise returns false. + + This is similar to allowsInteraction(), but also enables the application to + tell the user about any errors that occur. Session managers may give error + interaction requests higher priority, which means that it is more likely + that an error interaction is permitted. However, you are still not + guaranteed that the session manager will allow interaction. + + \sa allowsInteraction(), release(), cancel() +*/ + +/*! + \fn void QSessionManager::release() + + Releases the session manager's interaction semaphore after an interaction + phase. + + \sa allowsInteraction(), allowsErrorInteraction() +*/ + +/*! + \fn void QSessionManager::cancel() + + Tells the session manager to cancel the shutdown process. Applications + should not call this function without asking the user first. + + \sa allowsInteraction(), allowsErrorInteraction() +*/ + +/*! + \fn void QSessionManager::setRestartHint(RestartHint hint) + + Sets the application's restart hint to \a hint. On application startup, the + hint is set to \c RestartIfRunning. + + \note These flags are only hints, a session manager may or may not respect + them. + + We recommend setting the restart hint in QApplication::saveState() because + most session managers perform a checkpoint shortly after an application's + startup. + + \sa restartHint() +*/ + +/*! + \fn QSessionManager::RestartHint QSessionManager::restartHint() const + + Returns the application's current restart hint. The default is + \c RestartIfRunning. + + \sa setRestartHint() +*/ + +/*! + \fn void QSessionManager::setRestartCommand(const QStringList& command) + + If the session manager is capable of restoring sessions it will execute + \a command in order to restore the application. The command defaults to + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 9 + + The \c -session option is mandatory; otherwise QApplication cannot tell + whether it has been restored or what the current session identifier is. + See QApplication::isSessionRestored() and QApplication::sessionId() for + details. + + If your application is very simple, it may be possible to store the entire + application state in additional command line options. This is usually a + very bad idea because command lines are often limited to a few hundred + bytes. Instead, use QSettings, temporary files, or a database for this + purpose. By marking the data with the unique sessionId(), you will be able + to restore the application in a future session. + + \sa restartCommand(), setDiscardCommand(), setRestartHint() +*/ + +/*! + \fn QStringList QSessionManager::restartCommand() const + + Returns the currently set restart command. + + To iterate over the list, you can use the \l foreach pseudo-keyword: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 10 + + \sa setRestartCommand(), restartHint() +*/ + +/*! + \fn void QSessionManager::setDiscardCommand(const QStringList& list) + + Sets the discard command to the given \a list. + + \sa discardCommand(), setRestartCommand() +*/ + + +/*! + \fn QStringList QSessionManager::discardCommand() const + + Returns the currently set discard command. + + To iterate over the list, you can use the \l foreach pseudo-keyword: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 11 + + \sa setDiscardCommand(), restartCommand(), setRestartCommand() +*/ + +/*! + \fn void QSessionManager::setManagerProperty(const QString &name, const QString &value) + \overload + + Low-level write access to the application's identification and state + records are kept in the session manager. + + The property called \a name has its value set to the string \a value. +*/ + +/*! + \fn void QSessionManager::setManagerProperty(const QString& name, + const QStringList& value) + + Low-level write access to the application's identification and state record + are kept in the session manager. + + The property called \a name has its value set to the string list \a value. +*/ + +/*! + \fn bool QSessionManager::isPhase2() const + + Returns true if the session manager is currently performing a second + session management phase; otherwise returns false. + + \sa requestPhase2() +*/ + +/*! + \fn void QSessionManager::requestPhase2() + + Requests a second session management phase for the application. The + application may then return immediately from the QApplication::commitData() + or QApplication::saveState() function, and they will be called again once + most or all other applications have finished their session management. + + The two phases are useful for applications such as the X11 window manager + that need to store information about another application's windows and + therefore have to wait until these applications have completed their + respective session management tasks. + + \note If another application has requested a second phase it may get called + before, simultaneously with, or after your application's second phase. + + \sa isPhase2() +*/ + +/***************************************************************************** + Stubbed session management support + *****************************************************************************/ +#ifndef QT_NO_SESSIONMANAGER +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_QWS) + +#if defined(Q_OS_WINCE) +HRESULT qt_CoCreateGuid(GUID* guid) +{ + // We will use the following information to create the GUID + // 1. absolute path to application + wchar_t tempFilename[MAX_PATH]; + if (!GetModuleFileName(0, tempFilename, MAX_PATH)) + return S_FALSE; + unsigned int hash = qHash(QString::fromWCharArray(tempFilename)); + guid->Data1 = hash; + // 2. creation time of file + QFileInfo info(QString::fromWCharArray(tempFilename)); + guid->Data2 = qHash(info.created().toTime_t()); + // 3. current system time + guid->Data3 = qHash(QDateTime::currentDateTime().toTime_t()); + return S_OK; +} +#if !defined(OLE32_MCOMGUID) || defined(QT_WINCE_FORCE_CREATE_GUID) +#define CoCreateGuid qt_CoCreateGuid +#endif + +#endif + +class QSessionManagerPrivate : public QObjectPrivate +{ +public: + QStringList restartCommand; + QStringList discardCommand; + QString sessionId; + QString sessionKey; + QSessionManager::RestartHint restartHint; +}; + +QSessionManager* qt_session_manager_self = 0; +QSessionManager::QSessionManager(QApplication * app, QString &id, QString &key) + : QObject(*new QSessionManagerPrivate, app) +{ + Q_D(QSessionManager); + setObjectName(QLatin1String("qt_sessionmanager")); + qt_session_manager_self = this; +#if defined(Q_WS_WIN) + wchar_t guidstr[40]; + GUID guid; + CoCreateGuid(&guid); + StringFromGUID2(guid, guidstr, 40); + id = QString::fromWCharArray(guidstr); + CoCreateGuid(&guid); + StringFromGUID2(guid, guidstr, 40); + key = QString::fromWCharArray(guidstr); +#endif + d->sessionId = id; + d->sessionKey = key; + d->restartHint = RestartIfRunning; +} + +QSessionManager::~QSessionManager() +{ + qt_session_manager_self = 0; +} + +QString QSessionManager::sessionId() const +{ + Q_D(const QSessionManager); + return d->sessionId; +} + +QString QSessionManager::sessionKey() const +{ + Q_D(const QSessionManager); + return d->sessionKey; +} + + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) +void* QSessionManager::handle() const +{ + return 0; +} +#endif + +#if !defined(Q_WS_WIN) +bool QSessionManager::allowsInteraction() +{ + return true; +} + +bool QSessionManager::allowsErrorInteraction() +{ + return true; +} +void QSessionManager::release() +{ +} + +void QSessionManager::cancel() +{ +} +#endif + + +void QSessionManager::setRestartHint(QSessionManager::RestartHint hint) +{ + Q_D(QSessionManager); + d->restartHint = hint; +} + +QSessionManager::RestartHint QSessionManager::restartHint() const +{ + Q_D(const QSessionManager); + return d->restartHint; +} + +void QSessionManager::setRestartCommand(const QStringList& command) +{ + Q_D(QSessionManager); + d->restartCommand = command; +} + +QStringList QSessionManager::restartCommand() const +{ + Q_D(const QSessionManager); + return d->restartCommand; +} + +void QSessionManager::setDiscardCommand(const QStringList& command) +{ + Q_D(QSessionManager); + d->discardCommand = command; +} + +QStringList QSessionManager::discardCommand() const +{ + Q_D(const QSessionManager); + return d->discardCommand; +} + +void QSessionManager::setManagerProperty(const QString&, const QString&) +{ +} + +void QSessionManager::setManagerProperty(const QString&, const QStringList&) +{ +} + +bool QSessionManager::isPhase2() const +{ + return false; +} + +void QSessionManager::requestPhase2() +{ +} + +#endif +#endif // QT_NO_SESSIONMANAGER + +/*! + \typedef QApplication::ColorMode + \compat + + Use ColorSpec instead. +*/ + +/*! + \fn Qt::MacintoshVersion QApplication::macVersion() + + Use QSysInfo::MacintoshVersion instead. +*/ + +/*! + \fn QApplication::ColorMode QApplication::colorMode() + + Use colorSpec() instead, and use ColorSpec as the enum type. +*/ + +/*! + \fn void QApplication::setColorMode(ColorMode mode) + + Use setColorSpec() instead, and pass a ColorSpec value instead. +*/ + +/*! + \fn bool QApplication::hasGlobalMouseTracking() + + This feature does not exist anymore. This function always returns true + in Qt 4. +*/ + +/*! + \fn void QApplication::setGlobalMouseTracking(bool dummy) + + This function does nothing in Qt 4. The \a dummy parameter is ignored. +*/ + +/*! + \fn void QApplication::flushX() + + Use flush() instead. +*/ + +/*! + \fn void QApplication::setWinStyleHighlightColor(const QColor &c) + + Use the palette instead. + + \oldcode + app.setWinStyleHighlightColor(color); + \newcode + QPalette palette(QApplication::palette()); + palette.setColor(QPalette::Highlight, color); + QApplication::setPalette(palette); + \endcode +*/ + +/*! + \fn void QApplication::setPalette(const QPalette &pal, bool b, const char* className = 0) + + Use the two-argument overload instead. +*/ + +/*! + \fn void QApplication::setFont(const QFont &font, bool b, const char* className = 0) + + Use the two-argument overload instead. +*/ + +/*! + \fn const QColor &QApplication::winStyleHighlightColor() + + Use QApplication::palette().color(QPalette::Active, QPalette::Highlight) instead. +*/ + +/*! + \fn QWidget *QApplication::widgetAt(int x, int y, bool child) + + Use the two-argument widgetAt() overload to get the child widget. To get + the top-level widget do this: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 12 +*/ + +/*! + \fn QWidget *QApplication::widgetAt(const QPoint &point, bool child) + + Use the single-argument widgetAt() overload to get the child widget. To get + the top-level widget do this: + + \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 13 +*/ + +#ifdef QT3_SUPPORT +QWidget *QApplication::mainWidget() +{ + return QApplicationPrivate::main_widget; +} +#endif +bool QApplicationPrivate::inPopupMode() const +{ + return QApplicationPrivate::popupWidgets != 0; +} + +/*! + \property QApplication::quitOnLastWindowClosed + + \brief whether the application implicitly quits when the last window is + closed. + + The default is true. + + If this property is true, the applications quits when the last visible + primary window (i.e. window with no parent) with the Qt::WA_QuitOnClose + attribute set is closed. By default this attribute is set for all widgets + except for sub-windows. Refer to \l{Qt::WindowType} for a detailed list of + Qt::Window objects. + + \sa quit(), QWidget::close() + */ + +void QApplication::setQuitOnLastWindowClosed(bool quit) +{ + QApplicationPrivate::quitOnLastWindowClosed = quit; +} + +bool QApplication::quitOnLastWindowClosed() +{ + return QApplicationPrivate::quitOnLastWindowClosed; +} + +void QApplicationPrivate::emitLastWindowClosed() +{ + if (qApp && qApp->d_func()->in_exec) { + if (QApplicationPrivate::quitOnLastWindowClosed) { + // get ready to quit, this event might be removed if the + // event loop is re-entered, however + QApplication::postEvent(qApp, new QEvent(QEvent::Quit)); + } + emit qApp->lastWindowClosed(); + } +} + +/*! \variable QApplication::NormalColors + \compat + + Use \l NormalColor instead. +*/ + +/*! \variable QApplication::CustomColors + \compat + + Use \l CustomColor instead. +*/ + +#ifdef QT_KEYPAD_NAVIGATION +/*! + Sets the kind of focus navigation Qt should use to \a mode. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \note On Symbian, setting the mode to Qt::NavigationModeCursorAuto will enable a + virtual mouse cursor on non touchscreen devices, which is controlled + by the cursor keys if there is no analog pointer device. + On other platforms and on touchscreen devices, it has the same + meaning as Qt::NavigationModeNone. + + \since 4.6 + + \sa keypadNavigationEnabled() +*/ +void QApplication::setNavigationMode(Qt::NavigationMode mode) +{ +#ifdef Q_OS_SYMBIAN + QApplicationPrivate::setNavigationMode(mode); +#else + QApplicationPrivate::navigationMode = mode; +#endif +} + +/*! + Returns what kind of focus navigation Qt is using. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \note On Symbian, the default mode is Qt::NavigationModeNone for touch + devices, and Qt::NavigationModeKeypadDirectional. + + \since 4.6 + + \sa keypadNavigationEnabled() +*/ +Qt::NavigationMode QApplication::navigationMode() +{ + return QApplicationPrivate::navigationMode; +} + +/*! + Sets whether Qt should use focus navigation suitable for use with a + minimal keypad. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \deprecated + + \sa setNavigationMode() +*/ +void QApplication::setKeypadNavigationEnabled(bool enable) +{ + if (enable) { +#ifdef Q_OS_SYMBIAN + QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional); +#else + QApplication::setNavigationMode(Qt::NavigationModeKeypadTabOrder); +#endif + } + else { + QApplication::setNavigationMode(Qt::NavigationModeNone); + } +} + +/*! + Returns true if Qt is set to use keypad navigation; otherwise returns + false. The default value is true on Symbian, but false on other platforms. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \deprecated + + \sa navigationMode() +*/ +bool QApplication::keypadNavigationEnabled() +{ + return QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadTabOrder || + QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadDirectional; +} +#endif + +/*! + \fn void QApplication::alert(QWidget *widget, int msec) + \since 4.3 + + Causes an alert to be shown for \a widget if the window is not the active + window. The alert is shown for \a msec miliseconds. If \a msec is zero (the + default), then the alert is shown indefinitely until the window becomes + active again. + + Currently this function does nothing on Qt for Embedded Linux. + + On Mac OS X, this works more at the application level and will cause the + application icon to bounce in the dock. + + On Windows, this causes the window's taskbar entry to flash for a time. If + \a msec is zero, the flashing will stop and the taskbar entry will turn a + different color (currently orange). + + On X11, this will cause the window to be marked as "demands attention", the + window must not be hidden (i.e. not have hide() called on it, but be + visible in some sort of way) in order for this to work. +*/ + +/*! + \property QApplication::cursorFlashTime + \brief the text cursor's flash (blink) time in milliseconds + + The flash time is the time required to display, invert and restore the + caret display. Usually the text cursor is displayed for half the cursor + flash time, then hidden for the same amount of time, but this may vary. + + The default value on X11 is 1000 milliseconds. On Windows, the + \gui{Control Panel} value is used and setting this property sets the cursor + flash time for all applications. + + We recommend that widgets do not cache this value as it may change at any + time if the user changes the global desktop settings. +*/ + +/*! + \property QApplication::doubleClickInterval + \brief the time limit in milliseconds that distinguishes a double click + from two consecutive mouse clicks + + The default value on X11 is 400 milliseconds. On Windows and Mac OS, the + operating system's value is used. However, on Windows and Symbian OS, + calling this function sets the double click interval for all applications. +*/ + +/*! + \property QApplication::keyboardInputInterval + \brief the time limit in milliseconds that distinguishes a key press + from two consecutive key presses + \since 4.2 + + The default value on X11 is 400 milliseconds. On Windows and Mac OS, the + operating system's value is used. +*/ + +/*! + \property QApplication::wheelScrollLines + \brief the number of lines to scroll a widget, when the + mouse wheel is rotated. + + If the value exceeds the widget's number of visible lines, the widget + should interpret the scroll operation as a single \e{page up} or + \e{page down}. If the widget is an \l{QAbstractItemView}{item view class}, + then the result of scrolling one \e line depends on the setting of the + widget's \l{QAbstractItemView::verticalScrollMode()}{scroll mode}. Scroll + one \e line can mean \l{QAbstractItemView::ScrollPerItem}{scroll one item} + or \l{QAbstractItemView::ScrollPerPixel}{scroll one pixel}. + + By default, this property has a value of 3. +*/ + +/*! + \fn void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) + + Enables the UI effect \a effect if \a enable is true, otherwise the effect + will not be used. + + \note All effects are disabled on screens running at less than 16-bit color + depth. + + \sa isEffectEnabled(), Qt::UIEffect, setDesktopSettingsAware() +*/ + +/*! + \fn bool QApplication::isEffectEnabled(Qt::UIEffect effect) + + Returns true if \a effect is enabled; otherwise returns false. + + By default, Qt will try to use the desktop settings. To prevent this, call + setDesktopSettingsAware(false). + + \note All effects are disabled on screens running at less than 16-bit color + depth. + + \sa setEffectEnabled(), Qt::UIEffect +*/ + +/*! + \fn QWidget *QApplication::mainWidget() + + Returns the main application widget, or 0 if there is no main widget. +*/ + +/*! + \fn void QApplication::setMainWidget(QWidget *mainWidget) + + Sets the application's main widget to \a mainWidget. + + In most respects the main widget is like any other widget, except that if + it is closed, the application exits. QApplication does \e not take + ownership of the \a mainWidget, so if you create your main widget on the + heap you must delete it yourself. + + You need not have a main widget; connecting lastWindowClosed() to quit() + is an alternative. + + On X11, this function also resizes and moves the main widget according + to the \e -geometry command-line option, so you should set the default + geometry (using \l QWidget::setGeometry()) before calling setMainWidget(). + + \sa mainWidget(), exec(), quit() +*/ + +/*! + \fn void QApplication::beep() + + Sounds the bell, using the default volume and sound. The function is \e not + available in Qt for Embedded Linux. +*/ + +/*! + \fn void QApplication::setOverrideCursor(const QCursor &cursor) + + Sets the application override cursor to \a cursor. + + Application override cursors are intended for showing the user that the + application is in a special state, for example during an operation that + might take some time. + + This cursor will be displayed in all the application's widgets until + restoreOverrideCursor() or another setOverrideCursor() is called. + + Application cursors are stored on an internal stack. setOverrideCursor() + pushes the cursor onto the stack, and restoreOverrideCursor() pops the + active cursor off the stack. changeOverrideCursor() changes the curently + active application override cursor. + + Every setOverrideCursor() must eventually be followed by a corresponding + restoreOverrideCursor(), otherwise the stack will never be emptied. + + Example: + \snippet doc/src/snippets/code/src_gui_kernel_qapplication_x11.cpp 0 + + \sa overrideCursor(), restoreOverrideCursor(), changeOverrideCursor(), + QWidget::setCursor() +*/ + +/*! + \fn void QApplication::restoreOverrideCursor() + + Undoes the last setOverrideCursor(). + + If setOverrideCursor() has been called twice, calling + restoreOverrideCursor() will activate the first cursor set. Calling this + function a second time restores the original widgets' cursors. + + \sa setOverrideCursor(), overrideCursor() +*/ + +/*! + \macro qApp + \relates QApplication + + A global pointer referring to the unique application object. It is + equivalent to the pointer returned by the QCoreApplication::instance() + function except that, in GUI applications, it is a pointer to a + QApplication instance. + + Only one application object can be created. + + \sa QCoreApplication::instance() +*/ + +#ifndef QT_NO_IM +// ************************************************************************ +// Input Method support +// ************************************************************************ + +/*! + This function replaces the QInputContext instance used by the application + with \a inputContext. + + Qt takes ownership of the given \a inputContext. + + \sa inputContext() +*/ +void QApplication::setInputContext(QInputContext *inputContext) +{ + if (inputContext == QApplicationPrivate::inputContext) + return; + if (!inputContext) { + qWarning("QApplication::setInputContext: called with 0 input context"); + return; + } + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = inputContext; + QApplicationPrivate::inputContext->setParent(this); +} + +/*! + Returns the QInputContext instance used by the application. + + \sa setInputContext() +*/ +QInputContext *QApplication::inputContext() const +{ + Q_D(const QApplication); + Q_UNUSED(d);// only static members being used. + if (QApplicationPrivate::is_app_closing) + return d->inputContext; +#ifdef Q_WS_X11 + if (!X11) + return 0; + if (!d->inputContext) { + QApplication *that = const_cast(this); + QInputContext *qic = QInputContextFactory::create(X11->default_im, that); + // fallback to default X Input Method. + if (!qic) + qic = QInputContextFactory::create(QLatin1String("xim"), that); + that->d_func()->inputContext = qic; + } +#elif defined(Q_OS_SYMBIAN) + if (!d->inputContext) { + QApplication *that = const_cast(this); + const QStringList keys = QInputContextFactory::keys(); + // Try hbim and coefep first, then try others. + if (keys.contains(QLatin1String("hbim"))) { + that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("hbim"), that); + } else if (keys.contains(QLatin1String("coefep"))) { + that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("coefep"), that); + } else { + for (int c = 0; c < keys.size() && !d->inputContext; ++c) { + that->d_func()->inputContext = QInputContextFactory::create(keys[c], that); + } + } + } +#endif + return d->inputContext; +} +#endif // QT_NO_IM + +bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event) +{ + return QApplicationBase::sendSpontaneousEvent(receiver, event); +} + + +void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason) +{ + QWidget *focusWidget = widget; + while (focusWidget) { + if (focusWidget->isEnabled() + && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) { + focusWidget->setFocus(focusReason); + break; + } + if (focusWidget->isWindow()) + break; + focusWidget = focusWidget->parentWidget(); + } +} + +bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) +{ + QWidget *f = w; + while (f->d_func()->extra && f->d_func()->extra->focus_proxy) + f = f->d_func()->extra->focus_proxy; + + if ((w->focusPolicy() & policy) != policy) + return false; + if (w != f && (f->focusPolicy() & policy) != policy) + return false; + return true; +} + +/*! \fn QDecoration &QApplication::qwsDecoration() + Return the QWSDecoration used for decorating windows. + + \warning This method is non-portable. It is only available in + Qt for Embedded Linux. + + \sa QDecoration +*/ + +/*! + \fn void QApplication::qwsSetDecoration(QDecoration *decoration) + + Sets the QDecoration derived class to use for decorating the + windows used by Qt for Embedded Linux to the \a decoration + specified. + + This method is non-portable. It is only available in Qt for Embedded Linux. + + \sa QDecoration +*/ + +/*! \fn QDecoration* QApplication::qwsSetDecoration(const QString &decoration) + \overload + + Requests a QDecoration object for \a decoration from the + QDecorationFactory. + + The string must be one of the QDecorationFactory::keys(). Keys are case + insensitive. + + A later call to the QApplication constructor will override the requested + style when a "-style" option is passed in as a commandline parameter. + + Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object + returned is set as the application's GUI style. +*/ + +/*! + \fn bool QApplication::qwsEventFilter(QWSEvent *event) + + This virtual function is only implemented under Qt for Embedded Linux. + + If you create an application that inherits QApplication and + reimplement this function, you get direct access to all QWS (Q + Window System) events that the are received from the QWS master + process. The events are passed in the \a event parameter. + + Return true if you want to stop the event from being processed. + Return false for normal event dispatching. The default + implementation returns false. +*/ + +/*! \fn void QApplication::qwsSetCustomColors(QRgb *colorTable, int start, int numColors) + Set Qt for Embedded Linux custom color table. + + Qt for Embedded Linux on 8-bpp displays allocates a standard 216 color cube. + The remaining 40 colors may be used by setting a custom color + table in the QWS master process before any clients connect. + + \a colorTable is an array of up to 40 custom colors. \a start is + the starting index (0-39) and \a numColors is the number of colors + to be set (1-40). + + This method is non-portable. It is available \e only in + Qt for Embedded Linux. + + \note The custom colors will not be used by the default screen + driver. To make use of the new colors, implement a custom screen + driver, or use QDirectPainter. +*/ + +/*! \fn int QApplication::qwsProcessEvent(QWSEvent* event) + \internal +*/ + +/*! \fn int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) + \internal +*/ + +/*! \fn int QApplication::x11ProcessEvent(XEvent* event) + This function does the core processing of individual X + \a{event}s, normally by dispatching Qt events to the right + destination. + + It returns 1 if the event was consumed by special handling, 0 if + the \a event was consumed by normal handling, and -1 if the \a + event was for an unrecognized widget. + + \sa x11EventFilter() +*/ + +/*! + \fn bool QApplication::x11EventFilter(XEvent *event) + + \warning This virtual function is only implemented under X11. + + If you create an application that inherits QApplication and + reimplement this function, you get direct access to all X events + that the are received from the X server. The events are passed in + the \a event parameter. + + Return true if you want to stop the event from being processed. + Return false for normal event dispatching. The default + implementation returns false. + + It is only the directly addressed messages that are filtered. + You must install an event filter directly on the event + dispatcher, which is returned by + QAbstractEventDispatcher::instance(), to handle system wide + messages. + + \sa x11ProcessEvent() +*/ + +/*! \fn void QApplication::winFocus(QWidget *widget, bool gotFocus) + \internal + \since 4.1 + + If \a gotFocus is true, \a widget will become the active window. + Otherwise the active window is reset to 0. +*/ + +/*! \fn void QApplication::winMouseButtonUp() + \internal + */ + +/*! \fn void QApplication::syncX() + Synchronizes with the X server in the X11 implementation. + This normally takes some time. Does nothing on other platforms. +*/ + +void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +{ + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i]; + + // preserve the sub-pixel resolution + QRectF rect = touchPoint.screenRect(); + const QPointF screenPos = rect.center(); + const QPointF delta = screenPos - screenPos.toPoint(); + + rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta); + touchPoint.d->rect = rect; + if (touchPoint.state() == Qt::TouchPointPressed) { + touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta; + touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta; + } + } +} + +void QApplicationPrivate::initializeMultitouch() +{ + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); + + initializeMultitouch_sys(); +} + +void QApplicationPrivate::cleanupMultitouch() +{ + cleanupMultitouch_sys(); + + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); +} + +int QApplicationPrivate::findClosestTouchPointId(const QPointF &screenPos) +{ + int closestTouchPointId = -1; + qreal closestDistance = qreal(0.); + foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) { + qreal distance = QLineF(screenPos, touchPoint.screenPos()).length(); + if (closestTouchPointId == -1 || distance < closestDistance) { + closestTouchPointId = touchPoint.id(); + closestDistance = distance; + } + } + return closestTouchPointId; +} + +void QApplicationPrivate::translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints) +{ + QApplicationPrivate *d = self; + typedef QPair > StatesAndTouchPoints; + QHash widgetsNeedingEvents; + + for (int i = 0; i < touchPoints.count(); ++i) { + QTouchEvent::TouchPoint touchPoint = touchPoints.at(i); + // explicitly detach from the original touch point that we got, so even + // if the touchpoint structs are reused, we will make a copy that we'll + // deliver to the user (which might want to store the struct for later use). + touchPoint.d = touchPoint.d->detach(); + + // update state + QWeakPointer widget; + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + { + if (deviceType == QTouchEvent::TouchPad) { + // on touch-pads, send all touch points to the same widget + widget = d->widgetForTouchPointId.isEmpty() + ? QWeakPointer() + : d->widgetForTouchPointId.constBegin().value(); + } + + if (!widget) { + // determine which widget this event will go to + if (!window) + window = QApplication::topLevelAt(touchPoint.screenPos().toPoint()); + if (!window) + continue; + widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint())); + if (!widget) + widget = window; + } + + if (deviceType == QTouchEvent::TouchScreen) { + int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos()); + QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId).data(); + if (closestWidget + && (widget.data()->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget.data()))) { + widget = closestWidget; + } + } + + d->widgetForTouchPointId[touchPoint.id()] = widget; + touchPoint.d->startScreenPos = touchPoint.screenPos(); + touchPoint.d->lastScreenPos = touchPoint.screenPos(); + touchPoint.d->startNormalizedPos = touchPoint.normalizedPos(); + touchPoint.d->lastNormalizedPos = touchPoint.normalizedPos(); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.d->pressure = qreal(1.); + + d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint); + break; + } + case Qt::TouchPointReleased: + { + widget = d->widgetForTouchPointId.take(touchPoint.id()); + if (!widget) + continue; + + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id()); + touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos(); + touchPoint.d->lastScreenPos = previousTouchPoint.screenPos(); + touchPoint.d->startPos = previousTouchPoint.startPos(); + touchPoint.d->lastPos = previousTouchPoint.pos(); + touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos(); + touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos(); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.d->pressure = qreal(0.); + break; + } + default: + widget = d->widgetForTouchPointId.value(touchPoint.id()); + if (!widget) + continue; + + Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id())); + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id()); + touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos(); + touchPoint.d->lastScreenPos = previousTouchPoint.screenPos(); + touchPoint.d->startPos = previousTouchPoint.startPos(); + touchPoint.d->lastPos = previousTouchPoint.pos(); + touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos(); + touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos(); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.d->pressure = qreal(1.); + d->appCurrentTouchPoints[touchPoint.id()] = touchPoint; + break; + } + Q_ASSERT(widget.data() != 0); + + // make the *scene* functions return the same as the *screen* functions + touchPoint.d->sceneRect = touchPoint.screenRect(); + touchPoint.d->startScenePos = touchPoint.startScreenPos(); + touchPoint.d->lastScenePos = touchPoint.lastScreenPos(); + + StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget.data()]; + maskAndPoints.first |= touchPoint.state(); + if (touchPoint.isPrimary()) + maskAndPoints.first |= Qt::TouchPointPrimary; + maskAndPoints.second.append(touchPoint); + } + + if (widgetsNeedingEvents.isEmpty()) + return; + + QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = it.key(); + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QEvent::Type eventType; + switch (it.value().first & Qt::TouchPointStateMask) { + case Qt::TouchPointPressed: + eventType = QEvent::TouchBegin; + break; + case Qt::TouchPointReleased: + eventType = QEvent::TouchEnd; + break; + case Qt::TouchPointStationary: + // don't send the event if nothing changed + continue; + default: + eventType = QEvent::TouchUpdate; + break; + } + + QTouchEvent touchEvent(eventType, + deviceType, + QApplication::keyboardModifiers(), + it.value().first, + it.value().second); + updateTouchPointsForWidget(widget, &touchEvent); + + switch (touchEvent.type()) { + case QEvent::TouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + (void ) QApplication::sendSpontaneousEvent(widget, &touchEvent); + break; + } + default: + if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) { + if (touchEvent.type() == QEvent::TouchEnd) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false); + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + } + break; + } + } +} + +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints) +{ + QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); +} + +#ifndef QT_NO_GESTURES +QGestureManager* QGestureManager::instance() +{ + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); + if (!qAppPriv) + return 0; + if (!qAppPriv->gestureManager) + qAppPriv->gestureManager = new QGestureManager(qApp); + return qAppPriv->gestureManager; +} +#endif // QT_NO_GESTURES + +QString QApplicationPrivate::qmljsDebugArgumentsString() +{ + return qmljs_debug_arguments; +} + +QT_END_NAMESPACE + +#include "moc_qapplication.cpp" diff --git a/src/widgets/kernel/qapplication.h b/src/widgets/kernel/qapplication.h new file mode 100644 index 0000000000..3a5f02f144 --- /dev/null +++ b/src/widgets/kernel/qapplication.h @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAPPLICATION_H +#define QAPPLICATION_H + +#include +#include +#include +#include +#include +#ifdef QT_INCLUDE_COMPAT +# include +#endif +#ifdef QT3_SUPPORT +# include +# include +#endif +#ifdef Q_WS_QWS +# include +# include +#endif +#ifdef Q_WS_QPA +# include +#endif + +QT_BEGIN_HEADER + +#if defined(Q_OS_SYMBIAN) +class CApaApplication; +#endif + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QSessionManager; +class QDesktopWidget; +class QStyle; +class QEventLoop; +class QIcon; +class QInputContext; +template class QList; +class QLocale; +#if defined(Q_WS_QWS) +class QDecoration; +#elif defined(Q_WS_QPA) +class QPlatformNativeInterface; +#endif +#if defined(Q_OS_SYMBIAN) +class QSymbianEvent; +#endif + +class QApplication; +class QApplicationPrivate; +#if defined(qApp) +#undef qApp +#endif +#define qApp (static_cast(QCoreApplication::instance())) + +#ifdef Q_WS_QPA +#define QApplicationBase QGuiApplication +#else +#define QApplicationBase QCoreApplication +#endif + +class Q_GUI_EXPORT QApplication : public QApplicationBase +{ + Q_OBJECT + Q_PROPERTY(QIcon windowIcon READ windowIcon WRITE setWindowIcon) + Q_PROPERTY(int cursorFlashTime READ cursorFlashTime WRITE setCursorFlashTime) + Q_PROPERTY(int doubleClickInterval READ doubleClickInterval WRITE setDoubleClickInterval) + Q_PROPERTY(int keyboardInputInterval READ keyboardInputInterval WRITE setKeyboardInputInterval) +#ifndef QT_NO_WHEELEVENT + Q_PROPERTY(int wheelScrollLines READ wheelScrollLines WRITE setWheelScrollLines) +#endif + Q_PROPERTY(QSize globalStrut READ globalStrut WRITE setGlobalStrut) + Q_PROPERTY(int startDragTime READ startDragTime WRITE setStartDragTime) + Q_PROPERTY(int startDragDistance READ startDragDistance WRITE setStartDragDistance) + Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE setQuitOnLastWindowClosed) +#ifndef QT_NO_STYLE_STYLESHEET + Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet) +#endif +#ifdef Q_WS_WINCE + Q_PROPERTY(int autoMaximizeThreshold READ autoMaximizeThreshold WRITE setAutoMaximizeThreshold) +#endif + Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) + +public: + enum Type { Tty, GuiClient, GuiServer }; + +#ifdef Q_OS_SYMBIAN + typedef CApaApplication * (*QS60MainApplicationFactory)(); +#endif + +#ifndef qdoc + QApplication(int &argc, char **argv, int = ApplicationFlags); + QApplication(int &argc, char **argv, bool GUIenabled, int = ApplicationFlags); + QApplication(int &argc, char **argv, Type, int = ApplicationFlags); +#if defined(Q_WS_X11) + QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0, int = ApplicationFlags); + QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0, int = ApplicationFlags); +#endif +#if defined(Q_OS_SYMBIAN) + QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int = ApplicationFlags); +#endif +#endif + virtual ~QApplication(); + + static Type type(); + + static QStyle *style(); + static void setStyle(QStyle*); + static QStyle *setStyle(const QString&); + enum ColorSpec { NormalColor=0, CustomColor=1, ManyColor=2 }; + static int colorSpec(); + static void setColorSpec(int); + // ### Qt4 compatibility, remove? + static inline void setGraphicsSystem(const QString &) {} + + using QGuiApplication::palette; + static QPalette palette(const QWidget *); + static QPalette palette(const char *className); + static void setPalette(const QPalette &, const char* className = 0); + static QFont font(); + static QFont font(const QWidget*); + static QFont font(const char *className); + static void setFont(const QFont &, const char* className = 0); + static QFontMetrics fontMetrics(); + + static void setWindowIcon(const QIcon &icon); + static QIcon windowIcon(); + + +#ifdef QT3_SUPPORT + static QT3_SUPPORT QWidget *mainWidget(); + static QT3_SUPPORT void setMainWidget(QWidget *); +#endif + + static QWidgetList allWidgets(); + static QWidgetList topLevelWidgets(); + + static QDesktopWidget *desktop(); + + static QWidget *activePopupWidget(); + static QWidget *activeModalWidget(); +#if !defined(Q_WS_QPA) && !defined(QT_NO_CLIPBOARD) + static QClipboard *clipboard(); +#endif + static QWidget *focusWidget(); + + static QWidget *activeWindow(); + static void setActiveWindow(QWidget* act); + + static QWidget *widgetAt(const QPoint &p); + static inline QWidget *widgetAt(int x, int y) { return widgetAt(QPoint(x, y)); } + static QWidget *topLevelAt(const QPoint &p); + static inline QWidget *topLevelAt(int x, int y) { return topLevelAt(QPoint(x, y)); } + + static void syncX(); + static void beep(); + static void alert(QWidget *widget, int duration = 0); + + static Qt::KeyboardModifiers keyboardModifiers(); + static Qt::MouseButtons mouseButtons(); + + static void setDesktopSettingsAware(bool); + static bool desktopSettingsAware(); + + static void setCursorFlashTime(int); + static int cursorFlashTime(); + + static void setDoubleClickInterval(int); + static int doubleClickInterval(); + + static void setKeyboardInputInterval(int); + static int keyboardInputInterval(); + +#ifndef QT_NO_WHEELEVENT + static void setWheelScrollLines(int); + static int wheelScrollLines(); +#endif + static void setGlobalStrut(const QSize &); + static QSize globalStrut(); + + static void setStartDragTime(int ms); + static int startDragTime(); + static void setStartDragDistance(int l); + static int startDragDistance(); + + static bool isEffectEnabled(Qt::UIEffect); + static void setEffectEnabled(Qt::UIEffect, bool enable = true); + +#if defined(Q_WS_MAC) + virtual bool macEventFilter(EventHandlerCallRef, EventRef); +#endif +#if defined(Q_WS_X11) + virtual bool x11EventFilter(XEvent *); + virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only); + int x11ProcessEvent(XEvent*); +#endif +#if defined(Q_OS_SYMBIAN) + int symbianProcessEvent(const QSymbianEvent *event); + virtual bool symbianEventFilter(const QSymbianEvent *event); +#endif +#if defined(Q_WS_QWS) + virtual bool qwsEventFilter(QWSEvent *); + int qwsProcessEvent(QWSEvent*); + void qwsSetCustomColors(QRgb *colortable, int start, int numColors); +#ifndef QT_NO_QWS_MANAGER + static QDecoration &qwsDecoration(); + static void qwsSetDecoration(QDecoration *); + static QDecoration *qwsSetDecoration(const QString &decoration); +#endif +#endif + +#if defined(Q_WS_QPA) + static QPlatformNativeInterface *platformNativeInterface(); +#endif + + +#if defined(Q_WS_WIN) + void winFocus(QWidget *, bool); + static void winMouseButtonUp(); +#endif +#ifndef QT_NO_SESSIONMANAGER + // session management + bool isSessionRestored() const; + QString sessionId() const; + QString sessionKey() const; + virtual void commitData(QSessionManager& sm); + virtual void saveState(QSessionManager& sm); +#endif + +#ifndef QT_NO_IM + void setInputContext(QInputContext *); + QInputContext *inputContext() const; +#endif + + static int exec(); + bool notify(QObject *, QEvent *); + + + static void setQuitOnLastWindowClosed(bool quit); + static bool quitOnLastWindowClosed(); + +#ifdef QT_KEYPAD_NAVIGATION + static Q_DECL_DEPRECATED void setKeypadNavigationEnabled(bool); + static bool keypadNavigationEnabled(); + static void setNavigationMode(Qt::NavigationMode mode); + static Qt::NavigationMode navigationMode(); +#endif + +Q_SIGNALS: + void lastWindowClosed(); + void focusChanged(QWidget *old, QWidget *now); +#ifndef QT_NO_SESSIONMANAGER + void commitDataRequest(QSessionManager &sessionManager); + void saveStateRequest(QSessionManager &sessionManager); +#endif + +public: + QString styleSheet() const; +public Q_SLOTS: +#ifndef QT_NO_STYLE_STYLESHEET + void setStyleSheet(const QString& sheet); +#endif +#ifdef Q_WS_WINCE + void setAutoMaximizeThreshold(const int threshold); + int autoMaximizeThreshold() const; +#endif + void setAutoSipEnabled(const bool enabled); + bool autoSipEnabled() const; + static void closeAllWindows(); + static void aboutQt(); + +protected: +#if defined(Q_WS_QWS) + void setArgs(int, char **); +#endif + bool event(QEvent *); + bool compressEvent(QEvent *, QObject *receiver, QPostEventList *); + +#ifdef QT3_SUPPORT +public: + static inline QT3_SUPPORT void setReverseLayout(bool b) { setLayoutDirection(b?Qt::RightToLeft:Qt::LeftToRight); } + static inline bool QT3_SUPPORT reverseLayout() { return layoutDirection() == Qt::RightToLeft; } + static QT3_SUPPORT Qt::Alignment horizontalAlignment(Qt::Alignment align); + typedef int ColorMode; + enum { NormalColors = NormalColor, CustomColors = CustomColor }; + static inline QT3_SUPPORT ColorMode colorMode() { return static_cast(colorSpec()); } + static inline QT3_SUPPORT void setColorMode(ColorMode mode) { setColorSpec(int(mode)); } +#if defined(Q_OS_WIN32) || defined(Q_OS_CYGWIN) + static QT3_SUPPORT Qt::WindowsVersion winVersion() { return (Qt::WindowsVersion)QSysInfo::WindowsVersion; } +#endif +#if defined(Q_OS_MAC) + static QT3_SUPPORT Qt::MacintoshVersion macVersion() { return (Qt::MacintoshVersion)QSysInfo::MacintoshVersion; } +#endif +# ifndef QT_NO_CURSOR + inline static QT3_SUPPORT void setOverrideCursor(const QCursor &cursor, bool replace) + { if (replace) changeOverrideCursor(cursor); else setOverrideCursor(cursor); } +# endif + inline static QT3_SUPPORT bool hasGlobalMouseTracking() {return true;} + inline static QT3_SUPPORT void setGlobalMouseTracking(bool) {} + inline static QT3_SUPPORT void flushX() { flush(); } + static inline QT3_SUPPORT void setWinStyleHighlightColor(const QColor &c) { + QPalette p(palette()); + p.setColor(QPalette::Highlight, c); + setPalette(p); + } + static inline QT3_SUPPORT const QColor &winStyleHighlightColor() + { return palette().color(QPalette::Active, QPalette::Highlight); } + static inline QT3_SUPPORT void setPalette(const QPalette &pal, bool, const char* className = 0) + { setPalette(pal, className); } + static inline QT3_SUPPORT void setFont(const QFont &font, bool, const char* className = 0) + { setFont(font, className); } + + static inline QT3_SUPPORT QWidget *widgetAt(int x, int y, bool child) + { QWidget *w = widgetAt(x, y); return child ? w : (w ? w->window() : 0); } + static inline QT3_SUPPORT QWidget *widgetAt(const QPoint &p, bool child) + { QWidget *w = widgetAt(p); return child ? w : (w ? w->window() : 0); } +#endif // QT3_SUPPORT + +#if defined(Q_INTERNAL_QAPP_SRC) || defined(qdoc) + QApplication(int &argc, char **argv); + QApplication(int &argc, char **argv, bool GUIenabled); + QApplication(int &argc, char **argv, Type); +#if defined(Q_WS_X11) + QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0); + QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); +#endif +#if defined(Q_OS_SYMBIAN) || defined(qdoc) + QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv); +#endif +#endif + +private: + Q_DISABLE_COPY(QApplication) + Q_DECLARE_PRIVATE(QApplication) + + friend class QGraphicsWidget; + friend class QGraphicsItem; + friend class QGraphicsScene; + friend class QGraphicsScenePrivate; + friend class QWidget; + friend class QWidgetPrivate; + friend class QWidgetWindow; + friend class QETWidget; + friend class Q3AccelManager; + friend class QTranslator; + friend class QWidgetAnimator; +#ifndef QT_NO_SHORTCUT + friend class QShortcut; + friend class QLineEdit; + friend class QTextControl; +#endif + friend class QAction; + +#if defined(Q_WS_QWS) + friend class QInputContext; + friend class QWSDirectPainterSurface; + friend class QDirectPainter; + friend class QDirectPainterPrivate; +#endif +#ifndef QT_NO_GESTURES + friend class QGestureManager; +#endif + +#if defined(Q_WS_MAC) || defined(Q_WS_X11) + Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut()) +#endif +#if defined(QT_RX71_MULTITOUCH) + Q_PRIVATE_SLOT(d_func(), void _q_readRX71MultiTouchEvents()) +#endif +#if defined(Q_OS_SYMBIAN) + Q_PRIVATE_SLOT(d_func(), void _q_aboutToQuit()) +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAPPLICATION_H diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h new file mode 100644 index 0000000000..a089a6ba40 --- /dev/null +++ b/src/widgets/kernel/qapplication_p.h @@ -0,0 +1,626 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAPPLICATION_P_H +#define QAPPLICATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp, qcolor_x11.cpp, qfiledialog.cpp +// and many other. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qapplication.h" +#include "QtGui/qevent.h" +#include "QtGui/qfont.h" +#include "QtGui/qcursor.h" +#include "QtGui/qregion.h" +#include "QtCore/qmutex.h" +#include "QtCore/qtranslator.h" +#include "QtCore/qbasictimer.h" +#include "QtCore/qhash.h" +#include "QtCore/qpointer.h" +#include "private/qcoreapplication_p.h" +#include "QtGui/private/qshortcutmap_p.h" +#include +#include "QtCore/qpoint.h" +#include +#ifdef Q_OS_SYMBIAN +#include +#endif +#ifdef Q_WS_QPA +#include +#include "private/qwindowsysteminterface_qpa_p.h" +#include "QtGui/qplatformintegration_qpa.h" +#include "QtGui/private/qguiapplication_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QClipboard; +class QGraphicsScene; +class QInputContext; +class QObject; +class QWidget; +class QSocketNotifier; +#ifndef QT_NO_GESTURES +class QGestureManager; +#endif + +extern bool qt_is_gui_used; +#ifndef QT_NO_CLIPBOARD +extern QClipboard *qt_clipboard; +#endif + +#if defined (Q_OS_WIN32) || defined (Q_OS_CYGWIN) || defined(Q_OS_WINCE) +extern QSysInfo::WinVersion qt_winver; +enum { QT_TABLET_NPACKETQSIZE = 128 }; +# ifdef Q_OS_WINCE + extern DWORD qt_cever; +# endif +#elif defined (Q_OS_MAC) +extern QSysInfo::MacVersion qt_macver; +#endif +#if defined(Q_WS_QWS) +class QWSManager; +class QDirectPainter; +struct QWSServerCleaner { ~QWSServerCleaner(); }; +#endif + +#ifndef QT_NO_TABLET +struct QTabletDeviceData +{ +#ifndef Q_WS_MAC + int minPressure; + int maxPressure; + int minTanPressure; + int maxTanPressure; + int minX, maxX, minY, maxY, minZ, maxZ; + inline QPointF scaleCoord(int coordX, int coordY, int outOriginX, int outExtentX, + int outOriginY, int outExtentY) const; +#endif + +#if defined(Q_WS_X11) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) + QPointer widgetToGetPress; +#endif + +#ifdef Q_WS_X11 + int deviceType; + enum { + TOTAL_XINPUT_EVENTS = 64 + }; + void *device; + int eventCount; + long unsigned int eventList[TOTAL_XINPUT_EVENTS]; // XEventClass is in fact a long unsigned int + + int xinput_motion; + int xinput_key_press; + int xinput_key_release; + int xinput_button_press; + int xinput_button_release; + int xinput_proximity_in; + int xinput_proximity_out; +#elif defined(Q_WS_WIN) + qint64 llId; + int currentDevice; + int currentPointerType; +#elif defined(Q_WS_MAC) + quint64 tabletUniqueID; + int tabletDeviceType; + int tabletPointerType; + int capabilityMask; +#endif +}; + +static inline int sign(int x) +{ + return x >= 0 ? 1 : -1; +} + +#ifndef Q_WS_MAC +inline QPointF QTabletDeviceData::scaleCoord(int coordX, int coordY, + int outOriginX, int outExtentX, + int outOriginY, int outExtentY) const +{ + QPointF ret; + + if (sign(outExtentX) == sign(maxX)) + ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + outOriginX); + else + ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + + outOriginX); + + if (sign(outExtentY) == sign(maxY)) + ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + outOriginY); + else + ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + + outOriginY); + + return ret; +} +#endif + +typedef QList QTabletDeviceDataList; +QTabletDeviceDataList *qt_tablet_devices(); +# if defined(Q_WS_MAC) +typedef QHash QMacTabletHash; +QMacTabletHash *qt_mac_tablet_hash(); +# endif +#endif + +#ifdef QT3_SUPPORT +extern "C" { + typedef bool (*Ptrqt_tryAccelEvent)(QWidget *w, QKeyEvent *e); + typedef bool (*Ptrqt_tryComposeUnicode)(QWidget *w, QKeyEvent *e); + typedef bool (*Ptrqt_dispatchAccelEvent)(QWidget *w, QKeyEvent *e); +} +#endif + +#if defined(Q_WS_WIN) +typedef BOOL (WINAPI *PtrRegisterTouchWindow)(HWND, ULONG); +typedef BOOL (WINAPI *PtrGetTouchInputInfo)(HANDLE, UINT, PVOID, int); +typedef BOOL (WINAPI *PtrCloseTouchInputHandle)(HANDLE); + +#ifndef QT_NO_GESTURES +typedef BOOL (WINAPI *PtrGetGestureInfo)(HANDLE, PVOID); +typedef BOOL (WINAPI *PtrGetGestureExtraArgs)(HANDLE, UINT, PBYTE); +typedef BOOL (WINAPI *PtrCloseGestureInfoHandle)(HANDLE); +typedef BOOL (WINAPI *PtrSetGestureConfig)(HWND, DWORD, UINT, PVOID, UINT); +typedef BOOL (WINAPI *PtrGetGestureConfig)(HWND, DWORD, DWORD, PUINT, PVOID, UINT); + +typedef BOOL (WINAPI *PtrBeginPanningFeedback)(HWND); +typedef BOOL (WINAPI *PtrUpdatePanningFeedback)(HWND, LONG, LONG, BOOL); +typedef BOOL (WINAPI *PtrEndPanningFeedback)(HWND, BOOL); + +#ifndef WM_GESTURE +# define WM_GESTURE 0x0119 + +# define GID_BEGIN 1 +# define GID_END 2 +# define GID_ZOOM 3 +# define GID_PAN 4 +# define GID_ROTATE 5 +# define GID_TWOFINGERTAP 6 +# define GID_ROLLOVER 7 + +typedef struct tagGESTUREINFO +{ + UINT cbSize; + DWORD dwFlags; + DWORD dwID; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; + DWORD dwSequenceID; + ULONGLONG ullArguments; + UINT cbExtraArgs; +} GESTUREINFO; + +# define GC_PAN 0x00000001 +# define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 +# define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 + +# define GC_ZOOM 0x00000001 +# define GC_ROTATE 0x00000001 + +typedef struct tagGESTURECONFIG +{ + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; +} GESTURECONFIG; + +# define GID_ROTATE_ANGLE_FROM_ARGUMENT(arg) ((((double)(arg) / 65535.0) * 4.0 * 3.14159265) - 2.0*3.14159265) + +#endif // WM_GESTURE + +#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) +#undef GID_ZOOM +#define GID_ZOOM 0xf000 +#undef GID_ROTATE +#define GID_ROTATE 0xf001 +#undef GID_TWOFINGERTAP +#define GID_TWOFINGERTAP 0xf002 +#undef GID_ROLLOVER +#define GID_ROLLOVER 0xf003 +#endif + +#endif // QT_NO_GESTURES + +#endif // Q_WS_WIN + +class QScopedLoopLevelCounter +{ + QThreadData *threadData; +public: + QScopedLoopLevelCounter(QThreadData *threadData) + : threadData(threadData) + { ++threadData->loopLevel; } + ~QScopedLoopLevelCounter() + { --threadData->loopLevel; } +}; + +typedef QHash FontHash; +FontHash *qt_app_fonts_hash(); + +typedef QHash PaletteHash; +PaletteHash *qt_app_palettes_hash(); + +#ifdef Q_WS_QPA +#define QApplicationPrivateBase QGuiApplicationPrivate +#else +#define QApplicationPrivateBase QCoreApplicationPrivate +#endif + +class Q_GUI_EXPORT QApplicationPrivate : public QApplicationPrivateBase +{ + Q_DECLARE_PUBLIC(QApplication) +public: + QApplicationPrivate(int &argc, char **argv, QApplication::Type type, int flags); + ~QApplicationPrivate(); + + virtual void notifyLayoutDirectionChange(); + +#if defined(Q_WS_X11) +#ifndef QT_NO_SETTINGS + static bool x11_apply_settings(); +#endif + static void reset_instance_pointer(); +#elif defined(Q_WS_QWS) + static bool qws_apply_settings(); + static QWidget *findWidget(const QObjectList&, const QPoint &, bool rec); +#endif + static bool quitOnLastWindowClosed; + static void emitLastWindowClosed(); +#ifdef Q_WS_WINCE + static int autoMaximizeThreshold; +#endif + static bool autoSipEnabled; + static QString desktopStyleKey(); + + + void createEventDispatcher(); + QString appName() const; + static void dispatchEnterLeave(QWidget *enter, QWidget *leave); + + //modality + static void enterModal(QWidget*); + static void leaveModal(QWidget*); + static void enterModal_sys(QWidget*); + static void leaveModal_sys(QWidget*); + static bool isBlockedByModal(QWidget *widget); + static bool modalState(); + static bool tryModalHelper(QWidget *widget, QWidget **rettop = 0); +#ifdef Q_WS_MAC + static QWidget *tryModalHelper_sys(QWidget *top); + bool canQuit(); +#endif + + bool notify_helper(QObject *receiver, QEvent * e); + + void construct( +#ifdef Q_WS_X11 + Display *dpy = 0, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 +#endif + ); + void initialize(); + void process_cmdline(); + +#if defined(Q_WS_X11) + static void x11_initialize_style(); +#endif + + bool inPopupMode() const; + void closePopup(QWidget *popup); + void openPopup(QWidget *popup); + static void setFocusWidget(QWidget *focus, Qt::FocusReason reason); + static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next); + +#ifndef QT_NO_SESSIONMANAGER + QSessionManager *session_manager; + QString session_id; + QString session_key; + bool is_session_restored; +#endif + +#ifndef QT_NO_GRAPHICSVIEW + // Maintain a list of all scenes to ensure font and palette propagation to + // all scenes. + QList scene_list; +#endif + + QBasicTimer toolTipWakeUp, toolTipFallAsleep; + QPoint toolTipPos, toolTipGlobalPos, hoverGlobalPos; + QPointer toolTipWidget; +#ifndef QT_NO_SHORTCUT + QShortcutMap shortcutMap; +#endif + +#ifdef QT3_SUPPORT + bool qt_compat_used; + bool qt_compat_resolved; + Ptrqt_tryAccelEvent qt_tryAccelEvent; + Ptrqt_tryComposeUnicode qt_tryComposeUnicode; + Ptrqt_dispatchAccelEvent qt_dispatchAccelEvent; + + bool use_compat() { + return qt_tryAccelEvent + && qt_tryComposeUnicode + && qt_dispatchAccelEvent; + } +#endif + static QInputContext *inputContext; + + static Qt::MouseButtons mouse_buttons; + static Qt::KeyboardModifiers modifier_buttons; + + static QSize app_strut; + static QWidgetList *popupWidgets; + static QStyle *app_style; + static int app_cspec; + static QPalette *sys_pal; + static QPalette *set_pal; + +private: +#ifndef Q_WS_QPA + static QFont *app_font; // private for a reason! Always use QApplication::font() instead! +#endif +public: + static QFont *sys_font; + static QFont *set_font; + static QWidget *main_widget; + static QWidget *focus_widget; + static QWidget *hidden_focus_widget; + static QWidget *active_window; + static QIcon *app_icon; + static bool obey_desktop_settings; + static int cursor_flash_time; + static int mouse_double_click_time; + static int keyboard_input_time; +#ifndef QT_NO_WHEELEVENT + static int wheel_scroll_lines; +#endif + + static bool animate_ui; + static bool animate_menu; + static bool animate_tooltip; + static bool animate_combo; + static bool fade_menu; + static bool fade_tooltip; + static bool animate_toolbox; + static bool widgetCount; // Coupled with -widgetcount switch + static bool load_testability; // Coupled with -testability switch + static QString qmljs_debug_arguments; // a string containing arguments for js/qml debugging. + static QString qmljsDebugArgumentsString(); // access string from other libraries + +#ifdef Q_WS_MAC + static bool native_modal_dialog_active; +#endif + + static void setSystemPalette(const QPalette &pal); + static void setPalette_helper(const QPalette &palette, const char* className, bool clearWidgetPaletteHash); + static void initializeWidgetPaletteHash(); + static void setSystemFont(const QFont &font); + +#if defined(Q_WS_X11) + static void applyX11SpecificCommandLineArguments(QWidget *main_widget); +#elif defined(Q_WS_QWS) + static void applyQWSSpecificCommandLineArguments(QWidget *main_widget); +#endif + +#ifdef Q_WS_MAC + static OSStatus globalEventProcessor(EventHandlerCallRef, EventRef, void *); + static OSStatus globalAppleEventProcessor(const AppleEvent *, AppleEvent *, long); + static OSStatus tabletProximityCallback(EventHandlerCallRef, EventRef, void *); +#ifdef QT_MAC_USE_COCOA + static void qt_initAfterNSAppStarted(); + static void setupAppleEvents(); +#endif + static bool qt_mac_apply_settings(); +#endif + +#ifdef Q_WS_QWS + QPointer last_manager; + QWSServerCleaner qwsServerCleaner; +# ifndef QT_NO_DIRECTPAINTER + QMap *directPainters; +# endif + QRect maxWindowRect(const QScreen *screen) const { return maxWindowRects[screen]; } + void setMaxWindowRect(const QScreen *screen, int screenNo, const QRect &rect); + void setScreenTransformation(QScreen *screen, int screenNo, int transformation); +#endif + + static QApplicationPrivate *instance() { return self; } + + static QString styleOverride; + +#ifdef QT_KEYPAD_NAVIGATION + static QWidget *oldEditFocus; + static Qt::NavigationMode navigationMode; +#endif + +#if defined(Q_WS_MAC) || defined(Q_WS_X11) + void _q_alertTimeOut(); + QHash alertTimerHash; +#endif +#ifndef QT_NO_STYLE_STYLESHEET + static QString styleSheet; +#endif + static QPointer leaveAfterRelease; + static QWidget *pickMouseReceiver(QWidget *candidate, const QPoint &globalPos, QPoint &pos, + QEvent::Type type, Qt::MouseButtons buttons, + QWidget *buttonDown, QWidget *alienWidget); + static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, + QWidget *native, QWidget **buttonDown, QPointer &lastMouseReceiver, + bool spontaneous = true); +#ifdef Q_OS_SYMBIAN + static void setNavigationMode(Qt::NavigationMode mode); + static TUint resolveS60ScanCode(TInt scanCode, TUint keysym); + QSet nativeWindows; + + int symbianProcessWsEvent(const QSymbianEvent *symbianEvent); + int symbianHandleCommand(const QSymbianEvent *symbianEvent); + int symbianResourceChange(const QSymbianEvent *symbianEvent); + + void _q_aboutToQuit(); +#endif +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) + void sendSyntheticEnterLeave(QWidget *widget); +#endif + +#ifndef QT_NO_GESTURES + QGestureManager *gestureManager; + QWidget *gestureWidget; +#endif +#if defined(Q_WS_X11) || defined(Q_WS_WIN) + QPixmap *move_cursor; + QPixmap *copy_cursor; + QPixmap *link_cursor; +#endif +#if defined(Q_WS_WIN) + QPixmap *ignore_cursor; +#endif + + QMap > widgetForTouchPointId; + QMap appCurrentTouchPoints; + static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + void initializeMultitouch(); + void initializeMultitouch_sys(); + void cleanupMultitouch(); + void cleanupMultitouch_sys(); + int findClosestTouchPointId(const QPointF &screenPos); + void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); + void removeTouchPoint(int touchPointId); + static void translateRawTouchEvent(QWidget *widget, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints); + +#if defined(Q_WS_WIN) + static bool HasTouchSupport; + static PtrRegisterTouchWindow RegisterTouchWindow; + static PtrGetTouchInputInfo GetTouchInputInfo; + static PtrCloseTouchInputHandle CloseTouchInputHandle; + + QHash touchInputIDToTouchPointID; + bool translateTouchEvent(const MSG &msg); + +#ifndef QT_NO_GESTURES + PtrGetGestureInfo GetGestureInfo; + PtrGetGestureExtraArgs GetGestureExtraArgs; + PtrCloseGestureInfoHandle CloseGestureInfoHandle; + PtrSetGestureConfig SetGestureConfig; + PtrGetGestureConfig GetGestureConfig; + PtrBeginPanningFeedback BeginPanningFeedback; + PtrUpdatePanningFeedback UpdatePanningFeedback; + PtrEndPanningFeedback EndPanningFeedback; +#endif // QT_NO_GESTURES +#endif + +#ifdef QT_RX71_MULTITOUCH + bool hasRX71MultiTouch; + + struct RX71TouchPointState { + QSocketNotifier *socketNotifier; + QTouchEvent::TouchPoint touchPoint; + + int minX, maxX, scaleX; + int minY, maxY, scaleY; + int minZ, maxZ; + }; + QList allRX71TouchPoints; + + bool readRX71MultiTouchEvents(int deviceNumber); + void fakeMouseEventFromRX71TouchEvent(); + void _q_readRX71MultiTouchEvents(); +#endif + +#if defined(Q_OS_SYMBIAN) + int pressureSupported; + int maxTouchPressure; + QList appAllTouchPoints; + + bool useTranslucentEGLSurfaces; +#endif + +private: +#ifdef Q_WS_QWS + QMap maxWindowRects; +#endif + +#ifdef Q_OS_SYMBIAN + QHash scanCodeCache; +#endif + + static QApplicationPrivate *self; + + static void giveFocusAccordingToFocusPolicy(QWidget *w, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason); + static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); + + + static bool isAlien(QWidget *); +}; + +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList &touchPoints); + +#if defined(Q_WS_WIN) + extern void qt_win_set_cursor(QWidget *, bool); +#elif defined(Q_WS_X11) + extern void qt_x11_enforce_cursor(QWidget *, bool); + extern void qt_x11_enforce_cursor(QWidget *); +#elif defined(Q_OS_SYMBIAN) + extern void qt_symbian_set_cursor(QWidget *, bool); +#else + extern void qt_qpa_set_cursor(QWidget * w, bool force); +#endif + +QT_END_NAMESPACE + +#endif // QAPPLICATION_P_H diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp new file mode 100644 index 0000000000..f3e033c787 --- /dev/null +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qcolormap.h" +#include "qpixmapcache.h" +#if !defined(QT_NO_GLIB) +#include "private/qeventdispatcher_glib_qpa_p.h" +#endif +#include "private/qeventdispatcher_qpa_p.h" +#ifndef QT_NO_CURSOR +#include "private/qcursor_p.h" +#endif + +#include "private/qwidget_p.h" +#include "private/qevent_p.h" + +#include "qgenericpluginfactory_qpa.h" +#include "private/qplatformintegrationfactory_qpa_p.h" +#include + +#include +#include +#include +#include +#include "private/qwindowsysteminterface_qpa_p.h" +#include + +#include "qdesktopwidget_qpa_p.h" +#include "qwidgetwindow_qpa_p.h" + +QT_BEGIN_NAMESPACE + +static QString appName; +static QString appFont; + +QString QApplicationPrivate::appName() const +{ + return QT_PREPEND_NAMESPACE(appName); +} + +void QApplicationPrivate::createEventDispatcher() +{ + QGuiApplicationPrivate::createEventDispatcher(); +} + +static bool qt_try_modal(QWidget *widget, QEvent::Type type) +{ + QWidget * top = 0; + + if (QApplicationPrivate::tryModalHelper(widget, &top)) + return true; + + bool block_event = false; + bool paint_event = false; + + switch (type) { +#if 0 + case QEvent::Focus: + if (!static_cast(event)->simpleData.get_focus) + break; + // drop through +#endif + case QEvent::MouseButtonPress: // disallow mouse/key events + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + block_event = true; + break; + default: + break; + } + + if ((block_event || paint_event) && top->parentWidget() == 0) + top->raise(); + + return !block_event; +} + + + +void QApplicationPrivate::enterModal_sys(QWidget *) +{ +#if 0 + if (!qt_modal_stack) + qt_modal_stack = new QWidgetList; + qt_modal_stack->insert(0, widget); + app_do_modal = true; +#endif +} + +void QApplicationPrivate::leaveModal_sys(QWidget *) +{ +#if 0 + if (qt_modal_stack && qt_modal_stack->removeAll(widget)) { + if (qt_modal_stack->isEmpty()) { + delete qt_modal_stack; + qt_modal_stack = 0; + } + } + app_do_modal = qt_modal_stack != 0; +#endif +} + +bool QApplicationPrivate::modalState() +{ + return false; +#if 0 + return app_do_modal; +#endif +} + +void QApplicationPrivate::closePopup(QWidget *popup) +{ + Q_Q(QApplication); + if (!popupWidgets) + return; + popupWidgets->removeAll(popup); + +//### +// if (popup == qt_popup_down) { +// qt_button_down = 0; +// qt_popup_down = 0; +// } + + if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup + delete QApplicationPrivate::popupWidgets; + QApplicationPrivate::popupWidgets = 0; + + //### replay mouse event? + + //### transfer/release mouse grab + + //### transfer/release keyboard grab + + //give back focus + + if (active_window) { + if (QWidget *fw = active_window->focusWidget()) { + if (fw != QApplication::focusWidget()) { + fw->setFocus(Qt::PopupFocusReason); + } else { + QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); + q->sendEvent(fw, &e); + } + } + } + + } else { + // A popup was closed, so the previous popup gets the focus. + + QWidget* aw = QApplicationPrivate::popupWidgets->last(); + if (QWidget *fw = aw->focusWidget()) + fw->setFocus(Qt::PopupFocusReason); + + //### regrab the keyboard and mouse in case 'popup' lost the grab + + + } + +} + +static int openPopupCount = 0; +void QApplicationPrivate::openPopup(QWidget *popup) +{ + openPopupCount++; + if (!popupWidgets) { // create list + popupWidgets = new QWidgetList; + + /* only grab if you are the first/parent popup */ + //#### ->grabMouse(popup,true); + //#### ->grabKeyboard(popup,true); + //### popupGrabOk = true; + } + popupWidgets->append(popup); // add to end of list + + // popups are not focus-handled by the window system (the first + // popup grabbed the keyboard), so we have to do that manually: A + // new popup gets the focus + if (popup->focusWidget()) { + popup->focusWidget()->setFocus(Qt::PopupFocusReason); + } else if (popupWidgets->count() == 1) { // this was the first popup + if (QWidget *fw = QApplication::focusWidget()) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + QApplication::sendEvent(fw, &e); + } + } +} + +void QApplicationPrivate::initializeMultitouch_sys() +{ +} + +void QApplicationPrivate::cleanupMultitouch_sys() +{ +} + +void QApplicationPrivate::initializeWidgetPaletteHash() +{ +} + +void QApplication::setCursorFlashTime(int msecs) +{ + QApplicationPrivate::cursor_flash_time = msecs; +} + +int QApplication::cursorFlashTime() +{ + return QApplicationPrivate::cursor_flash_time; +} + +void QApplication::setDoubleClickInterval(int ms) +{ + QApplicationPrivate::mouse_double_click_time = ms; +} + +int QApplication::doubleClickInterval() +{ + return QApplicationPrivate::mouse_double_click_time; +} + +void QApplication::setKeyboardInputInterval(int ms) +{ + QApplicationPrivate::keyboard_input_time = ms; +} + +int QApplication::keyboardInputInterval() +{ + return QApplicationPrivate::keyboard_input_time; +} + +#ifndef QT_NO_WHEELEVENT +void QApplication::setWheelScrollLines(int lines) +{ + QApplicationPrivate::wheel_scroll_lines = lines; +} + +int QApplication::wheelScrollLines() +{ + return QApplicationPrivate::wheel_scroll_lines; +} +#endif + +void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +{ + switch (effect) { + case Qt::UI_AnimateMenu: + QApplicationPrivate::animate_menu = enable; + break; + case Qt::UI_FadeMenu: + if (enable) + QApplicationPrivate::animate_menu = true; + QApplicationPrivate::fade_menu = enable; + break; + case Qt::UI_AnimateCombo: + QApplicationPrivate::animate_combo = enable; + break; + case Qt::UI_AnimateTooltip: + QApplicationPrivate::animate_tooltip = enable; + break; + case Qt::UI_FadeTooltip: + if (enable) + QApplicationPrivate::animate_tooltip = true; + QApplicationPrivate::fade_tooltip = enable; + break; + case Qt::UI_AnimateToolBox: + QApplicationPrivate::animate_toolbox = enable; + break; + default: + QApplicationPrivate::animate_ui = enable; + break; + } +} + +bool QApplication::isEffectEnabled(Qt::UIEffect effect) +{ + if (QColormap::instance().depth() < 16 || !QApplicationPrivate::animate_ui) + return false; + + switch(effect) { + case Qt::UI_AnimateMenu: + return QApplicationPrivate::animate_menu; + case Qt::UI_FadeMenu: + return QApplicationPrivate::fade_menu; + case Qt::UI_AnimateCombo: + return QApplicationPrivate::animate_combo; + case Qt::UI_AnimateTooltip: + return QApplicationPrivate::animate_tooltip; + case Qt::UI_FadeTooltip: + return QApplicationPrivate::fade_tooltip; + case Qt::UI_AnimateToolBox: + return QApplicationPrivate::animate_toolbox; + default: + return QApplicationPrivate::animate_ui; + } +} + +QWidget *QApplication::topLevelAt(const QPoint &pos) +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + + QList screens = pi->screens(); + QList::const_iterator screen = screens.constBegin(); + QList::const_iterator end = screens.constEnd(); + + // The first screen in a virtual environment should know about all top levels + if (pi->isVirtualDesktop()) { + QWidgetWindow *w = qobject_cast((*screen)->topLevelAt(pos)); + return w ? w->widget() : 0; + } + + while (screen != end) { + if ((*screen)->geometry().contains(pos)) { + QWidgetWindow *w = qobject_cast((*screen)->topLevelAt(pos)); + return w ? w->widget() : 0; + } + ++screen; + } + return 0; +} + +void QApplication::beep() +{ +} + +void QApplication::alert(QWidget *, int) +{ +} + +QPlatformNativeInterface *QApplication::platformNativeInterface() +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + return pi->nativeInterface(); +} + +#ifndef QT_NO_QWS_INPUTMETHODS +class QDummyInputContext : public QInputContext +{ +public: + explicit QDummyInputContext(QObject* parent = 0) : QInputContext(parent) {} + ~QDummyInputContext() {} + QString identifierName() { return QString(); } + QString language() { return QString(); } + + void reset() {} + bool isComposing() const { return false; } + +}; +#endif // QT_NO_QWS_INPUTMETHODS + +void qt_init(QApplicationPrivate *, int type) +{ + Q_UNUSED(type); + + qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + QColormap::initialize(); +#ifndef QT_NO_CURSOR +// QCursorData::initialize(); +#endif + + qApp->setObjectName(appName); + +#ifndef QT_NO_QWS_INPUTMETHODS + qApp->setInputContext(new QDummyInputContext(qApp)); +#endif +} + +void qt_cleanup() +{ + QPixmapCache::clear(); +#ifndef QT_NO_CURSOR + QCursorData::cleanup(); +#endif + QColormap::cleanup(); + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; + + QApplicationPrivate::active_window = 0; //### this should not be necessary +} + + +#ifdef QT3_SUPPORT +void QApplication::setMainWidget(QWidget *mainWidget) +{ + QApplicationPrivate::main_widget = mainWidget; + if (QApplicationPrivate::main_widget && windowIcon().isNull() + && QApplicationPrivate::main_widget->testAttribute(Qt::WA_SetWindowIcon)) + setWindowIcon(QApplicationPrivate::main_widget->windowIcon()); +} +#endif + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qbackingstore.cpp b/src/widgets/kernel/qbackingstore.cpp new file mode 100644 index 0000000000..1ee66f09cc --- /dev/null +++ b/src/widgets/kernel/qbackingstore.cpp @@ -0,0 +1,1665 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qplatformdefs.h" + +#include "qbackingstore_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef Q_WS_QWS +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +extern QRegion qt_dirtyRegion(QWidget *); + +/* + A version of QRect::intersects() that does not normalize the rects. +*/ +static inline bool qRectIntersects(const QRect &r1, const QRect &r2) +{ + return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) + && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); +} + +/** + * Flushes the contents of the \a windowSurface into the screen area of \a widget. + * \a tlwOffset is the position of the top level widget relative to the window surface. + * \a region is the region to be updated in \a widget coordinates. + */ +static inline void qt_flush(QWidget *widget, const QRegion ®ion, QWindowSurface *windowSurface, + QWidget *tlw, const QPoint &tlwOffset) +{ + Q_ASSERT(widget); + Q_ASSERT(!region.isEmpty()); + Q_ASSERT(windowSurface); + Q_ASSERT(tlw); + +#if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS) + // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc). + static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt(); + if (flushUpdate > 0) + QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); +#endif + + //The performance hit by doing this should be negligible. However, be aware that + //using this FPS when you have > 1 windowsurface can give you inaccurate FPS + static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt(); + if (fpsDebug) { + static QTime time = QTime::currentTime(); + static int frames = 0; + + frames++; + + if(time.elapsed() > 5000) { + double fps = double(frames * 1000) /time.restart(); + fprintf(stderr,"FPS: %.1f\n",fps); + frames = 0; + } + } + if (widget != tlw) + windowSurface->flush(widget->windowHandle(), region, tlwOffset + widget->mapTo(tlw, QPoint())); + else + windowSurface->flush(widget->windowHandle(), region, tlwOffset); +} + +#ifndef QT_NO_PAINT_DEBUG +#ifdef Q_WS_WIN +static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec) +{ + HBRUSH brush; + static int i = 0; + switch (i) { + case 0: + brush = CreateSolidBrush(RGB(255, 255, 0)); + break; + case 1: + brush = CreateSolidBrush(RGB(255, 200, 55)); + break; + case 2: + brush = CreateSolidBrush(RGB(200, 255, 55)); + break; + case 3: + brush = CreateSolidBrush(RGB(200, 200, 0)); + break; + } + i = (i + 1) & 3; + + HDC hdc = widget->getDC(); + + const QVector &rects = region.rects(); + foreach (QRect rect, rects) { + RECT winRect; + SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom()); + FillRect(hdc, &winRect, brush); + } + + widget->releaseDC(hdc); + ::Sleep(msec); +} +#endif + +void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped) +{ +#ifdef Q_WS_QWS + Q_UNUSED(widget); + Q_UNUSED(unclipped); + static QWSYellowSurface surface(true); + surface.setDelay(msec); + surface.flush(widget, toBePainted, QPoint()); +#else + QRegion paintRegion = toBePainted; + QRect widgetRect = widget->rect(); + + if (!widget->internalWinId()) { + QWidget *nativeParent = widget->nativeParentWidget(); + const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0)); + paintRegion.translate(offset); + widgetRect.translate(offset); + widget = nativeParent; + } + +#ifdef Q_WS_WIN + Q_UNUSED(unclipped); + showYellowThing_win(widget, paintRegion, msec); +#else + //flags to fool painter + bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped); + if (unclipped && !widget->d_func()->paintOnScreen()) + widget->setAttribute(Qt::WA_PaintUnclipped); + + const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent); + if (setFlag) + widget->setAttribute(Qt::WA_WState_InPaintEvent); + + //setup the engine + QPaintEngine *pe = widget->paintEngine(); + if (pe) { + pe->setSystemClip(paintRegion); + { + QPainter p(widget); + p.setClipRegion(paintRegion); + static int i = 0; + switch (i) { + case 0: + p.fillRect(widgetRect, QColor(255,255,0)); + break; + case 1: + p.fillRect(widgetRect, QColor(255,200,55)); + break; + case 2: + p.fillRect(widgetRect, QColor(200,255,55)); + break; + case 3: + p.fillRect(widgetRect, QColor(200,200,0)); + break; + } + i = (i+1) & 3; + p.end(); + } + } + + if (setFlag) + widget->setAttribute(Qt::WA_WState_InPaintEvent, false); + + //restore + widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped); + + if (pe) + pe->setSystemClip(QRegion()); + + QApplication::syncX(); + +#if defined(Q_OS_UNIX) + ::usleep(1000 * msec); +#endif +#endif // Q_WS_WIN +#endif // Q_WS_QWS +} + +bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn) +{ + if (!widget) + return false; + + int delay = 0; + if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) { + static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt(); + if (!flushPaintEvent) + return false; + delay = flushPaintEvent; + } else { + static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt(); + if (!flushPaint) + return false; + delay = flushPaint; + } + + QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true); + return true; +} + +void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) +{ + if (widget->d_func()->paintOnScreen() || rgn.isEmpty()) + return; + + QWidget *tlw = widget->window(); + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (!tlwExtra) + return; + + const QPoint offset = widget->mapTo(tlw, QPoint()); + qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset); +} +#endif // QT_NO_PAINT_DEBUG + +/* + Moves the whole rect by (dx, dy) in widget's coordinate system. + Doesn't generate any updates. +*/ +bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget) +{ + const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft())); + const QRect tlwRect(QRect(pos, rect.size())); + if (fullUpdatePending || dirty.intersects(tlwRect)) + return false; // We don't want to scroll junk. + return windowSurface->scroll(tlwRect, dx, dy); +} + +void QWidgetBackingStore::releaseBuffer() +{ + if (windowSurface) +#if defined(Q_WS_QPA) + windowSurface->resize(QSize()); +#else + windowSurface->setGeometry(QRect()); +#endif +#ifdef Q_BACKINGSTORE_SUBSURFACES + for (int i = 0; i < subSurfaces.size(); ++i) + subSurfaces.at(i)->setGeometry(QRect()); +#endif +} + +/*! + Prepares the window surface to paint a\ toClean region of the \a widget and + updates the BeginPaintInfo struct accordingly. + + The \a toClean region might be clipped by the window surface. +*/ +void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface, + BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates) +{ +#ifdef Q_WS_QWS + QWSWindowSurface *surface = static_cast(windowSurface); + QWidget *surfaceWidget = surface->window(); + + if (!surface->isValid()) { + // this looks strange but it really just releases the surface + surface->releaseSurface(); + // the old window surface is deleted in setWindowSurface, which is + // called from QWindowSurface constructor. + windowSurface = tlw->d_func()->createDefaultWindowSurface(); + surface = static_cast(windowSurface); + // createDefaultWindowSurface() will set topdata->windowSurface on the + // widget to zero. However, if this is a sub-surface, it should point + // to the widget's sub windowSurface, so we set that here: + if (!surfaceWidget->isWindow()) + surfaceWidget->d_func()->topData()->windowSurface = windowSurface; + surface->setGeometry(topLevelRect()); + returnInfo->windowSurfaceRecreated = true; + } + + const QRegion toCleanUnclipped(toClean); + + if (surfaceWidget->isWindow()) + tlwOffset = surface->painterOffset(); +#ifdef Q_BACKINGSTORE_SUBSURFACES + else if (toCleanIsInTopLevelCoordinates) + toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint())); + if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface) + toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint())); +#else + toClean &= surface->clipRegion(); +#endif + + if (toClean.isEmpty()) { + if (surfaceWidget->isWindow()) { + dirtyFromPreviousSync += toCleanUnclipped; + hasDirtyFromPreviousSync = true; + } + + returnInfo->nothingToPaint = true; + // Nothing to repaint. However, we might have newly exposed areas on the + // screen, so we have to make sure those are flushed. + flush(); + return; + } + + if (surfaceWidget->isWindow()) { + if (toCleanUnclipped != toClean) { + dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion()); + hasDirtyFromPreviousSync = true; + } + if (hasDirtyFromPreviousSync) { + dirtyFromPreviousSync -= toClean; + hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty(); + } + } + +#endif // Q_WS_QWS + + Q_UNUSED(widget); + Q_UNUSED(toCleanIsInTopLevelCoordinates); + + // Always flush repainted areas. + dirtyOnScreen += toClean; + +#if defined(Q_WS_QWS) && !defined(Q_BACKINGSTORE_SUBSURFACES) + toClean.translate(tlwOffset); +#endif + +#ifdef QT_NO_PAINT_DEBUG + windowSurface->beginPaint(toClean); +#else + returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean); + // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for + // the BackingStore lock, so if we hold that, the server will + // never release the Communication lock that we are waiting for in + // sendSynchronousCommand + if (!returnInfo->wasFlushed) + windowSurface->beginPaint(toClean); +#endif + + Q_UNUSED(returnInfo); +} + +void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, + BeginPaintInfo *beginPaintInfo) +{ +#ifndef QT_NO_PAINT_DEBUG + if (!beginPaintInfo->wasFlushed) + windowSurface->endPaint(cleaned); + else + QWidgetBackingStore::unflushPaint(tlw, cleaned); +#else + Q_UNUSED(beginPaintInfo); + windowSurface->endPaint(cleaned); +#endif + +#ifdef Q_BACKINGSTORE_SUBSURFACES + flush(static_cast(windowSurface)->window(), windowSurface); +#else + flush(); +#endif +} + +/*! + Returns the region (in top-level coordinates) that needs repaint and/or flush. + + If the widget is non-zero, only the dirty region for the widget is returned + and the region will be in widget coordinates. +*/ +QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const +{ + const bool widgetDirty = widget && widget != tlw; + const QRect tlwRect(topLevelRect()); +#if defined(Q_WS_QPA) + const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); +#else + const QRect surfaceGeometry(windowSurface->geometry()); +#endif + if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) { + if (widgetDirty) { + const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); + const QPoint offset(widget->mapTo(tlw, QPoint())); + const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset)); + return dirtyWidgetRect.translated(-offset); + } + return QRect(QPoint(), tlwRect.size()); + } + + // Calculate the region that needs repaint. + QRegion r(dirty); + for (int i = 0; i < dirtyWidgets.size(); ++i) { + QWidget *w = dirtyWidgets.at(i); + if (widgetDirty && w != widget && !widget->isAncestorOf(w)) + continue; + r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint())); + } + + // Append the region that needs flush. + r += dirtyOnScreen; + + if (dirtyOnScreenWidgets) { // Only in use with native child widgets. + for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { + QWidget *w = dirtyOnScreenWidgets->at(i); + if (widgetDirty && w != widget && !widget->isAncestorOf(w)) + continue; + QWidgetPrivate *wd = w->d_func(); + Q_ASSERT(wd->needsFlush); + r += wd->needsFlush->translated(w->mapTo(tlw, QPoint())); + } + } + + if (widgetDirty) { + // Intersect with the widget geometry and translate to its coordinates. + const QPoint offset(widget->mapTo(tlw, QPoint())); + r &= widget->rect().translated(offset); + r.translate(-offset); + } + return r; +} + +/*! + Returns the static content inside the \a parent if non-zero; otherwise the static content + for the entire backing store is returned. The content will be clipped to \a withinClipRect + if non-empty. +*/ +QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const +{ + if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { +#if defined(Q_WS_QPA) + const QSize surfaceGeometry(windowSurface->size()); +#else + const QRect surfaceGeometry(windowSurface->geometry()); +#endif + QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); + if (!withinClipRect.isEmpty()) + surfaceRect &= withinClipRect; + return QRegion(surfaceRect); + } + + QRegion region; + if (parent && parent->d_func()->children.isEmpty()) + return region; + + const bool clipToRect = !withinClipRect.isEmpty(); + const int count = staticWidgets.count(); + for (int i = 0; i < count; ++i) { + QWidget *w = staticWidgets.at(i); + QWidgetPrivate *wd = w->d_func(); + if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() + || !w->isVisible() || (parent && !parent->isAncestorOf(w))) { + continue; + } + + QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height()); + const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint()); + if (clipToRect) + rect &= withinClipRect.translated(-offset); + if (rect.isEmpty()) + continue; + + rect &= wd->clipRect(); + if (rect.isEmpty()) + continue; + + QRegion visible(rect); + wd->clipToEffectiveMask(visible); + if (visible.isEmpty()) + continue; + wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true); + + visible.translate(offset); + region += visible; + } + + return region; +} + +static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) +{ + if (!widget) + return; + + if (updateImmediately) { + QEvent event(QEvent::UpdateRequest); + QApplication::sendEvent(widget, &event); + } else { + QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); + } +} + +/*! + Marks the region of the widget as dirty (if not already marked as dirty) and + posts an UpdateRequest event to the top-level widget (if not already posted). + + If updateImmediately is true, the event is sent immediately instead of posted. + + If invalidateBuffer is true, all widgets intersecting with the region will be dirty. + + If the widget paints directly on screen, the event is sent to the widget + instead of the top-level widget, and invalidateBuffer is completely ignored. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, + bool invalidateBuffer) +{ + Q_ASSERT(tlw->d_func()->extra); + Q_ASSERT(tlw->d_func()->extra->topextra); + Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); + Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); + Q_ASSERT(widget->window() == tlw); + Q_ASSERT(!rgn.isEmpty()); + +#ifndef QT_NO_GRAPHICSEFFECT + widget->d_func()->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + if (widget->d_func()->paintOnScreen()) { + if (widget->d_func()->dirty.isEmpty()) { + widget->d_func()->dirty = rgn; + sendUpdateRequest(widget, updateImmediately); + return; + } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { + if (updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; // Already dirty. + } + + const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); + widget->d_func()->dirty += rgn; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; + } + + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { + fullUpdatePending = true; + sendUpdateRequest(tlw, updateImmediately); + return; + } + + const QPoint offset = widget->mapTo(tlw, QPoint()); + const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); + if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; // Already dirty. + } + + if (invalidateBuffer) { + const bool eventAlreadyPosted = !dirty.isEmpty(); +#ifndef QT_NO_GRAPHICSEFFECT + if (widget->d_func()->graphicsEffect) + dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); + else +#endif //QT_NO_GRAPHICSEFFECT + dirty += rgn.translated(offset); + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (dirtyWidgets.isEmpty()) { + addDirtyWidget(widget, rgn); + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (widget->d_func()->inDirtyList) { + if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) { +#ifndef QT_NO_GRAPHICSEFFECT + if (widget->d_func()->graphicsEffect) + widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()); + else +#endif //QT_NO_GRAPHICSEFFECT + widget->d_func()->dirty += rgn; + } + } else { + addDirtyWidget(widget, rgn); + } + + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); +} + +/*! + This function is equivalent to calling markDirty(QRegion(rect), ...), but + is more efficient as it eliminates QRegion operations/allocations and can + use the rect more precisely for additional cut-offs. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, + bool invalidateBuffer) +{ + Q_ASSERT(tlw->d_func()->extra); + Q_ASSERT(tlw->d_func()->extra->topextra); + Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); + Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); + Q_ASSERT(widget->window() == tlw); + Q_ASSERT(!rect.isEmpty()); + +#ifndef QT_NO_GRAPHICSEFFECT + widget->d_func()->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + if (widget->d_func()->paintOnScreen()) { + if (widget->d_func()->dirty.isEmpty()) { + widget->d_func()->dirty = QRegion(rect); + sendUpdateRequest(widget, updateImmediately); + return; + } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) { + if (updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; // Already dirty. + } + + const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); + widget->d_func()->dirty += rect; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; + } + + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { + fullUpdatePending = true; + sendUpdateRequest(tlw, updateImmediately); + return; + } + + const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); + const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); + if (qt_region_strictContains(dirty, translatedRect)) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; // Already dirty + } + + if (invalidateBuffer) { + const bool eventAlreadyPosted = !dirty.isEmpty(); + dirty += translatedRect; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (dirtyWidgets.isEmpty()) { + addDirtyWidget(widget, rect); + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (widget->d_func()->inDirtyList) { + if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) + widget->d_func()->dirty += widgetRect; + } else { + addDirtyWidget(widget, rect); + } + + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); +} + +/*! + Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from + the backing store to the \a widget's native parent next time flush() is called. + + Paint on screen widgets are ignored. +*/ +void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widget, const QPoint &topLevelOffset) +{ + if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty()) + return; + +#if defined(Q_WS_QWS) || defined(Q_WS_MAC) + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region.translated(topLevelOffset); + return; +#endif + + // Top-level. + if (widget == tlw) { + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region; + return; + } + + // Alien widgets. + if (!widget->internalWinId() && !widget->isWindow()) { + QWidget *nativeParent = widget->nativeParentWidget(); // Alien widgets with the top-level as the native parent (common case). + if (nativeParent == tlw) { + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region.translated(topLevelOffset); + return; + } + + // Alien widgets with native parent != tlw. + QWidgetPrivate *nativeParentPrivate = nativeParent->d_func(); + if (!nativeParentPrivate->needsFlush) + nativeParentPrivate->needsFlush = new QRegion; + const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint()); + *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset); + appendDirtyOnScreenWidget(nativeParent); + return; + } + + // Native child widgets. + QWidgetPrivate *widgetPrivate = widget->d_func(); + if (!widgetPrivate->needsFlush) + widgetPrivate->needsFlush = new QRegion; + *widgetPrivate->needsFlush += region; + appendDirtyOnScreenWidget(widget); +} + +void QWidgetBackingStore::removeDirtyWidget(QWidget *w) +{ + if (!w) + return; + + dirtyWidgetsRemoveAll(w); + dirtyOnScreenWidgetsRemoveAll(w); + resetWidget(w); + + QWidgetPrivate *wd = w->d_func(); + const int n = wd->children.count(); + for (int i = 0; i < n; ++i) { + if (QWidget *child = qobject_cast(wd->children.at(i))) + removeDirtyWidget(child); + } +} + +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) +bool QWidgetBackingStore::hasDirtyWindowDecoration() const +{ + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (tlwExtra && tlwExtra->qwsManager) + return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty(); + return false; +} + +void QWidgetBackingStore::paintWindowDecoration() +{ + if (!hasDirtyWindowDecoration()) + return; + + QDecoration &decoration = QApplication::qwsDecoration(); + const QRect decorationRect = tlw->rect(); + QRegion decorationRegion = decoration.region(tlw, decorationRect); + + QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func(); + const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint + && !managerPrivate->dirtyClip.isEmpty(); + + if (doClipping) { + decorationRegion &= static_cast(windowSurface)->clipRegion(); + decorationRegion &= managerPrivate->dirtyClip; + } + + if (decorationRegion.isEmpty()) + return; + + //### The QWS decorations do not always paint the pixels they promise to paint. + // This causes painting problems with QWSMemorySurface. Since none of the other + // window surfaces actually use the region, passing an empty region is a safe + // workaround. + + windowSurface->beginPaint(QRegion()); + + QPaintEngine *engine = windowSurface->paintDevice()->paintEngine(); + Q_ASSERT(engine); + const QRegion oldSystemClip(engine->systemClip()); + engine->setSystemClip(decorationRegion.translated(tlwOffset)); + + QPainter painter(windowSurface->paintDevice()); + painter.setFont(QApplication::font()); + painter.translate(tlwOffset); + + const int numDirty = managerPrivate->dirtyRegions.size(); + for (int i = 0; i < numDirty; ++i) { + const int area = managerPrivate->dirtyRegions.at(i); + + QRegion clipRegion = decoration.region(tlw, decorationRect, area); + if (!clipRegion.isEmpty()) { + // Decoration styles changes the clip and assumes the old clip is non-empty, + // so we have to set it, but in theory it shouldn't be required. + painter.setClipRegion(clipRegion); + decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i)); + } + } + markDirtyOnScreen(decorationRegion, tlw, QPoint()); + + painter.end(); + windowSurface->endPaint(decorationRegion); + managerPrivate->clearDirtyRegions(); + engine->setSystemClip(oldSystemClip); +} +#endif + +void QWidgetBackingStore::updateLists(QWidget *cur) +{ + if (!cur) + return; + + QList children = cur->children(); + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast(children.at(i)); + if (!child) + continue; + + updateLists(child); + } + + if (cur->testAttribute(Qt::WA_StaticContents)) + addStaticWidget(cur); + +#ifdef Q_BACKINGSTORE_SUBSURFACES + QTLWExtra *extra = cur->d_func()->maybeTopData(); + if (extra && extra->windowSurface && cur != tlw) + subSurfaces.append(extra->windowSurface); +#endif +} + +QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) + : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) + , fullUpdatePending(0) +{ + windowSurface = tlw->windowSurface(); + if (!windowSurface) + windowSurface = topLevel->d_func()->createDefaultWindowSurface(); + + // The QWindowSurface constructor will call QWidget::setWindowSurface(), + // but automatically created surfaces should not be added to the topdata. +#ifdef Q_BACKINGSTORE_SUBSURFACES + Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface); +#endif + topLevel->d_func()->topData()->windowSurface = 0; + + // Ensure all existing subsurfaces and static widgets are added to their respective lists. + updateLists(topLevel); +} + +QWidgetBackingStore::~QWidgetBackingStore() +{ + for (int c = 0; c < dirtyWidgets.size(); ++c) { + resetWidget(dirtyWidgets.at(c)); + } + + delete windowSurface; + windowSurface = 0; + delete dirtyOnScreenWidgets; + dirtyOnScreenWidgets = 0; +} + +//parent's coordinates; move whole rect; update parent and widget +//assume the screen blt has already been done, so we don't need to refresh that part +void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) +{ + Q_Q(QWidget); + if (!q->isVisible() || (dx == 0 && dy == 0)) + return; + + QWidget *tlw = q->window(); + QTLWExtra* x = tlw->d_func()->topData(); + if (x->inTopLevelResize) + return; + + static int accelEnv = -1; + if (accelEnv == -1) { + accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0; + } + + QWidget *pw = q->parentWidget(); + QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); + QWidgetPrivate *pd = pw->d_func(); + QRect clipR(pd->clipRect()); +#ifdef Q_WS_QWS + QWidgetBackingStore *wbs = x->backingStore.data(); + QWSWindowSurface *surface = static_cast(wbs->windowSurface); + clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect()); +#endif + const QRect newRect(rect.translated(dx, dy)); + QRect destRect = rect.intersected(clipR); + if (destRect.isValid()) + destRect = destRect.translated(dx, dy).intersected(clipR); + const QRect sourceRect(destRect.translated(-dx, -dy)); + const QRect parentRect(rect & clipR); + + bool accelerateMove = accelEnv && isOpaque +#ifndef QT_NO_GRAPHICSVIEW + // No accelerate move for proxy widgets. + && !tlw->d_func()->extra->proxyWidget +#endif + && !isOverlapped(sourceRect) && !isOverlapped(destRect); + + if (!accelerateMove) { + QRegion parentR(effectiveRectFor(parentRect)); + if (!extra || !extra->hasMask) { + parentR -= newRect; + } else { + // invalidateBuffer() excludes anything outside the mask + parentR += newRect & clipR; + } + pd->invalidateBuffer(parentR); + invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); + } else { + + QWidgetBackingStore *wbs = x->backingStore.data(); + QRegion childExpose(newRect & clipR); + + if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) + childExpose -= destRect; + + if (!pw->updatesEnabled()) + return; + + const bool childUpdatesEnabled = q->updatesEnabled(); + if (childUpdatesEnabled && !childExpose.isEmpty()) { + childExpose.translate(-data.crect.topLeft()); + wbs->markDirty(childExpose, q); + isMoved = true; + } + + QRegion parentExpose(parentRect); + parentExpose -= newRect; + if (extra && extra->hasMask) + parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); + + if (!parentExpose.isEmpty()) { + wbs->markDirty(parentExpose, pw); + pd->isMoved = true; + } + + if (childUpdatesEnabled) { + QRegion needsFlush(sourceRect); + needsFlush += destRect; + wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset); + } + } +} + +//widget's coordinates; scroll within rect; only update widget +void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) +{ + Q_Q(QWidget); + QWidget *tlw = q->window(); + QTLWExtra* x = tlw->d_func()->topData(); + if (x->inTopLevelResize) + return; + + QWidgetBackingStore *wbs = x->backingStore.data(); + if (!wbs) + return; + + static int accelEnv = -1; + if (accelEnv == -1) { + accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0; + } + + QRect scrollRect = rect & clipRect(); + bool overlapped = false; + bool accelerateScroll = accelEnv && isOpaque + && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); + +#if defined(Q_WS_QWS) + QWSWindowSurface *surface; + surface = static_cast(wbs->windowSurface); + + if (accelerateScroll && !surface->isBuffered()) { + const QRegion surfaceClip = surface->clipRegion(); + const QRegion outsideClip = QRegion(rect) - surfaceClip; + if (!outsideClip.isEmpty()) { + const QVector clipped = (surfaceClip & rect).rects(); + if (clipped.size() < 8) { + for (int i = 0; i < clipped.size(); ++i) + this->scrollRect(clipped.at(i), dx, dy); + return; + } else { + accelerateScroll = false; + } + } + } +#endif // Q_WS_QWS + + if (!accelerateScroll) { + if (overlapped) { + QRegion region(scrollRect); + subtractOpaqueSiblings(region); + invalidateBuffer(region); + }else { + invalidateBuffer(scrollRect); + } + } else { + const QPoint toplevelOffset = q->mapTo(tlw, QPoint()); +#ifdef Q_WS_QWS + QWSWindowSurface *surface = static_cast(wbs->windowSurface); + const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect; + const QRect clipBoundingRect = clip.boundingRect(); + scrollRect &= clipBoundingRect; +#endif + const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; + const QRect sourceRect = destRect.translated(-dx, -dy); + + QRegion childExpose(scrollRect); + if (sourceRect.isValid()) { + if (wbs->bltRect(sourceRect, dx, dy, q)) + childExpose -= destRect; + } + + if (inDirtyList) { + if (rect == q->rect()) { + dirty.translate(dx, dy); + } else { + QRegion dirtyScrollRegion = dirty.intersected(scrollRect); + if (!dirtyScrollRegion.isEmpty()) { + dirty -= dirtyScrollRegion; + dirtyScrollRegion.translate(dx, dy); + dirty += dirtyScrollRegion; + } + } + } + + if (!q->updatesEnabled()) + return; + + if (!childExpose.isEmpty()) { + wbs->markDirty(childExpose, q); + isScrolled = true; + } + + // Instead of using native scroll-on-screen, we copy from + // backingstore, giving only one screen update for each + // scroll, and a solid appearance + wbs->markDirtyOnScreen(destRect, q, toplevelOffset); + } +} + +static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) +{ + if (!tlw || !tlwExtra) + return true; + +#ifdef Q_WS_X11 + // Delay the sync until we get an Expose event from X11 (initial show). + // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred. + // However, we must repaint immediately regardless of the state if someone calls repaint(). + if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint) + return true; +#endif + + if (!tlw->testAttribute(Qt::WA_Mapped)) + return true; + + if (!tlw->isVisible() +#ifndef Q_WS_X11 + // If we're minimized on X11, WA_Mapped will be false and we + // will return in the case above. Some window managers on X11 + // sends us the PropertyNotify to change the minimized state + // *AFTER* we've received the expose event, which is baaad. + || tlw->isMinimized() +#endif + ) + return true; + + return false; +} + +/*! + Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store. + + If there's nothing to repaint, the area is flushed and painting does not occur; + otherwise the area is marked as dirty on screen and will be flushed right after + we are done with all painting. +*/ +void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) +{ + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) + return; + + if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() + || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { + return; + } + + // If there's no preserved contents support we always need + // to do a full repaint before flushing + if (!windowSurface->hasFeature(QWindowSurface::PreservedContents)) + fullUpdatePending = true; + + // Nothing to repaint. + if (!isDirty()) { + qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset); + return; + } + + if (exposedWidget != tlw) + markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); + else + markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); + sync(); +} + +/*! + Synchronizes the backing store, i.e. dirty areas are repainted and flushed. +*/ +void QWidgetBackingStore::sync() +{ + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (discardSyncRequest(tlw, tlwExtra)) { + // If the top-level is minimized, it's not visible on the screen so we can delay the + // update until it's shown again. In order to do that we must keep the dirty states. + // These will be cleared when we receive the first expose after showNormal(). + // However, if the widget is not visible (isVisible() returns false), everything will + // be invalidated once the widget is shown again, so clear all dirty states. + if (!tlw->isVisible()) { + dirty = QRegion(); + for (int i = 0; i < dirtyWidgets.size(); ++i) + resetWidget(dirtyWidgets.at(i)); + dirtyWidgets.clear(); + fullUpdatePending = false; + } + return; + } + + const bool updatesDisabled = !tlw->updatesEnabled(); + bool repaintAllWidgets = false; + + const bool inTopLevelResize = tlwExtra->inTopLevelResize; + const QRect tlwRect(topLevelRect()); +#ifdef Q_WS_QPA + const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); +#else + const QRect surfaceGeometry(windowSurface->geometry()); +#endif + if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { + if (hasStaticContents()) { + // Repaint existing dirty area and newly visible area. + const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); + const QRegion staticRegion(staticContents(0, clipRect)); + QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); + newVisible -= staticRegion; + dirty += newVisible; + windowSurface->setStaticContents(staticRegion); + } else { + // Repaint everything. + dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); + for (int i = 0; i < dirtyWidgets.size(); ++i) + resetWidget(dirtyWidgets.at(i)); + dirtyWidgets.clear(); + repaintAllWidgets = true; + } + } + +#ifdef Q_WS_QPA + if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) + windowSurface->resize(tlwRect.size()); +#else + if (inTopLevelResize || surfaceGeometry != tlwRect) + windowSurface->setGeometry(tlwRect); +#endif + + if (updatesDisabled) + return; + + if (hasDirtyFromPreviousSync) + dirty += dirtyFromPreviousSync; + + // Contains everything that needs repaint. + QRegion toClean(dirty); + + // Loop through all update() widgets and remove them from the list before they are + // painted (in case someone calls update() in paintEvent). If the widget is opaque + // and does not have transparent overlapping siblings, append it to the + // opaqueNonOverlappedWidgets list and paint it directly without composition. + QVarLengthArray opaqueNonOverlappedWidgets; + for (int i = 0; i < dirtyWidgets.size(); ++i) { + QWidget *w = dirtyWidgets.at(i); + QWidgetPrivate *wd = w->d_func(); + if (wd->data.in_destructor) + continue; + + // Clip with mask() and clipRect(). + wd->dirty &= wd->clipRect(); + wd->clipToEffectiveMask(wd->dirty); + + // Subtract opaque siblings and children. + bool hasDirtySiblingsAbove = false; + // We know for sure that the widget isn't overlapped if 'isMoved' is true. + if (!wd->isMoved) + wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); + // Scrolled and moved widgets must draw all children. + if (!wd->isScrolled && !wd->isMoved) + wd->subtractOpaqueChildren(wd->dirty, w->rect()); + + if (wd->dirty.isEmpty()) { + resetWidget(w); + continue; + } + + const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) + : wd->dirty); + toClean += widgetDirty; + +#ifndef QT_NO_GRAPHICSVIEW + if (tlw->d_func()->extra->proxyWidget) { + resetWidget(w); + continue; + } +#endif + + if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { + opaqueNonOverlappedWidgets.append(w); + } else { + resetWidget(w); + dirty += widgetDirty; + } + } + dirtyWidgets.clear(); + + fullUpdatePending = false; + + if (toClean.isEmpty()) { + // Nothing to repaint. However, we might have newly exposed areas on the + // screen if this function was called from sync(QWidget *, QRegion)), so + // we have to make sure those are flushed. + flush(); + return; + } + +#ifndef QT_NO_GRAPHICSVIEW + if (tlw->d_func()->extra->proxyWidget) { + updateStaticContentsSize(); + dirty = QRegion(); + const QVector rects(toClean.rects()); + for (int i = 0; i < rects.size(); ++i) + tlw->d_func()->extra->proxyWidget->update(rects.at(i)); + return; + } +#endif + +#ifndef Q_BACKINGSTORE_SUBSURFACES + BeginPaintInfo beginPaintInfo; + beginPaint(toClean, tlw, windowSurface, &beginPaintInfo); + if (beginPaintInfo.nothingToPaint) { + for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) + resetWidget(opaqueNonOverlappedWidgets[i]); + dirty = QRegion(); + return; + } +#endif + + // Must do this before sending any paint events because + // the size may change in the paint event. + updateStaticContentsSize(); + const QRegion dirtyCopy(dirty); + dirty = QRegion(); + + // Paint opaque non overlapped widgets. + for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { + QWidget *w = opaqueNonOverlappedWidgets[i]; + QWidgetPrivate *wd = w->d_func(); + + int flags = QWidgetPrivate::DrawRecursive; + // Scrolled and moved widgets must draw all children. + if (!wd->isScrolled && !wd->isMoved) + flags |= QWidgetPrivate::DontDrawOpaqueChildren; + if (w == tlw) + flags |= QWidgetPrivate::DrawAsRoot; + + QRegion toBePainted(wd->dirty); + resetWidget(w); + +#ifdef Q_BACKINGSTORE_SUBSURFACES + QWindowSurface *subSurface = w->windowSurface(); + BeginPaintInfo beginPaintInfo; + + QPoint off = w->mapTo(tlw, QPoint()); + toBePainted.translate(off); + beginPaint(toBePainted, w, subSurface, &beginPaintInfo, true); + toBePainted.translate(-off); + + if (beginPaintInfo.nothingToPaint) + continue; + + if (beginPaintInfo.windowSurfaceRecreated) { + // Eep the window surface has changed. The old one may have been + // deleted, in which case we will segfault on the call to + // painterOffset() below. Use the new window surface instead. + subSurface = w->windowSurface(); + } + + QPoint offset(tlwOffset); + if (subSurface == windowSurface) + offset += w->mapTo(tlw, QPoint()); + else + offset = static_cast(subSurface)->painterOffset(); + wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this); + + endPaint(toBePainted, subSurface, &beginPaintInfo); +#else + QPoint offset(tlwOffset); + if (w != tlw) + offset += w->mapTo(tlw, QPoint()); + wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this); +#endif + } + + // Paint the rest with composition. +#ifndef Q_BACKINGSTORE_SUBSURFACES + if (repaintAllWidgets || !dirtyCopy.isEmpty()) { + const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; + tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); + } + + endPaint(toClean, windowSurface, &beginPaintInfo); +#else + if (!repaintAllWidgets && dirtyCopy.isEmpty()) + return; // Nothing more to paint. + + QList surfaceList(subSurfaces); + surfaceList.prepend(windowSurface); + const QRect dirtyBoundingRect(dirtyCopy.boundingRect()); + + // Loop through all window surfaces (incl. the top-level surface) and + // repaint those intersecting with the bounding rect of the dirty region. + for (int i = 0; i < surfaceList.size(); ++i) { + QWindowSurface *subSurface = surfaceList.at(i); + QWidget *w = subSurface->window(); + QWidgetPrivate *wd = w->d_func(); + + const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint())); + if (!qRectIntersects(dirtyBoundingRect, clipRect)) + continue; + + toClean = dirtyCopy; + BeginPaintInfo beginPaintInfo; + beginPaint(toClean, w, subSurface, &beginPaintInfo); + if (beginPaintInfo.nothingToPaint) + continue; + + if (beginPaintInfo.windowSurfaceRecreated) { + // Eep the window surface has changed. The old one may have been + // deleted, in which case we will segfault on the call to + // painterOffset() below. Use the new window surface instead. + subSurface = w->windowSurface(); + } + + int flags = QWidgetPrivate::DrawRecursive; + if (w == tlw) + flags |= QWidgetPrivate::DrawAsRoot; + const QPoint painterOffset = static_cast(subSurface)->painterOffset(); + wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this); + + endPaint(toClean, subSurface, &beginPaintInfo); + } +#endif +} + +/*! + Flushes the contents of the backing store into the top-level widget. + If the \a widget is non-zero, the content is flushed to the \a widget. + If the \a surface is non-zero, the content of the \a surface is flushed. +*/ +void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface) +{ +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + paintWindowDecoration(); +#endif + + if (!dirtyOnScreen.isEmpty()) { + QWidget *target = widget ? widget : tlw; + QWindowSurface *source = surface ? surface : windowSurface; + qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset); + dirtyOnScreen = QRegion(); + } + + if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) + return; + + for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { + QWidget *w = dirtyOnScreenWidgets->at(i); + QWidgetPrivate *wd = w->d_func(); + Q_ASSERT(wd->needsFlush); + qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset); + *wd->needsFlush = QRegion(); + } + dirtyOnScreenWidgets->clear(); +} + +static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra) +{ + Q_ASSERT(widget); + if (QApplication::closingDown()) + return true; + + if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore) + return true; + + if (!widget->isVisible() || !widget->updatesEnabled()) + return true; + + return false; +} + +/*! + Invalidates the buffer when the widget is resized. + Static areas are never invalidated unless absolutely needed. +*/ +void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize) +{ + Q_Q(QWidget); + Q_ASSERT(!q->isWindow()); + Q_ASSERT(q->parentWidget()); + + const bool staticContents = q->testAttribute(Qt::WA_StaticContents); + const bool sizeDecreased = (data.crect.width() < oldSize.width()) + || (data.crect.height() < oldSize.height()); + + const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y()); + const bool parentAreaExposed = !offset.isNull() || sizeDecreased; + const QRect newWidgetRect(q->rect()); + const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height()); + + if (!staticContents || graphicsEffect) { + QRegion staticChildren; + QWidgetBackingStore *bs = 0; + if (offset.isNull() && (bs = maybeBackingStore())) + staticChildren = bs->staticContents(q, oldWidgetRect); + const bool hasStaticChildren = !staticChildren.isEmpty(); + + if (hasStaticChildren) { + QRegion dirty(newWidgetRect); + dirty -= staticChildren; + invalidateBuffer(dirty); + } else { + // Entire widget needs repaint. + invalidateBuffer(newWidgetRect); + } + + if (!parentAreaExposed) + return; + + // Invalidate newly exposed area of the parent. + if (!graphicsEffect && extra && extra->hasMask) { + QRegion parentExpose(extra->mask.translated(oldPos)); + parentExpose &= QRect(oldPos, oldSize); + if (hasStaticChildren) + parentExpose -= data.crect; // Offset is unchanged, safe to do this. + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + if (hasStaticChildren && !graphicsEffect) { + QRegion parentExpose(QRect(oldPos, oldSize)); + parentExpose -= data.crect; // Offset is unchanged, safe to do this. + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize))); + } + } + return; + } + + // Move static content to its new position. + if (!offset.isNull()) { + if (sizeDecreased) { + const QSize minSize(qMin(oldSize.width(), data.crect.width()), + qMin(oldSize.height(), data.crect.height())); + moveRect(QRect(oldPos, minSize), offset.x(), offset.y()); + } else { + moveRect(QRect(oldPos, oldSize), offset.x(), offset.y()); + } + } + + // Invalidate newly visible area of the widget. + if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) { + QRegion newVisible(newWidgetRect); + newVisible -= oldWidgetRect; + invalidateBuffer(newVisible); + } + + if (!parentAreaExposed) + return; + + // Invalidate newly exposed area of the parent. + const QRect oldRect(oldPos, oldSize); + if (extra && extra->hasMask) { + QRegion parentExpose(oldRect); + parentExpose &= extra->mask.translated(oldPos); + parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect); + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + QRegion parentExpose(oldRect); + parentExpose -= data.crect; + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } +} + +/*! + Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e. + all widgets intersecting with the region will be repainted when the backing store + is synced. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) +{ + Q_Q(QWidget); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty()) + return; + + QRegion wrgn(rgn); + wrgn &= clipRect(); + if (!graphicsEffect && extra && extra->hasMask) + wrgn &= extra->mask; + if (wrgn.isEmpty()) + return; + + tlwExtra->backingStore->markDirty(wrgn, q, false, true); +} + +/*! + This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but + is more efficient as it eliminates QRegion operations/allocations and can + use the rect more precisely for additional cut-offs. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetPrivate::invalidateBuffer(const QRect &rect) +{ + Q_Q(QWidget); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty()) + return; + + QRect wRect(rect); + wRect &= clipRect(); + if (wRect.isEmpty()) + return; + + if (graphicsEffect || !extra || !extra->hasMask) { + tlwExtra->backingStore->markDirty(wRect, q, false, true); + return; + } + + QRegion wRgn(extra->mask); + wRgn &= wRect; + if (wRgn.isEmpty()) + return; + + tlwExtra->backingStore->markDirty(wRgn, q, false, true); +} + +void QWidgetPrivate::repaint_sys(const QRegion &rgn) +{ + if (data.in_destructor) + return; + + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_StaticContents)) { + if (!extra) + createExtra(); + extra->staticContentsSize = data.crect.size(); + } + +#ifdef Q_WS_QPA //Dont even call q->p + QPaintEngine *engine = 0; +#else + QPaintEngine *engine = q->paintEngine(); +#endif + // QGLWidget does not support partial updates if: + // 1) The context is double buffered + // 2) The context is single buffered and auto-fill background is enabled. + const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL + || engine->type() == QPaintEngine::OpenGL2)) + && (usesDoubleBufferedGLContext || q->autoFillBackground()); + QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn); + +#ifdef Q_WS_MAC + // No difference between update() and repaint() on the Mac. + update_sys(toBePainted); + return; +#endif + + toBePainted &= clipRect(); + clipToEffectiveMask(toBePainted); + if (toBePainted.isEmpty()) + return; // Nothing to repaint. + +#ifndef QT_NO_PAINT_DEBUG + bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); +#endif + + drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0); + +#ifndef QT_NO_PAINT_DEBUG + if (flushed) + QWidgetBackingStore::unflushPaint(q, toBePainted); +#endif + + if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive()) + qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); +} + + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qbackingstore_p.h b/src/widgets/kernel/qbackingstore_p.h new file mode 100644 index 0000000000..05f4bfcb6c --- /dev/null +++ b/src/widgets/kernel/qbackingstore_p.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBACKINGSTORE_P_H +#define QBACKINGSTORE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#ifdef Q_WS_QWS +#include +#endif + +QT_BEGIN_NAMESPACE + +class QWindowSurface; + +struct BeginPaintInfo { + inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), windowSurfaceRecreated(0) {} + uint wasFlushed : 1; + uint nothingToPaint : 1; + uint windowSurfaceRecreated : 1; +}; + +class Q_AUTOTEST_EXPORT QWidgetBackingStore +{ +public: + QWidgetBackingStore(QWidget *t); + ~QWidgetBackingStore(); + + static void showYellowThing(QWidget *widget, const QRegion &rgn, int msec, bool); + + void sync(QWidget *exposedWidget, const QRegion &exposedRegion); + void sync(); + void flush(QWidget *widget = 0, QWindowSurface *surface = 0); + + inline QPoint topLevelOffset() const { return tlwOffset; } + + QWindowSurface *surface() const { return windowSurface; } + + inline bool isDirty() const + { + return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && !hasDirtyFromPreviousSync + && !fullUpdatePending +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + && !hasDirtyWindowDecoration() +#endif + ); + } + + // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). + void markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately = false, + bool invalidateBuffer = false); + void markDirty(const QRect &rect, QWidget *widget, bool updateImmediately = false, + bool invalidateBuffer = false); + +private: + QWidget *tlw; + QRegion dirtyOnScreen; // needsFlush + QRegion dirty; // needsRepaint + QRegion dirtyFromPreviousSync; + QVector dirtyWidgets; + QVector *dirtyOnScreenWidgets; + QList staticWidgets; + QWindowSurface *windowSurface; +#ifdef Q_BACKINGSTORE_SUBSURFACES + QList subSurfaces; +#endif + uint hasDirtyFromPreviousSync : 1; + uint fullUpdatePending : 1; + + QPoint tlwOffset; + + static bool flushPaint(QWidget *widget, const QRegion &rgn); + static void unflushPaint(QWidget *widget, const QRegion &rgn); + + bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget); + void releaseBuffer(); + + void beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface, + BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates = true); + void endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, BeginPaintInfo *beginPaintInfo); + + QRegion dirtyRegion(QWidget *widget = 0) const; + QRegion staticContents(QWidget *widget = 0, const QRect &withinClipRect = QRect()) const; + + void markDirtyOnScreen(const QRegion &dirtyOnScreen, QWidget *widget, const QPoint &topLevelOffset); + + void removeDirtyWidget(QWidget *w); + +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + bool hasDirtyWindowDecoration() const; + void paintWindowDecoration(); +#endif + void updateLists(QWidget *widget); + + inline void addDirtyWidget(QWidget *widget, const QRegion &rgn) + { + if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) { + QWidgetPrivate *widgetPrivate = widget->d_func(); +#ifndef QT_NO_GRAPHICSEFFECT + if (widgetPrivate->graphicsEffect) + widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect()); + else +#endif //QT_NO_GRAPHICSEFFECT + widgetPrivate->dirty = rgn; + dirtyWidgets.append(widget); + widgetPrivate->inDirtyList = true; + } + } + + inline void dirtyWidgetsRemoveAll(QWidget *widget) + { + int i = 0; + while (i < dirtyWidgets.size()) { + if (dirtyWidgets.at(i) == widget) + dirtyWidgets.remove(i); + else + ++i; + } + } + + inline void addStaticWidget(QWidget *widget) + { + if (!widget) + return; + + Q_ASSERT(widget->testAttribute(Qt::WA_StaticContents)); + if (!staticWidgets.contains(widget)) + staticWidgets.append(widget); + } + + inline void removeStaticWidget(QWidget *widget) + { staticWidgets.removeAll(widget); } + + // Move the reparented widget and all its static children from this backing store + // to the new backing store if reparented into another top-level / backing store. + inline void moveStaticWidgets(QWidget *reparented) + { + Q_ASSERT(reparented); + QWidgetBackingStore *newBs = reparented->d_func()->maybeBackingStore(); + if (newBs == this) + return; + + int i = 0; + while (i < staticWidgets.size()) { + QWidget *w = staticWidgets.at(i); + if (reparented == w || reparented->isAncestorOf(w)) { + staticWidgets.removeAt(i); + if (newBs) + newBs->addStaticWidget(w); + } else { + ++i; + } + } + } + + inline QRect topLevelRect() const + { +#ifdef Q_WS_QWS + return tlw->frameGeometry(); +#else + return tlw->data->crect; +#endif + } + + inline void appendDirtyOnScreenWidget(QWidget *widget) + { + if (!widget) + return; + + if (!dirtyOnScreenWidgets) { + dirtyOnScreenWidgets = new QVector; + dirtyOnScreenWidgets->append(widget); + } else if (!dirtyOnScreenWidgets->contains(widget)) { + dirtyOnScreenWidgets->append(widget); + } + } + + inline void dirtyOnScreenWidgetsRemoveAll(QWidget *widget) + { + if (!widget || !dirtyOnScreenWidgets) + return; + + int i = 0; + while (i < dirtyOnScreenWidgets->size()) { + if (dirtyOnScreenWidgets->at(i) == widget) + dirtyOnScreenWidgets->remove(i); + else + ++i; + } + } + + inline void resetWidget(QWidget *widget) + { + if (widget) { + widget->d_func()->inDirtyList = false; + widget->d_func()->isScrolled = false; + widget->d_func()->isMoved = false; + widget->d_func()->dirty = QRegion(); + } + } + + inline void updateStaticContentsSize() + { + for (int i = 0; i < staticWidgets.size(); ++i) { + QWidgetPrivate *wd = staticWidgets.at(i)->d_func(); + if (!wd->extra) + wd->createExtra(); + wd->extra->staticContentsSize = wd->data.crect.size(); + } + } + + inline bool hasStaticContents() const + { return !staticWidgets.isEmpty() && windowSurface->hasFeature(QWindowSurface::StaticContents); } + + friend QRegion qt_dirtyRegion(QWidget *); + friend class QWidgetPrivate; + friend class QWidget; + friend class QWSManagerPrivate; + friend class QETWidget; + friend class QWindowSurface; + friend class QWSWindowSurface; +}; + +QT_END_NAMESPACE + +#endif // QBACKINGSTORE_P_H diff --git a/src/widgets/kernel/qboxlayout.cpp b/src/widgets/kernel/qboxlayout.cpp new file mode 100644 index 0000000000..6946f9bd27 --- /dev/null +++ b/src/widgets/kernel/qboxlayout.cpp @@ -0,0 +1,1550 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qboxlayout.h" +#include "qapplication.h" +#include "qwidget.h" +#include "qlist.h" +#include "qsizepolicy.h" +#include "qvector.h" + +#include "qlayoutengine_p.h" +#include "qlayout_p.h" + +QT_BEGIN_NAMESPACE + +/* + Returns true if the \a widget can be added to the \a layout; + otherwise returns false. +*/ +static bool checkWidget(QLayout *layout, QWidget *widget) +{ + if (!widget) { + qWarning("QLayout: Cannot add null widget to %s/%s", layout->metaObject()->className(), + layout->objectName().toLocal8Bit().data()); + return false; + } + return true; +} + +struct QBoxLayoutItem +{ + QBoxLayoutItem(QLayoutItem *it, int stretch_ = 0) + : item(it), stretch(stretch_), magic(false) { } + ~QBoxLayoutItem() { delete item; } + + int hfw(int w) { + if (item->hasHeightForWidth()) { + return item->heightForWidth(w); + } else { + return item->sizeHint().height(); + } + } + int mhfw(int w) { + if (item->hasHeightForWidth()) { + return item->heightForWidth(w); + } else { + return item->minimumSize().height(); + } + } + int hStretch() { + if (stretch == 0 && item->widget()) { + return item->widget()->sizePolicy().horizontalStretch(); + } else { + return stretch; + } + } + int vStretch() { + if (stretch == 0 && item->widget()) { + return item->widget()->sizePolicy().verticalStretch(); + } else { + return stretch; + } + } + + QLayoutItem *item; + int stretch; + bool magic; +}; + +class QBoxLayoutPrivate : public QLayoutPrivate +{ + Q_DECLARE_PUBLIC(QBoxLayout) +public: + QBoxLayoutPrivate() : hfwWidth(-1), dirty(true), spacing(-1) { } + ~QBoxLayoutPrivate(); + + void setDirty() { + geomArray.clear(); + hfwWidth = -1; + hfwHeight = -1; + dirty = true; + } + + QList list; + QVector geomArray; + int hfwWidth; + int hfwHeight; + int hfwMinHeight; + QSize sizeHint; + QSize minSize; + QSize maxSize; + int leftMargin, topMargin, rightMargin, bottomMargin; + Qt::Orientations expanding; + uint hasHfw : 1; + uint dirty : 1; + QBoxLayout::Direction dir; + int spacing; + + inline void deleteAll() { while (!list.isEmpty()) delete list.takeFirst(); } + + void setupGeom(); + void calcHfw(int); + + void effectiveMargins(int *left, int *top, int *right, int *bottom) const; +}; + +QBoxLayoutPrivate::~QBoxLayoutPrivate() +{ +} + +static inline bool horz(QBoxLayout::Direction dir) +{ + return dir == QBoxLayout::RightToLeft || dir == QBoxLayout::LeftToRight; +} + +/** + * The purpose of this function is to make sure that widgets are not laid out outside its layout. + * E.g. the layoutItemRect margins are only meant to take of the surrounding margins/spacings. + * However, if the margin is 0, it can easily cover the area of a widget above it. + */ +void QBoxLayoutPrivate::effectiveMargins(int *left, int *top, int *right, int *bottom) const +{ + int l = leftMargin; + int t = topMargin; + int r = rightMargin; + int b = bottomMargin; +#ifdef Q_WS_MAC + Q_Q(const QBoxLayout); + if (horz(dir)) { + QBoxLayoutItem *leftBox = 0; + QBoxLayoutItem *rightBox = 0; + + if (left || right) { + leftBox = list.value(0); + rightBox = list.value(list.count() - 1); + if (dir == QBoxLayout::RightToLeft) + qSwap(leftBox, rightBox); + + int leftDelta = 0; + int rightDelta = 0; + if (leftBox) { + QLayoutItem *itm = leftBox->item; + if (QWidget *w = itm->widget()) + leftDelta = itm->geometry().left() - w->geometry().left(); + } + if (rightBox) { + QLayoutItem *itm = rightBox->item; + if (QWidget *w = itm->widget()) + rightDelta = w->geometry().right() - itm->geometry().right(); + } + QWidget *w = q->parentWidget(); + Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection(); + if (layoutDirection == Qt::RightToLeft) + qSwap(leftDelta, rightDelta); + + l = qMax(l, leftDelta); + r = qMax(r, rightDelta); + } + + int count = top || bottom ? list.count() : 0; + for (int i = 0; i < count; ++i) { + QBoxLayoutItem *box = list.at(i); + QLayoutItem *itm = box->item; + QWidget *w = itm->widget(); + if (w) { + QRect lir = itm->geometry(); + QRect wr = w->geometry(); + if (top) + t = qMax(t, lir.top() - wr.top()); + if (bottom) + b = qMax(b, wr.bottom() - lir.bottom()); + } + } + } else { // vertical layout + QBoxLayoutItem *topBox = 0; + QBoxLayoutItem *bottomBox = 0; + + if (top || bottom) { + topBox = list.value(0); + bottomBox = list.value(list.count() - 1); + if (dir == QBoxLayout::BottomToTop) { + qSwap(topBox, bottomBox); + } + + if (top && topBox) { + QLayoutItem *itm = topBox->item; + QWidget *w = itm->widget(); + if (w) + t = qMax(t, itm->geometry().top() - w->geometry().top()); + } + + if (bottom && bottomBox) { + QLayoutItem *itm = bottomBox->item; + QWidget *w = itm->widget(); + if (w) + b = qMax(b, w->geometry().bottom() - itm->geometry().bottom()); + } + } + + int count = left || right ? list.count() : 0; + for (int i = 0; i < count; ++i) { + QBoxLayoutItem *box = list.at(i); + QLayoutItem *itm = box->item; + QWidget *w = itm->widget(); + if (w) { + QRect lir = itm->geometry(); + QRect wr = w->geometry(); + if (left) + l = qMax(l, lir.left() - wr.left()); + if (right) + r = qMax(r, wr.right() - lir.right()); + } + } + } +#endif + if (left) + *left = l; + if (top) + *top = t; + if (right) + *right = r; + if (bottom) + *bottom = b; +} + + +/* + Initializes the data structure needed by qGeomCalc and + recalculates max/min and size hint. +*/ +void QBoxLayoutPrivate::setupGeom() +{ + if (!dirty) + return; + + Q_Q(QBoxLayout); + int maxw = horz(dir) ? 0 : QLAYOUTSIZE_MAX; + int maxh = horz(dir) ? QLAYOUTSIZE_MAX : 0; + int minw = 0; + int minh = 0; + int hintw = 0; + int hinth = 0; + + bool horexp = false; + bool verexp = false; + + hasHfw = false; + + int n = list.count(); + geomArray.clear(); + QVector a(n); + + QSizePolicy::ControlTypes controlTypes1; + QSizePolicy::ControlTypes controlTypes2; + int fixedSpacing = q->spacing(); + int previousNonEmptyIndex = -1; + + QStyle *style = 0; + if (fixedSpacing < 0) { + if (QWidget *parentWidget = q->parentWidget()) + style = parentWidget->style(); + } + + for (int i = 0; i < n; i++) { + QBoxLayoutItem *box = list.at(i); + QSize max = box->item->maximumSize(); + QSize min = box->item->minimumSize(); + QSize hint = box->item->sizeHint(); + Qt::Orientations exp = box->item->expandingDirections(); + bool empty = box->item->isEmpty(); + int spacing = 0; + + if (!empty) { + if (fixedSpacing >= 0) { + spacing = (previousNonEmptyIndex >= 0) ? fixedSpacing : 0; +#ifdef Q_WS_MAC + if (!horz(dir) && previousNonEmptyIndex >= 0) { + QBoxLayoutItem *sibling = (dir == QBoxLayout::TopToBottom ? box : list.at(previousNonEmptyIndex)); + if (sibling) { + QWidget *wid = sibling->item->widget(); + if (wid) + spacing = qMax(spacing, sibling->item->geometry().top() - wid->geometry().top()); + } + } +#endif + } else { + controlTypes1 = controlTypes2; + controlTypes2 = box->item->controlTypes(); + if (previousNonEmptyIndex >= 0) { + QSizePolicy::ControlTypes actual1 = controlTypes1; + QSizePolicy::ControlTypes actual2 = controlTypes2; + if (dir == QBoxLayout::RightToLeft || dir == QBoxLayout::BottomToTop) + qSwap(actual1, actual2); + + if (style) { + spacing = style->combinedLayoutSpacing(actual1, actual2, + horz(dir) ? Qt::Horizontal : Qt::Vertical, + 0, q->parentWidget()); + if (spacing < 0) + spacing = 0; + } + } + } + + if (previousNonEmptyIndex >= 0) + a[previousNonEmptyIndex].spacing = spacing; + previousNonEmptyIndex = i; + } + + bool ignore = empty && box->item->widget(); // ignore hidden widgets + bool dummy = true; + if (horz(dir)) { + bool expand = (exp & Qt::Horizontal || box->stretch > 0); + horexp = horexp || expand; + maxw += spacing + max.width(); + minw += spacing + min.width(); + hintw += spacing + hint.width(); + if (!ignore) + qMaxExpCalc(maxh, verexp, dummy, + max.height(), exp & Qt::Vertical, box->item->isEmpty()); + minh = qMax(minh, min.height()); + hinth = qMax(hinth, hint.height()); + + a[i].sizeHint = hint.width(); + a[i].maximumSize = max.width(); + a[i].minimumSize = min.width(); + a[i].expansive = expand; + a[i].stretch = box->stretch ? box->stretch : box->hStretch(); + } else { + bool expand = (exp & Qt::Vertical || box->stretch > 0); + verexp = verexp || expand; + maxh += spacing + max.height(); + minh += spacing + min.height(); + hinth += spacing + hint.height(); + if (!ignore) + qMaxExpCalc(maxw, horexp, dummy, + max.width(), exp & Qt::Horizontal, box->item->isEmpty()); + minw = qMax(minw, min.width()); + hintw = qMax(hintw, hint.width()); + + a[i].sizeHint = hint.height(); + a[i].maximumSize = max.height(); + a[i].minimumSize = min.height(); + a[i].expansive = expand; + a[i].stretch = box->stretch ? box->stretch : box->vStretch(); + } + + a[i].empty = empty; + a[i].spacing = 0; // might be be initialized with a non-zero value in a later iteration + hasHfw = hasHfw || box->item->hasHeightForWidth(); + } + + geomArray = a; + + expanding = (Qt::Orientations) + ((horexp ? Qt::Horizontal : 0) + | (verexp ? Qt::Vertical : 0)); + + minSize = QSize(minw, minh); + maxSize = QSize(maxw, maxh).expandedTo(minSize); + sizeHint = QSize(hintw, hinth).expandedTo(minSize).boundedTo(maxSize); + + q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + int left, top, right, bottom; + effectiveMargins(&left, &top, &right, &bottom); + QSize extra(left + right, top + bottom); + + minSize += extra; + maxSize += extra; + sizeHint += extra; + + dirty = false; +} + +/* + Calculates and stores the preferred height given the width \a w. +*/ +void QBoxLayoutPrivate::calcHfw(int w) +{ + QVector &a = geomArray; + int n = a.count(); + int h = 0; + int mh = 0; + + Q_ASSERT(n == list.size()); + + if (horz(dir)) { + qGeomCalc(a, 0, n, 0, w); + for (int i = 0; i < n; i++) { + QBoxLayoutItem *box = list.at(i); + h = qMax(h, box->hfw(a.at(i).size)); + mh = qMax(mh, box->mhfw(a.at(i).size)); + } + } else { + for (int i = 0; i < n; ++i) { + QBoxLayoutItem *box = list.at(i); + int spacing = a.at(i).spacing; + h += box->hfw(w); + mh += box->mhfw(w); + h += spacing; + mh += spacing; + } + } + hfwWidth = w; + hfwHeight = h; + hfwMinHeight = mh; +} + + +/*! + \class QBoxLayout + + \brief The QBoxLayout class lines up child widgets horizontally or + vertically. + + \ingroup geomanagement + + QBoxLayout takes the space it gets (from its parent layout or from + the parentWidget()), divides it up into a row of boxes, and makes + each managed widget fill one box. + + \image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets + + If the QBoxLayout's orientation is Qt::Horizontal the boxes are + placed in a row, with suitable sizes. Each widget (or other box) + will get at least its minimum size and at most its maximum size. + Any excess space is shared according to the stretch factors (more + about that below). + + \image qvboxlayout-with-5-children.png Vertical box layout with five child widgets + + If the QBoxLayout's orientation is Qt::Vertical, the boxes are + placed in a column, again with suitable sizes. + + The easiest way to create a QBoxLayout is to use one of the + convenience classes, e.g. QHBoxLayout (for Qt::Horizontal boxes) + or QVBoxLayout (for Qt::Vertical boxes). You can also use the + QBoxLayout constructor directly, specifying its direction as + LeftToRight, RightToLeft, TopToBottom, or BottomToTop. + + If the QBoxLayout is not the top-level layout (i.e. it is not + managing all of the widget's area and children), you must add it + to its parent layout before you can do anything with it. The + normal way to add a layout is by calling + parentLayout-\>addLayout(). + + Once you have done this, you can add boxes to the QBoxLayout using + one of four functions: + + \list + \o addWidget() to add a widget to the QBoxLayout and set the + widget's stretch factor. (The stretch factor is along the row of + boxes.) + + \o addSpacing() to create an empty box; this is one of the + functions you use to create nice and spacious dialogs. See below + for ways to set margins. + + \o addStretch() to create an empty, stretchable box. + + \o addLayout() to add a box containing another QLayout to the row + and set that layout's stretch factor. + \endlist + + Use insertWidget(), insertSpacing(), insertStretch() or + insertLayout() to insert a box at a specified position in the + layout. + + QBoxLayout also includes two margin widths: + + \list + \o setContentsMargins() sets the width of the outer border on + each side of the widget. This is the width of the reserved space + along each of the QBoxLayout's four sides. + \o setSpacing() sets the width between neighboring boxes. (You + can use addSpacing() to get more space at a particular spot.) + \endlist + + The margin default is provided by the style. The default margin + most Qt styles specify is 9 for child widgets and 11 for windows. + The spacing defaults to the same as the margin width for a + top-level layout, or to the same as the parent layout. + + To remove a widget from a layout, call removeWidget(). Calling + QWidget::hide() on a widget also effectively removes the widget + from the layout until QWidget::show() is called. + + You will almost always want to use QVBoxLayout and QHBoxLayout + rather than QBoxLayout because of their convenient constructors. + + \sa QGridLayout, QStackedLayout, {Layout Management} +*/ + +/*! + \enum QBoxLayout::Direction + + This type is used to determine the direction of a box layout. + + \value LeftToRight Horizontal from left to right. + \value RightToLeft Horizontal from right to left. + \value TopToBottom Vertical from top to bottom. + \value BottomToTop Vertical from bottom to top. + + \omitvalue Down + \omitvalue Up +*/ + +/*! + Constructs a new QBoxLayout with direction \a dir and parent widget \a + parent. + + \sa direction() +*/ +QBoxLayout::QBoxLayout(Direction dir, QWidget *parent) + : QLayout(*new QBoxLayoutPrivate, 0, parent) +{ + Q_D(QBoxLayout); + d->dir = dir; +} + +#ifdef QT3_SUPPORT +/*! + Constructs a new QBoxLayout with direction \a dir and main widget \a + parent. \a parent may not be 0. + + The \a margin is the number of pixels between the edge of the + widget and its managed children. The \a spacing is the default + number of pixels between neighboring children. If \a spacing is -1 + the value of \a margin is used for \a spacing. + + \a name is the internal object name. + + \sa direction() +*/ +QBoxLayout::QBoxLayout(QWidget *parent, Direction dir, + int margin, int spacing, const char *name) + : QLayout(*new QBoxLayoutPrivate, 0, parent) +{ + Q_D(QBoxLayout); + d->dir = dir; + setMargin(margin); + setObjectName(QString::fromAscii(name)); + setSpacing(spacing<0 ? margin : spacing); +} + +/*! + Constructs a new QBoxLayout called \a name, with direction \a dir, + and inserts it into \a parentLayout. + + The \a spacing is the default number of pixels between neighboring + children. If \a spacing is -1, the layout will inherit its + parent's spacing(). +*/ +QBoxLayout::QBoxLayout(QLayout *parentLayout, Direction dir, int spacing, + const char *name) + : QLayout(*new QBoxLayoutPrivate, parentLayout, 0) +{ + Q_D(QBoxLayout); + d->dir = dir; + setObjectName(QString::fromAscii(name)); + setSpacing(spacing); +} + +/*! + Constructs a new QBoxLayout called \a name, with direction \a dir. + + If \a spacing is -1, the layout will inherit its parent's + spacing(); otherwise \a spacing is used. + + You must insert this box into another layout. +*/ +QBoxLayout::QBoxLayout(Direction dir, int spacing, const char *name) + : QLayout(*new QBoxLayoutPrivate,0, 0) +{ + Q_D(QBoxLayout); + d->dir = dir; + setObjectName(QString::fromAscii(name)); + setSpacing(spacing); +} +#endif // QT3_SUPPORT + + +/*! + Destroys this box layout. + + The layout's widgets aren't destroyed. +*/ +QBoxLayout::~QBoxLayout() +{ + Q_D(QBoxLayout); + d->deleteAll(); // must do it before QObject deletes children, so can't be in ~QBoxLayoutPrivate +} + +/*! + Reimplements QLayout::spacing(). If the spacing property is + valid, that value is returned. Otherwise, a value for the spacing + property is computed and returned. Since layout spacing in a widget + is style dependent, if the parent is a widget, it queries the style + for the (horizontal or vertical) spacing of the layout. Otherwise, + the parent is a layout, and it queries the parent layout for the + spacing(). + + \sa QLayout::spacing(), setSpacing() + */ +int QBoxLayout::spacing() const +{ + Q_D(const QBoxLayout); + if (d->spacing >=0) { + return d->spacing; + } else { + return qSmartSpacing(this, d->dir == LeftToRight || d->dir == RightToLeft + ? QStyle::PM_LayoutHorizontalSpacing + : QStyle::PM_LayoutVerticalSpacing); + } +} + +/*! + Reimplements QLayout::setSpacing(). Sets the spacing + property to \a spacing. + + \sa QLayout::setSpacing(), spacing() + */ +void QBoxLayout::setSpacing(int spacing) +{ + Q_D(QBoxLayout); + d->spacing = spacing; + invalidate(); +} + +/*! + \reimp +*/ +QSize QBoxLayout::sizeHint() const +{ + Q_D(const QBoxLayout); + if (d->dirty) + const_cast(this)->d_func()->setupGeom(); + return d->sizeHint; +} + +/*! + \reimp +*/ +QSize QBoxLayout::minimumSize() const +{ + Q_D(const QBoxLayout); + if (d->dirty) + const_cast(this)->d_func()->setupGeom(); + return d->minSize; +} + +/*! + \reimp +*/ +QSize QBoxLayout::maximumSize() const +{ + Q_D(const QBoxLayout); + if (d->dirty) + const_cast(this)->d_func()->setupGeom(); + + QSize s = d->maxSize.boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX)); + + if (alignment() & Qt::AlignHorizontal_Mask) + s.setWidth(QLAYOUTSIZE_MAX); + if (alignment() & Qt::AlignVertical_Mask) + s.setHeight(QLAYOUTSIZE_MAX); + return s; +} + +/*! + \reimp +*/ +bool QBoxLayout::hasHeightForWidth() const +{ + Q_D(const QBoxLayout); + if (d->dirty) + const_cast(this)->d_func()->setupGeom(); + return d->hasHfw; +} + +/*! + \reimp +*/ +int QBoxLayout::heightForWidth(int w) const +{ + Q_D(const QBoxLayout); + if (!hasHeightForWidth()) + return -1; + + int left, top, right, bottom; + d->effectiveMargins(&left, &top, &right, &bottom); + + w -= left + right; + if (w != d->hfwWidth) + const_cast(this)->d_func()->calcHfw(w); + + return d->hfwHeight + top + bottom; +} + +/*! + \reimp +*/ +int QBoxLayout::minimumHeightForWidth(int w) const +{ + Q_D(const QBoxLayout); + (void) heightForWidth(w); + int top, bottom; + d->effectiveMargins(0, &top, 0, &bottom); + return d->hasHfw ? (d->hfwMinHeight + top + bottom) : -1; +} + +/*! + Resets cached information. +*/ +void QBoxLayout::invalidate() +{ + Q_D(QBoxLayout); + d->setDirty(); + QLayout::invalidate(); +} + +/*! + \reimp +*/ +int QBoxLayout::count() const +{ + Q_D(const QBoxLayout); + return d->list.count(); +} + +/*! + \reimp +*/ +QLayoutItem *QBoxLayout::itemAt(int index) const +{ + Q_D(const QBoxLayout); + return index >= 0 && index < d->list.count() ? d->list.at(index)->item : 0; +} + +/*! + \reimp +*/ +QLayoutItem *QBoxLayout::takeAt(int index) +{ + Q_D(QBoxLayout); + if (index < 0 || index >= d->list.count()) + return 0; + QBoxLayoutItem *b = d->list.takeAt(index); + QLayoutItem *item = b->item; + b->item = 0; + delete b; + + invalidate(); + return item; +} + + +/*! + \reimp +*/ +Qt::Orientations QBoxLayout::expandingDirections() const +{ + Q_D(const QBoxLayout); + if (d->dirty) + const_cast(this)->d_func()->setupGeom(); + return d->expanding; +} + +/*! + \reimp +*/ +void QBoxLayout::setGeometry(const QRect &r) +{ + Q_D(QBoxLayout); + if (d->dirty || r != geometry()) { + QRect oldRect = geometry(); + QLayout::setGeometry(r); + if (d->dirty) + d->setupGeom(); + QRect cr = alignment() ? alignmentRect(r) : r; + + int left, top, right, bottom; + d->effectiveMargins(&left, &top, &right, &bottom); + QRect s(cr.x() + left, cr.y() + top, + cr.width() - (left + right), + cr.height() - (top + bottom)); + + QVector a = d->geomArray; + int pos = horz(d->dir) ? s.x() : s.y(); + int space = horz(d->dir) ? s.width() : s.height(); + int n = a.count(); + if (d->hasHfw && !horz(d->dir)) { + for (int i = 0; i < n; i++) { + QBoxLayoutItem *box = d->list.at(i); + if (box->item->hasHeightForWidth()) { + int width = qBound(box->item->minimumSize().width(), s.width(), box->item->maximumSize().width()); + a[i].sizeHint = a[i].minimumSize = + box->item->heightForWidth(width); + } + } + } + + Direction visualDir = d->dir; + QWidget *parent = parentWidget(); + if (parent && parent->isRightToLeft()) { + if (d->dir == LeftToRight) + visualDir = RightToLeft; + else if (d->dir == RightToLeft) + visualDir = LeftToRight; + } + + qGeomCalc(a, 0, n, pos, space); + + bool reverse = (horz(visualDir) + ? ((r.right() > oldRect.right()) != (visualDir == RightToLeft)) + : r.bottom() > oldRect.bottom()); + for (int j = 0; j < n; j++) { + int i = reverse ? n-j-1 : j; + QBoxLayoutItem *box = d->list.at(i); + + switch (visualDir) { + case LeftToRight: + box->item->setGeometry(QRect(a.at(i).pos, s.y(), a.at(i).size, s.height())); + break; + case RightToLeft: + box->item->setGeometry(QRect(s.left() + s.right() - a.at(i).pos - a.at(i).size + 1, + s.y(), a.at(i).size, s.height())); + break; + case TopToBottom: + box->item->setGeometry(QRect(s.x(), a.at(i).pos, s.width(), a.at(i).size)); + break; + case BottomToTop: + box->item->setGeometry(QRect(s.x(), + s.top() + s.bottom() - a.at(i).pos - a.at(i).size + 1, + s.width(), a.at(i).size)); + } + } + } +} + +/*! + \reimp +*/ +void QBoxLayout::addItem(QLayoutItem *item) +{ + Q_D(QBoxLayout); + QBoxLayoutItem *it = new QBoxLayoutItem(item); + d->list.append(it); + invalidate(); +} + +/*! + Inserts \a item into this box layout at position \a index. If \a + index is negative, the item is added at the end. + + \sa addItem(), insertWidget(), insertLayout(), insertStretch(), + insertSpacing() +*/ +void QBoxLayout::insertItem(int index, QLayoutItem *item) +{ + Q_D(QBoxLayout); + if (index < 0) // append + index = d->list.count(); + + QBoxLayoutItem *it = new QBoxLayoutItem(item); + d->list.insert(index, it); + invalidate(); +} + +/*! + Inserts a non-stretchable space (a QSpacerItem) at position \a index, with + size \a size. If \a index is negative the space is added at the end. + + The box layout has default margin and spacing. This function adds + additional space. + + \sa addSpacing(), insertItem(), QSpacerItem +*/ +void QBoxLayout::insertSpacing(int index, int size) +{ + Q_D(QBoxLayout); + if (index < 0) // append + index = d->list.count(); + + QLayoutItem *b; + if (horz(d->dir)) + b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum); + else + b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Minimum, QSizePolicy::Fixed); + + QT_TRY { + QBoxLayoutItem *it = new QBoxLayoutItem(b); + it->magic = true; + d->list.insert(index, it); + + } QT_CATCH(...) { + delete b; + QT_RETHROW; + } + invalidate(); +} + +/*! + Inserts a stretchable space (a QSpacerItem) at position \a + index, with zero minimum size and stretch factor \a stretch. If \a + index is negative the space is added at the end. + + \sa addStretch(), insertItem(), QSpacerItem +*/ +void QBoxLayout::insertStretch(int index, int stretch) +{ + Q_D(QBoxLayout); + if (index < 0) // append + index = d->list.count(); + + QLayoutItem *b; + if (horz(d->dir)) + b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + else + b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + + QBoxLayoutItem *it = new QBoxLayoutItem(b, stretch); + it->magic = true; + d->list.insert(index, it); + invalidate(); +} + +/*! + \since 4.4 + + Inserts \a spacerItem at position \a index, with zero minimum + size and stretch factor. If \a index is negative the + space is added at the end. + + \sa addSpacerItem(), insertStretch(), insertSpacing() +*/ +void QBoxLayout::insertSpacerItem(int index, QSpacerItem *spacerItem) +{ + Q_D(QBoxLayout); + if (index < 0) // append + index = d->list.count(); + + QBoxLayoutItem *it = new QBoxLayoutItem(spacerItem); + it->magic = true; + d->list.insert(index, it); + invalidate(); +} + +/*! + Inserts \a layout at position \a index, with stretch factor \a + stretch. If \a index is negative, the layout is added at the end. + + \a layout becomes a child of the box layout. + + \sa addLayout(), insertItem() +*/ +void QBoxLayout::insertLayout(int index, QLayout *layout, int stretch) +{ + Q_D(QBoxLayout); + addChildLayout(layout); + if (index < 0) // append + index = d->list.count(); + QBoxLayoutItem *it = new QBoxLayoutItem(layout, stretch); + d->list.insert(index, it); + invalidate(); +} + +/*! + Inserts \a widget at position \a index, with stretch factor \a + stretch and alignment \a alignment. If \a index is negative, the + widget is added at the end. + + The stretch factor applies only in the \l{direction()}{direction} + of the QBoxLayout, and is relative to the other boxes and widgets + in this QBoxLayout. Widgets and boxes with higher stretch factors + grow more. + + If the stretch factor is 0 and nothing else in the QBoxLayout has + a stretch factor greater than zero, the space is distributed + according to the QWidget:sizePolicy() of each widget that's + involved. + + The alignment is specified by \a alignment. The default alignment + is 0, which means that the widget fills the entire cell. + + \sa addWidget(), insertItem() +*/ +void QBoxLayout::insertWidget(int index, QWidget *widget, int stretch, + Qt::Alignment alignment) +{ + Q_D(QBoxLayout); + if (!checkWidget(this, widget)) + return; + addChildWidget(widget); + if (index < 0) // append + index = d->list.count(); + QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget); + b->setAlignment(alignment); + + QBoxLayoutItem *it; + QT_TRY{ + it = new QBoxLayoutItem(b, stretch); + } QT_CATCH(...) { + delete b; + QT_RETHROW; + } + + QT_TRY{ + d->list.insert(index, it); + } QT_CATCH(...) { + delete it; + QT_RETHROW; + } + invalidate(); +} + +/*! + Adds a non-stretchable space (a QSpacerItem) with size \a size + to the end of this box layout. QBoxLayout provides default margin + and spacing. This function adds additional space. + + \sa insertSpacing(), addItem(), QSpacerItem +*/ +void QBoxLayout::addSpacing(int size) +{ + insertSpacing(-1, size); +} + +/*! + Adds a stretchable space (a QSpacerItem) with zero minimum + size and stretch factor \a stretch to the end of this box layout. + + \sa insertStretch(), addItem(), QSpacerItem +*/ +void QBoxLayout::addStretch(int stretch) +{ + insertStretch(-1, stretch); +} + +/*! + \since 4.4 + + Adds \a spacerItem to the end of this box layout. + + \sa addSpacing(), addStretch() +*/ +void QBoxLayout::addSpacerItem(QSpacerItem *spacerItem) +{ + insertSpacerItem(-1, spacerItem); +} + +/*! + Adds \a widget to the end of this box layout, with a stretch + factor of \a stretch and alignment \a alignment. + + The stretch factor applies only in the \l{direction()}{direction} + of the QBoxLayout, and is relative to the other boxes and widgets + in this QBoxLayout. Widgets and boxes with higher stretch factors + grow more. + + If the stretch factor is 0 and nothing else in the QBoxLayout has + a stretch factor greater than zero, the space is distributed + according to the QWidget:sizePolicy() of each widget that's + involved. + + The alignment is specified by \a alignment. The default + alignment is 0, which means that the widget fills the entire cell. + + \sa insertWidget(), addItem(), addLayout(), addStretch(), + addSpacing(), addStrut() +*/ +void QBoxLayout::addWidget(QWidget *widget, int stretch, Qt::Alignment alignment) +{ + insertWidget(-1, widget, stretch, alignment); +} + +/*! + Adds \a layout to the end of the box, with serial stretch factor + \a stretch. + + \sa insertLayout(), addItem(), addWidget() +*/ +void QBoxLayout::addLayout(QLayout *layout, int stretch) +{ + insertLayout(-1, layout, stretch); +} + +/*! + Limits the perpendicular dimension of the box (e.g. height if the + box is \l LeftToRight) to a minimum of \a size. Other constraints + may increase the limit. + + \sa addItem() +*/ +void QBoxLayout::addStrut(int size) +{ + Q_D(QBoxLayout); + QLayoutItem *b; + if (horz(d->dir)) + b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Fixed, QSizePolicy::Minimum); + else + b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Minimum, QSizePolicy::Fixed); + + QBoxLayoutItem *it = new QBoxLayoutItem(b); + it->magic = true; + d->list.append(it); + invalidate(); +} + +/*! + \fn int QBoxLayout::findWidget(QWidget *widget) + + Use indexOf(\a widget) instead. +*/ + +/*! + Sets the stretch factor for \a widget to \a stretch and returns + true if \a widget is found in this layout (not including child + layouts); otherwise returns false. + + \sa setAlignment() +*/ +bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch) +{ + Q_D(QBoxLayout); + if (!widget) + return false; + for (int i = 0; i < d->list.size(); ++i) { + QBoxLayoutItem *box = d->list.at(i); + if (box->item->widget() == widget) { + box->stretch = stretch; + invalidate(); + return true; + } + } + return false; +} + +/*! + \overload + + Sets the stretch factor for the layout \a layout to \a stretch and + returns true if \a layout is found in this layout (not including + child layouts); otherwise returns false. +*/ +bool QBoxLayout::setStretchFactor(QLayout *layout, int stretch) +{ + Q_D(QBoxLayout); + for (int i = 0; i < d->list.size(); ++i) { + QBoxLayoutItem *box = d->list.at(i); + if (box->item->layout() == layout) { + if (box->stretch != stretch) { + box->stretch = stretch; + invalidate(); + } + return true; + } + } + return false; +} + +/*! + Sets the stretch factor at position \a index. to \a stretch. + + \since 4.5 +*/ + +void QBoxLayout::setStretch(int index, int stretch) +{ + Q_D(QBoxLayout); + if (index >= 0 && index < d->list.size()) { + QBoxLayoutItem *box = d->list.at(index); + if (box->stretch != stretch) { + box->stretch = stretch; + invalidate(); + } + } +} + +/*! + Returns the stretch factor at position \a index. + + \since 4.5 +*/ + +int QBoxLayout::stretch(int index) const +{ + Q_D(const QBoxLayout); + if (index >= 0 && index < d->list.size()) + return d->list.at(index)->stretch; + return -1; +} + +/*! + Sets the direction of this layout to \a direction. +*/ +void QBoxLayout::setDirection(Direction direction) +{ + Q_D(QBoxLayout); + if (d->dir == direction) + return; + if (horz(d->dir) != horz(direction)) { + //swap around the spacers (the "magic" bits) + //#### a bit yucky, knows too much. + //#### probably best to add access functions to spacerItem + //#### or even a QSpacerItem::flip() + for (int i = 0; i < d->list.size(); ++i) { + QBoxLayoutItem *box = d->list.at(i); + if (box->magic) { + QSpacerItem *sp = box->item->spacerItem(); + if (sp) { + if (sp->expandingDirections() == Qt::Orientations(0) /*No Direction*/) { + //spacing or strut + QSize s = sp->sizeHint(); + sp->changeSize(s.height(), s.width(), + horz(direction) ? QSizePolicy::Fixed:QSizePolicy::Minimum, + horz(direction) ? QSizePolicy::Minimum:QSizePolicy::Fixed); + + } else { + //stretch + if (horz(direction)) + sp->changeSize(0, 0, QSizePolicy::Expanding, + QSizePolicy::Minimum); + else + sp->changeSize(0, 0, QSizePolicy::Minimum, + QSizePolicy::Expanding); + } + } + } + } + } + d->dir = direction; + invalidate(); +} + +/*! + \fn QBoxLayout::Direction QBoxLayout::direction() const + + Returns the direction of the box. addWidget() and addSpacing() + work in this direction; the stretch stretches in this direction. + + \sa QBoxLayout::Direction addWidget() addSpacing() +*/ + +QBoxLayout::Direction QBoxLayout::direction() const +{ + Q_D(const QBoxLayout); + return d->dir; +} + +/*! + \class QHBoxLayout + \brief The QHBoxLayout class lines up widgets horizontally. + + \ingroup geomanagement + + This class is used to construct horizontal box layout objects. See + QBoxLayout for details. + + The simplest use of the class is like this: + + \snippet doc/src/snippets/layouts/layouts.cpp 0 + \snippet doc/src/snippets/layouts/layouts.cpp 1 + \snippet doc/src/snippets/layouts/layouts.cpp 2 + \codeline + \snippet doc/src/snippets/layouts/layouts.cpp 3 + \snippet doc/src/snippets/layouts/layouts.cpp 4 + \snippet doc/src/snippets/layouts/layouts.cpp 5 + + First, we create the widgets we want in the layout. Then, we + create the QHBoxLayout object and add the widgets into the + layout. Finally, we call QWidget::setLayout() to install the + QHBoxLayout object onto the widget. At that point, the widgets in + the layout are reparented to have \c window as their parent. + + \image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets + + \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} +*/ + + +/*! + Constructs a new top-level horizontal box with + parent \a parent. +*/ +QHBoxLayout::QHBoxLayout(QWidget *parent) + : QBoxLayout(LeftToRight, parent) +{ +} + +/*! + Constructs a new horizontal box. You must add + it to another layout. +*/ +QHBoxLayout::QHBoxLayout() + : QBoxLayout(LeftToRight) +{ +} + + + +#ifdef QT3_SUPPORT +/*! + Constructs a new top-level horizontal box called \a name, with + parent \a parent. + + The \a margin is the number of pixels between the edge of the + widget and its managed children. The \a spacing is the default + number of pixels between neighboring children. If \a spacing is -1 + the value of \a margin is used for \a spacing. +*/ +QHBoxLayout::QHBoxLayout(QWidget *parent, int margin, + int spacing, const char *name) + : QBoxLayout(LeftToRight, parent) +{ + setMargin(margin); + setSpacing(spacing<0 ? margin : spacing); + setObjectName(QString::fromAscii(name)); +} + +/*! + Constructs a new horizontal box called name \a name and adds it to + \a parentLayout. + + The \a spacing is the default number of pixels between neighboring + children. If \a spacing is -1, this QHBoxLayout will inherit its + parent's spacing(). +*/ +QHBoxLayout::QHBoxLayout(QLayout *parentLayout, int spacing, + const char *name) + : QBoxLayout(LeftToRight) +{ + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); + if (parentLayout) { + setParent(parentLayout); + parentLayout->addItem(this); + } +} + +/*! + Constructs a new horizontal box called name \a name. You must add + it to another layout. + + The \a spacing is the default number of pixels between neighboring + children. If \a spacing is -1, this QHBoxLayout will inherit its + parent's spacing(). +*/ +QHBoxLayout::QHBoxLayout(int spacing, const char *name) + : QBoxLayout(LeftToRight) +{ + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); +} +#endif + + +/*! + Destroys this box layout. + + The layout's widgets aren't destroyed. +*/ +QHBoxLayout::~QHBoxLayout() +{ +} + +/*! + \class QVBoxLayout + \brief The QVBoxLayout class lines up widgets vertically. + + \ingroup geomanagement + + This class is used to construct vertical box layout objects. See + QBoxLayout for details. + + The simplest use of the class is like this: + + \snippet doc/src/snippets/layouts/layouts.cpp 6 + \snippet doc/src/snippets/layouts/layouts.cpp 7 + \snippet doc/src/snippets/layouts/layouts.cpp 8 + \codeline + \snippet doc/src/snippets/layouts/layouts.cpp 9 + \snippet doc/src/snippets/layouts/layouts.cpp 10 + \snippet doc/src/snippets/layouts/layouts.cpp 11 + + First, we create the widgets we want in the layout. Then, we + create the QVBoxLayout object and add the widgets into the + layout. Finally, we call QWidget::setLayout() to install the + QVBoxLayout object onto the widget. At that point, the widgets in + the layout are reparented to have \c window as their parent. + + \image qvboxlayout-with-5-children.png Horizontal box layout with five child widgets + + \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} +*/ + +/*! + Constructs a new top-level vertical box with + parent \a parent. +*/ +QVBoxLayout::QVBoxLayout(QWidget *parent) + : QBoxLayout(TopToBottom, parent) +{ +} + +/*! + Constructs a new vertical box. You must add + it to another layout. + +*/ +QVBoxLayout::QVBoxLayout() + : QBoxLayout(TopToBottom) +{ +} + +#ifdef QT3_SUPPORT +/*! + Constructs a new top-level vertical box called \a name, with + parent \a parent. + + The \a margin is the number of pixels between the edge of the + widget and its managed children. The \a spacing is the default + number of pixels between neighboring children. If \a spacing is -1 + the value of \a margin is used for \a spacing. +*/ +QVBoxLayout::QVBoxLayout(QWidget *parent, int margin, int spacing, + const char *name) + : QBoxLayout(TopToBottom, parent) +{ + setMargin(margin); + setSpacing(spacing<0 ? margin : spacing); + setObjectName(QString::fromAscii(name)); +} + +/*! + Constructs a new vertical box called name \a name and adds it to + \a parentLayout. + + The \a spacing is the default number of pixels between neighboring + children. If \a spacing is -1, this QVBoxLayout will inherit its + parent's spacing(). +*/ +QVBoxLayout::QVBoxLayout(QLayout *parentLayout, int spacing, + const char *name) + : QBoxLayout(TopToBottom) +{ + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); + if (parentLayout) { + setParent(parentLayout); + parentLayout->addItem(this); + } +} + +/*! + Constructs a new vertical box called name \a name. You must add + it to another layout. + + The \a spacing is the default number of pixels between neighboring + children. If \a spacing is -1, this QVBoxLayout will inherit its + parent's spacing(). +*/ +QVBoxLayout::QVBoxLayout(int spacing, const char *name) + : QBoxLayout(TopToBottom) +{ + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); +} + + +#endif + +/*! + Destroys this box layout. + + The layout's widgets aren't destroyed. +*/ +QVBoxLayout::~QVBoxLayout() +{ +} + +/*! + \fn QWidget *QLayout::mainWidget() const + + Use parentWidget() instead. +*/ + +/*! + \fn void QLayout::remove(QWidget *widget) + + Use removeWidget(\a widget) instead. +*/ + +/*! + \fn void QLayout::add(QWidget *widget) + + Use addWidget(\a widget) instead. +*/ + +/*! + \fn QLayoutIterator QLayout::iterator() + + Use a QLayoutIterator() constructor instead. +*/ + +/*! + \fn int QLayout::defaultBorder() const + + Use spacing() instead. +*/ + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qboxlayout.h b/src/widgets/kernel/qboxlayout.h new file mode 100644 index 0000000000..66ce23a9f5 --- /dev/null +++ b/src/widgets/kernel/qboxlayout.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBOXLAYOUT_H +#define QBOXLAYOUT_H + +#include +#ifdef QT_INCLUDE_COMPAT +#include +#endif + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QBoxLayoutPrivate; + +class Q_GUI_EXPORT QBoxLayout : public QLayout +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QBoxLayout) +public: + enum Direction { LeftToRight, RightToLeft, TopToBottom, BottomToTop, + Down = TopToBottom, Up = BottomToTop }; + + explicit QBoxLayout(Direction, QWidget *parent = 0); + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QBoxLayout(QWidget *parent, Direction, int border = 0, int spacing = -1, + const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QBoxLayout(QLayout *parentLayout, Direction, int spacing = -1, + const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QBoxLayout(Direction, int spacing, const char *name = 0); +#endif + ~QBoxLayout(); + + Direction direction() const; + void setDirection(Direction); + + void addSpacing(int size); + void addStretch(int stretch = 0); + void addSpacerItem(QSpacerItem *spacerItem); + void addWidget(QWidget *, int stretch = 0, Qt::Alignment alignment = 0); + void addLayout(QLayout *layout, int stretch = 0); + void addStrut(int); + void addItem(QLayoutItem *); + + void insertSpacing(int index, int size); + void insertStretch(int index, int stretch = 0); + void insertSpacerItem(int index, QSpacerItem *spacerItem); + void insertWidget(int index, QWidget *widget, int stretch = 0, Qt::Alignment alignment = 0); + void insertLayout(int index, QLayout *layout, int stretch = 0); + + int spacing() const; + void setSpacing(int spacing); + + bool setStretchFactor(QWidget *w, int stretch); + bool setStretchFactor(QLayout *l, int stretch); + void setStretch(int index, int stretch); + int stretch(int index) const; + + QSize sizeHint() const; + QSize minimumSize() const; + QSize maximumSize() const; + + bool hasHeightForWidth() const; + int heightForWidth(int) const; + int minimumHeightForWidth(int) const; + + Qt::Orientations expandingDirections() const; + void invalidate(); + QLayoutItem *itemAt(int) const; + QLayoutItem *takeAt(int); + int count() const; + void setGeometry(const QRect&); +#ifdef QT3_SUPPORT + inline QT3_SUPPORT int findWidget(QWidget* w) {return indexOf(w);} +#endif +protected: + // ### Qt 5: make public + void insertItem(int index, QLayoutItem *); + +private: + Q_DISABLE_COPY(QBoxLayout) +}; + +class Q_GUI_EXPORT QHBoxLayout : public QBoxLayout +{ + Q_OBJECT +public: + QHBoxLayout(); + explicit QHBoxLayout(QWidget *parent); + ~QHBoxLayout(); + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QHBoxLayout(QWidget *parent, int border, + int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QHBoxLayout(QLayout *parentLayout, + int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QHBoxLayout(int spacing, const char *name = 0); +#endif + +private: + Q_DISABLE_COPY(QHBoxLayout) +}; + +class Q_GUI_EXPORT QVBoxLayout : public QBoxLayout +{ + Q_OBJECT +public: + QVBoxLayout(); + explicit QVBoxLayout(QWidget *parent); + ~QVBoxLayout(); + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QVBoxLayout(QWidget *parent, int border, + int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QVBoxLayout(QLayout *parentLayout, + int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QVBoxLayout(int spacing, const char *name = 0); +#endif + +private: + Q_DISABLE_COPY(QVBoxLayout) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QBOXLAYOUT_H diff --git a/src/widgets/kernel/qdesktopwidget.cpp b/src/widgets/kernel/qdesktopwidget.cpp new file mode 100644 index 0000000000..6e1414dc5d --- /dev/null +++ b/src/widgets/kernel/qdesktopwidget.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" +#include "qdesktopwidget.h" +#include "qwidget_p.h" + +QT_BEGIN_NAMESPACE + +const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const +{ + if (!widget) { + qWarning("QDesktopWidget::screenGeometry(): Attempt " + "to get the screen geometry of a null widget"); + return QRect(); + } + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return screenGeometry(screenNumber(widget)); + else return rect; +} + +const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const +{ + if (!widget) { + qWarning("QDesktopWidget::availableGeometry(): Attempt " + "to get the available geometry of a null widget"); + return QRect(); + } + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return availableGeometry(screenNumber(widget)); + else + return rect; +} + +QT_END_NAMESPACE + diff --git a/src/widgets/kernel/qdesktopwidget.h b/src/widgets/kernel/qdesktopwidget.h new file mode 100644 index 0000000000..deb896029a --- /dev/null +++ b/src/widgets/kernel/qdesktopwidget.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESKTOPWIDGET_H +#define QDESKTOPWIDGET_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QApplication; +class QDesktopWidgetPrivate; + +class Q_GUI_EXPORT QDesktopWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(bool virtualDesktop READ isVirtualDesktop) + Q_PROPERTY(int screenCount READ screenCount NOTIFY screenCountChanged) + Q_PROPERTY(int primaryScreen READ primaryScreen) +public: + QDesktopWidget(); + ~QDesktopWidget(); + + bool isVirtualDesktop() const; + + int numScreens() const; + int screenCount() const; + int primaryScreen() const; + + int screenNumber(const QWidget *widget = 0) const; + int screenNumber(const QPoint &) const; + + QWidget *screen(int screen = -1); + + const QRect screenGeometry(int screen = -1) const; + const QRect screenGeometry(const QWidget *widget) const; + const QRect screenGeometry(const QPoint &point) const + { return screenGeometry(screenNumber(point)); } + + const QRect availableGeometry(int screen = -1) const; + const QRect availableGeometry(const QWidget *widget) const; + const QRect availableGeometry(const QPoint &point) const + { return availableGeometry(screenNumber(point)); } + +Q_SIGNALS: + void resized(int); + void workAreaResized(int); + void screenCountChanged(int); + +protected: + void resizeEvent(QResizeEvent *e); + +private: + Q_DISABLE_COPY(QDesktopWidget) + Q_DECLARE_PRIVATE(QDesktopWidget) + + friend class QApplication; + friend class QApplicationPrivate; +}; + +inline int QDesktopWidget::screenCount() const +{ return numScreens(); } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDESKTOPWIDGET_H diff --git a/src/widgets/kernel/qdesktopwidget.qdoc b/src/widgets/kernel/qdesktopwidget.qdoc new file mode 100644 index 0000000000..a79a098d74 --- /dev/null +++ b/src/widgets/kernel/qdesktopwidget.qdoc @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesktopWidget + \brief The QDesktopWidget class provides access to screen information on multi-head systems. + + \ingroup advanced + \ingroup desktop + + Systems with more than one graphics card and monitor can manage the + physical screen space available either as multiple desktops, or as a + large virtual desktop. + + This class provides information about the user's desktop, such as its + total size, number of screens, the geometry of each screen, and whether + they are configured as separate desktops or a single virtual desktop. + + Widgets provided by Qt use this class to place tooltips, menus and + dialog boxes on the correct screen for their parent or application + widgets. Applications can use this class to obtain information that + can be used to save window positions, or to place child widgets and + dialogs on one particular screen. + + \section1 Obtaining a Desktop Widget + + The QApplication::desktop() function is used to get an instance of + QDesktopWidget. + + The widget's screenGeometry() function provides information about the + geometry of the available screens with. The number of screens + available is returned by screenCount, and the screenCountChanged() + signal is emitted when screens are added or removed. + The screen number that a particular point or widget is located in + is returned by screenNumber(). + + \section1 Screen Geometry + + To obtain the dimensions of a particular screen, call the screenGeometry() + function. On some desktop environments, not all of the screen is + available for applications to use; for example, an application dock or + menu bar may take up some space. Use the availableGeometry() function + to obtain the available area for applications. + + QDesktopWidget also inherits the QWidget properties, width() and + height(), which specify the size of the desktop. However, for + desktops with multiple screens, the size of the desktop is the union + of all the screen sizes, so width() and height() should \e not be + used for computing the size of a widget to be placed on one of the + screens. + + On systems that are configured to use the available screens as a + single, large virtual desktop, the virtualDesktop property will be + set to true. In this case, the widget's size is usually the size of + the bounding rectangle of all the screens. + + \section1 Use of the Primary Screen + + For an application, the screen where the main widget resides is the + primary screen. This is stored in the primaryScreen property. + All windows opened in the context of the application should be + constrained to the boundaries of the primary screen; for example, + it would be inconvenient if a dialog box popped up on a different + screen, or split over two screens. + + \image qdesktopwidget.png Managing Multiple Screens + + In the illustration above, Application One's primary screen is + screen 0, and App Two's primary screen is screen 1. + + \sa QApplication, QApplication::desktop(), QX11Info::appRootWindow() +*/ + +/*! + \fn QDesktopWidget::QDesktopWidget() + + \internal + + Creates the desktop widget. + + If the system supports a virtual desktop, this widget will have + the size of the virtual desktop; otherwise this widget will have + the size of the primary screen. + + Instead of using QDesktopWidget directly, use QApplication::desktop(). +*/ + +/*! + \fn QDesktopWidget::~QDesktopWidget() + + \internal + + Destroys the desktop widget and frees any allocated resources. +*/ + +/*! + \fn int QDesktopWidget::numScreens() const + + Returns the number of available screens. + + \obsolete + + This function is deprecated. Use screenCount instead. + + \sa primaryScreen +*/ + +/*! + \fn QWidget *QDesktopWidget::screen(int screen) + + Returns a widget that represents the screen with index \a screen + (a value of -1 means the default screen). + + If the system uses a virtual desktop, the returned widget will + have the geometry of the entire virtual desktop; i.e., bounding + every \a screen. + + \sa primaryScreen, screenCount, virtualDesktop +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(int screen) const + + Returns the available geometry of the screen with index \a screen. What + is available will be subrect of screenGeometry() based on what the + platform decides is available (for example excludes the dock and menu bar + on Mac OS X, or the task bar on Windows). The default screen is used if + \a screen is -1. + + \sa screenNumber(), screenGeometry() +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const + \overload + + Returns the available geometry of the screen which contains \a widget. + + \sa screenGeometry() +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(const QPoint &p) const + \overload + + Returns the available geometry of the screen which contains \a p. + + \sa screenGeometry() +*/ + + +/*! + \fn const QRect QDesktopWidget::screenGeometry(int screen) const + + Returns the geometry of the screen with index \a screen. The default + screen is used if \a screen is -1. + + \sa screenNumber() +*/ + +/*! + \fn const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const + \overload + + Returns the geometry of the screen which contains \a widget. +*/ + +/*! + \fn const QRect QDesktopWidget::screenGeometry(const QPoint &p) const + \overload + + Returns the geometry of the screen which contains \a p. +*/ + + +/*! + \fn int QDesktopWidget::screenNumber(const QWidget *widget) const + + Returns the index of the screen that contains the largest + part of \a widget, or -1 if the widget not on a screen. + + \sa primaryScreen +*/ + +/*! + \fn int QDesktopWidget::screenNumber(const QPoint &point) const + + \overload + Returns the index of the screen that contains the \a point, or the + screen which is the shortest distance from the \a point. + + \sa primaryScreen +*/ + +/*! + \fn void QDesktopWidget::resizeEvent(QResizeEvent *event) + \reimp +*/ + +/*! + \fn void QDesktopWidget::resized(int screen) + + This signal is emitted when the size of \a screen changes. +*/ + +/*! + \fn void QDesktopWidget::workAreaResized(int screen) + + This signal is emitted when the work area available on \a screen changes. +*/ + +/*! + \property QDesktopWidget::screenCount + \brief the number of screens currently available on the system. + + \since 4.6 + + \sa screenCountChanged() +*/ + +/*! + \property QDesktopWidget::primaryScreen + \brief the index of the screen that is configured to be the primary screen + on the system. +*/ + +/*! + \property QDesktopWidget::virtualDesktop + + \brief if the system manages the available screens in a virtual desktop. + + For virtual desktops, screen() will always return the same widget. + The size of the virtual desktop is the size of this desktop + widget. +*/ + +/*! + \fn void QDesktopWidget::screenCountChanged(int newCount) + + \since 4.6 + + This signal is emitted when the number of screens changes to \a newCount. + + \sa screenCount +*/ diff --git a/src/widgets/kernel/qdesktopwidget_qpa.cpp b/src/widgets/kernel/qdesktopwidget_qpa.cpp new file mode 100644 index 0000000000..7b175dbe95 --- /dev/null +++ b/src/widgets/kernel/qdesktopwidget_qpa.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopwidget.h" +#include "private/qapplication_p.h" +#include +#include "private/qwidget_p.h" +#include "private/qdesktopwidget_qpa_p.h" +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +void QDesktopWidgetPrivate::updateScreenList() +{ + Q_Q(QDesktopWidget); + QList screenList = QGuiApplicationPrivate::platformIntegration()->screens(); + int targetLength = screenList.length(); + int currentLength = screens.length(); + + // Add or remove screen widgets as necessary + if(currentLength > targetLength) { + QDesktopScreenWidget *screen; + while (currentLength-- > targetLength) { + screen = screens.takeLast(); + delete screen; + } + } + else if (currentLength < targetLength) { + QDesktopScreenWidget *screen; + while (currentLength < targetLength) { + screen = new QDesktopScreenWidget(currentLength++); + screens.append(screen); + } + } + + QRegion virtualGeometry; + + // update the geometry of each screen widget + for (int i = 0; i < screens.length(); i++) { + QRect screenGeometry = screenList.at(i)->geometry(); + screens.at(i)->setGeometry(screenGeometry); + virtualGeometry += screenGeometry; + } + + q->setGeometry(virtualGeometry.boundingRect()); +} + +QDesktopWidget::QDesktopWidget() + : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) +{ + Q_D(QDesktopWidget); + setObjectName(QLatin1String("desktop")); + d->updateScreenList(); +} + +QDesktopWidget::~QDesktopWidget() +{ +} + +bool QDesktopWidget::isVirtualDesktop() const +{ + return QGuiApplicationPrivate::platformIntegration()->isVirtualDesktop(); +} + +int QDesktopWidget::primaryScreen() const +{ + return 0; +} + +int QDesktopWidget::numScreens() const +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + return qMax(pi->screens().size(), 1); +} + +QWidget *QDesktopWidget::screen(int screen) +{ + Q_D(QDesktopWidget); + if (screen < 0 || screen >= d->screens.length()) + return d->screens.at(0); + return d->screens.at(screen); +} + +const QRect QDesktopWidget::availableGeometry(int screenNo) const +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + QList screens = pi->screens(); + if (screenNo == -1) + screenNo = 0; + if (screenNo < 0 || screenNo >= screens.size()) + return QRect(); + else + return screens[screenNo]->availableGeometry(); +} + +const QRect QDesktopWidget::screenGeometry(int screenNo) const +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + QList screens = pi->screens(); + if (screenNo == -1) + screenNo = 0; + if (screenNo < 0 || screenNo >= screens.size()) + return QRect(); + else + return screens[screenNo]->geometry(); +} + +int QDesktopWidget::screenNumber(const QWidget *w) const +{ + if (!w) + return 0; + + QRect frame = w->frameGeometry(); + if (!w->isWindow()) + frame.moveTopLeft(w->mapToGlobal(QPoint(0, 0))); + const QPoint midpoint = (frame.topLeft() + frame.bottomRight()) / 2; + return screenNumber(midpoint); +} + +int QDesktopWidget::screenNumber(const QPoint &p) const +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + QList screens = pi->screens(); + + for (int i = 0; i < screens.size(); ++i) + if (screens[i]->geometry().contains(p)) + return i; + + return primaryScreen(); //even better would be closest screen +} + +void QDesktopWidget::resizeEvent(QResizeEvent *) +{ +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qdesktopwidget_qpa_p.h b/src/widgets/kernel/qdesktopwidget_qpa_p.h new file mode 100644 index 0000000000..d6ed686a3f --- /dev/null +++ b/src/widgets/kernel/qdesktopwidget_qpa_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESKTOPWIDGET_QPA_P_H +#define QDESKTOPWIDGET_QPA_P_H + +#include "QDesktopWidget" +#include "private/qwidget_p.h" + +class QDesktopScreenWidget : public QWidget { + Q_OBJECT +public: + QDesktopScreenWidget(int screenNumber = -1) + { + setWindowFlags(Qt::Desktop); + setVisible(false); + QTLWExtra *topData = d_func()->topData(); + topData->screenIndex = screenNumber; + } +}; + +class QDesktopWidgetPrivate : public QWidgetPrivate { + Q_DECLARE_PUBLIC(QDesktopWidget) + +public: + ~QDesktopWidgetPrivate() {foreach(QDesktopScreenWidget *s, screens) delete s; } + void updateScreenList(); + + QList screens; +}; + +#endif // QDESKTOPWIDGET_QPA_P_H diff --git a/src/widgets/kernel/qformlayout.cpp b/src/widgets/kernel/qformlayout.cpp new file mode 100644 index 0000000000..d098c01f0f --- /dev/null +++ b/src/widgets/kernel/qformlayout.cpp @@ -0,0 +1,2079 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qdebug.h" +#include "qformlayout.h" +#include "qlabel.h" +#include "qlayout_p.h" +#include "qlayoutengine_p.h" +#include "qrect.h" +#include "qvector.h" +#include "qwidget.h" + +QT_BEGIN_NAMESPACE + +namespace { +// Fixed column matrix, stores items as [i11, i12, i21, i22...], +// with FORTRAN-style index operator(r, c). +template +class FixedColumnMatrix { +public: + typedef QVector Storage; + + FixedColumnMatrix() { } + + void clear() { m_storage.clear(); } + + const T &operator()(int r, int c) const { return m_storage[r * NumColumns + c]; } + T &operator()(int r, int c) { return m_storage[r * NumColumns + c]; } + + int rowCount() const { return m_storage.size() / NumColumns; } + void addRow(const T &value); + void insertRow(int r, const T &value); + void removeRow(int r); + + bool find(const T &value, int *rowPtr, int *colPtr) const ; + int count(const T &value) const { return m_storage.count(value); } + + // Hmmpf.. Some things are faster that way. + const Storage &storage() const { return m_storage; } + + static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr); + +private: + Storage m_storage; +}; + +template +void FixedColumnMatrix::addRow(const T &value) +{ + for (int i = 0; i < NumColumns; ++i) + m_storage.append(value); +} + +template +void FixedColumnMatrix::insertRow(int r, const T &value) +{ + Q_TYPENAME Storage::iterator it = m_storage.begin(); + it += r * NumColumns; + m_storage.insert(it, NumColumns, value); +} + +template +void FixedColumnMatrix::removeRow(int r) +{ + m_storage.remove(r * NumColumns, NumColumns); +} + +template +bool FixedColumnMatrix::find(const T &value, int *rowPtr, int *colPtr) const +{ + const int idx = m_storage.indexOf(value); + if (idx == -1) + return false; + storageIndexToPosition(idx, rowPtr, colPtr); + return true; +} + +template +void FixedColumnMatrix::storageIndexToPosition(int idx, int *rowPtr, int *colPtr) +{ + *rowPtr = idx / NumColumns; + *colPtr = idx % NumColumns; +} +} // namespace + +// special values for unset fields; must not clash with values of FieldGrowthPolicy or +// RowWrapPolicy +const uint DefaultFieldGrowthPolicy = 255; +const uint DefaultRowWrapPolicy = 255; + +enum { ColumnCount = 2 }; + +// -- our data structure for our items +// This owns the QLayoutItem +struct QFormLayoutItem +{ + QFormLayoutItem(QLayoutItem* i) : item(i), fullRow(false), isHfw(false) { } + ~QFormLayoutItem() { delete item; } + + // Wrappers + QWidget *widget() const { return item->widget(); } + QLayout *layout() const { return item->layout(); } + + bool hasHeightForWidth() const { return item->hasHeightForWidth(); } + int heightForWidth(int width) const { return item->heightForWidth(width); } + int minimumHeightForWidth(int width) const { return item->minimumHeightForWidth(width); } + Qt::Orientations expandingDirections() const { return item->expandingDirections(); } + QSizePolicy::ControlTypes controlTypes() const { return item->controlTypes(); } + int vStretch() const { return widget() ? widget()->sizePolicy().verticalStretch() : 0; } + + void setGeometry(const QRect& r) { item->setGeometry(r); } + QRect geometry() const { return item->geometry(); } + + // For use with FixedColumnMatrix + bool operator==(const QFormLayoutItem& other) { return item == other.item; } + + QLayoutItem *item; + bool fullRow; + + // set by updateSizes + bool isHfw; + QSize minSize; + QSize sizeHint; + QSize maxSize; + + // also set by updateSizes + int sbsHSpace; // only used for side by side, for the field item only (not label) + int vSpace; // This is the spacing to the item in the row above + + // set by setupVerticalLayoutData + bool sideBySide; + int vLayoutIndex; + + // set by setupHorizontalLayoutData + int layoutPos; + int layoutWidth; +}; + +class QFormLayoutPrivate : public QLayoutPrivate +{ + Q_DECLARE_PUBLIC(QFormLayout) + +public: + typedef FixedColumnMatrix ItemMatrix; + + QFormLayoutPrivate(); + ~QFormLayoutPrivate() { } + + int insertRow(int row); + void insertRows(int row, int count); + void setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item); + void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout); + void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget); + + void arrangeWidgets(const QVector& layouts, QRect &rect); + + void updateSizes(); + + void setupVerticalLayoutData(int width); + void setupHorizontalLayoutData(int width); + + QStyle* getStyle() const; + + inline bool haveHfwCached(int width) const + { + return (hfw_width == width) || (width == sh_width && hfw_sh_height >= 0); + } + + void recalcHFW(int w); + void setupHfwLayoutData(); + + uint fieldGrowthPolicy : 8; + uint rowWrapPolicy : 8; + uint has_hfw : 2; + uint dirty : 2; // have we laid out yet? + uint sizesDirty : 2; // have we (not) gathered layout item sizes? + uint expandVertical : 1; // Do we expand vertically? + uint expandHorizontal : 1; // Do we expand horizonally? + Qt::Alignment labelAlignment; + Qt::Alignment formAlignment; + + ItemMatrix m_matrix; + QList m_things; + + int layoutWidth; // the last width that we called setupVerticalLayoutData on (for vLayouts) + + int hfw_width; // the last width we calculated HFW for + int hfw_height; // what that height was + int hfw_minheight; // what that minheight was + + int hfw_sh_height; // the hfw for sh_width + int hfw_sh_minheight; // the minhfw for sh_width + + int min_width; // the width that gets turned into minSize (from updateSizes) + int sh_width; // the width that gets turned into prefSize (from updateSizes) + int thresh_width; // the width that we start splitting label/field pairs at (from updateSizes) + QSize minSize; + QSize prefSize; + int formMaxWidth; + void calcSizeHints(); + + QVector vLayouts; // set by setupVerticalLayoutData; + int vLayoutCount; // Number of rows we calculated in setupVerticalLayoutData + int maxLabelWidth; // the label width we calculated in setupVerticalLayoutData + + QVector hfwLayouts; + + int hSpacing; + int vSpacing; +}; + +QFormLayoutPrivate::QFormLayoutPrivate() + : fieldGrowthPolicy(DefaultFieldGrowthPolicy), + rowWrapPolicy(DefaultRowWrapPolicy), has_hfw(false), dirty(true), sizesDirty(true), + expandVertical(0), expandHorizontal(0), labelAlignment(0), formAlignment(0), + layoutWidth(-1), hfw_width(-1), hfw_sh_height(-1), min_width(-1), + sh_width(-1), thresh_width(QLAYOUTSIZE_MAX), hSpacing(-1), vSpacing(-1) +{ +} + +static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection) +{ + if (layoutDirection == Qt::RightToLeft && alignment & Qt::AlignAbsolute) { + // swap left and right, and eliminate absolute flag + return Qt::Alignment((alignment & ~(Qt::AlignLeft | Qt::AlignRight | Qt::AlignAbsolute)) + | ((alignment & Qt::AlignRight) ? Qt::AlignLeft : 0) + | ((alignment & Qt::AlignLeft) ? Qt::AlignRight : 0)); + } else { + return alignment & ~Qt::AlignAbsolute; + } +} + +static int storageIndexFromLayoutItem(const QFormLayoutPrivate::ItemMatrix &m, + QFormLayoutItem *item) +{ + if (item) { + return m.storage().indexOf(item); + } else { + return -1; + } +} + +static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing, + QFormLayout::FieldGrowthPolicy fieldGrowthPolicy, + bool fullRow) +{ + item->minSize = item->item->minimumSize(); + item->sizeHint = item->item->sizeHint(); + item->maxSize = item->item->maximumSize(); + + if (!fullRow && (fieldGrowthPolicy == QFormLayout::FieldsStayAtSizeHint + || (fieldGrowthPolicy == QFormLayout::ExpandingFieldsGrow + && !(item->item->expandingDirections() & Qt::Horizontal)))) + item->maxSize.setWidth(item->sizeHint.width()); + + item->isHfw = item->item->hasHeightForWidth(); + item->vSpace = userVSpacing; +} + +/* + Iterate over all the controls and gather their size information + (min, sizeHint and max). Also work out what the spacing between + pairs of controls should be, and figure out the min and sizeHint + widths. +*/ +void QFormLayoutPrivate::updateSizes() +{ + Q_Q(QFormLayout); + + if (sizesDirty) { + QFormLayout::RowWrapPolicy wrapPolicy = q->rowWrapPolicy(); + bool wrapAllRows = (wrapPolicy == QFormLayout::WrapAllRows); + bool dontWrapRows = (wrapPolicy == QFormLayout::DontWrapRows); + int rr = m_matrix.rowCount(); + + has_hfw = false; + + // If any control can expand, so can this layout + // Wrapping doesn't affect expansion, though, just the minsize + bool expandH = false; + bool expandV = false; + + QFormLayoutItem *prevLbl = 0; + QFormLayoutItem *prevFld = 0; + + QWidget *parent = q->parentWidget(); + QStyle *style = parent ? parent->style() : 0; + + int userVSpacing = q->verticalSpacing(); + int userHSpacing = wrapAllRows ? 0 : q->horizontalSpacing(); + + int maxMinLblWidth = 0; + int maxMinFldWidth = 0; // field with label + int maxMinIfldWidth = 0; // independent field + + int maxShLblWidth = 0; + int maxShFldWidth = 0; + int maxShIfldWidth = 0; + + for (int i = 0; i < rr; ++i) { + QFormLayoutItem *label = m_matrix(i, 0); + QFormLayoutItem *field = m_matrix(i, 1); + + // Skip empty rows + if (!label && !field) + continue; + + if (label) { + updateFormLayoutItem(label, userVSpacing, q->fieldGrowthPolicy(), false); + if (label->isHfw) + has_hfw = true; + Qt::Orientations o = label->expandingDirections(); + + if (o & Qt::Vertical) + expandV = true; + if (o & Qt::Horizontal) + expandH = true; + } + if (field) { + updateFormLayoutItem(field, userVSpacing, q->fieldGrowthPolicy(), !label && field->fullRow); + field->sbsHSpace = (!label && field->fullRow) ? 0 : userHSpacing; + if (field->isHfw) + has_hfw = true; + + Qt::Orientations o = field->expandingDirections(); + + if (o & Qt::Vertical) + expandV = true; + if (o & Qt::Horizontal) + expandH = true; + } + + // See if we need to calculate default spacings + if ((userHSpacing < 0 || userVSpacing < 0) && style) { + QSizePolicy::ControlTypes lbltypes = + QSizePolicy::ControlTypes(label ? label->controlTypes() : QSizePolicy::DefaultType); + QSizePolicy::ControlTypes fldtypes = + QSizePolicy::ControlTypes(field ? field->controlTypes() : QSizePolicy::DefaultType); + + // VSpacing + if (userVSpacing < 0) { + if (wrapAllRows) { + // label spacing is to a previous item + QFormLayoutItem *lbltop = prevFld ? prevFld : prevLbl; + // field spacing is to the label (or a previous item) + QFormLayoutItem *fldtop = label ? label : lbltop; + QSizePolicy::ControlTypes lbltoptypes = + QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType); + QSizePolicy::ControlTypes fldtoptypes = + QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType); + if (label && lbltop) + label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent); + if (field && fldtop) + field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent); + } else { + // Side by side.. we have to also consider the spacings to empty cells, which can strangely be more than + // non empty cells.. + QFormLayoutItem *lbltop = prevLbl ? prevLbl : prevFld; + QFormLayoutItem *fldtop = prevFld; + QSizePolicy::ControlTypes lbltoptypes = + QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType); + QSizePolicy::ControlTypes fldtoptypes = + QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType); + + // To be compatible to QGridLayout, we have to compare solitary labels & fields with both predecessors + if (label) { + if (!field) { + int lblspacing = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent); + int fldspacing = style->combinedLayoutSpacing(fldtoptypes, lbltypes, Qt::Vertical, 0, parent); + label->vSpace = qMax(lblspacing, fldspacing); + } else + label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent); + } + + if (field) { + // check spacing against both the previous label and field + if (!label) { + int lblspacing = style->combinedLayoutSpacing(lbltoptypes, fldtypes, Qt::Vertical, 0, parent); + int fldspacing = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent); + field->vSpace = qMax(lblspacing, fldspacing); + } else + field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent); + } + } + } + + // HSpacing + // hard-coded the left and right control types so that all the rows have the same + // inter-column spacing (otherwise the right column isn't always left aligned) + if (userHSpacing < 0 && !wrapAllRows && (label || !field->fullRow) && field) + field->sbsHSpace = style->combinedLayoutSpacing(QSizePolicy::Label, QSizePolicy::LineEdit, Qt::Horizontal, 0, parent); + } + + // Now update our min/sizehint widths + // We choose to put the spacing in the field side in sbs, so + // the right edge of the labels will align, but fields may + // be a little ragged.. since different controls may have + // different appearances, a slight raggedness in the left + // edges of fields can be tolerated. + // (Note - field->sbsHSpace is 0 for WrapAllRows mode) + if (label) { + maxMinLblWidth = qMax(maxMinLblWidth, label->minSize.width()); + maxShLblWidth = qMax(maxShLblWidth, label->sizeHint.width()); + if (field) { + maxMinFldWidth = qMax(maxMinFldWidth, field->minSize.width() + field->sbsHSpace); + maxShFldWidth = qMax(maxShFldWidth, field->sizeHint.width() + field->sbsHSpace); + } + } else if (field) { + maxMinIfldWidth = qMax(maxMinIfldWidth, field->minSize.width()); + maxShIfldWidth = qMax(maxShIfldWidth, field->sizeHint.width()); + } + + prevLbl = label; + prevFld = field; + } + + // Now, finally update the min/sizeHint widths + if (wrapAllRows) { + sh_width = qMax(maxShLblWidth, qMax(maxShIfldWidth, maxShFldWidth)); + min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth)); + // in two line, we don't care as much about the threshold width + thresh_width = 0; + } else if (dontWrapRows) { + // This is just the max widths glommed together + sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth); + min_width = qMax(maxMinLblWidth + maxMinFldWidth, maxMinIfldWidth); + thresh_width = QWIDGETSIZE_MAX; + } else { + // This is just the max widths glommed together + sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth); + // min width needs to be the min when everything is wrapped, + // otherwise we'll never get set with a width that causes wrapping + min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth)); + // We split a pair at label sh + field min (### for now..) + thresh_width = maxShLblWidth + maxMinFldWidth; + } + + // Update the expansions + expandVertical = expandV; + expandHorizontal = expandH; + } + sizesDirty = false; +} + +void QFormLayoutPrivate::recalcHFW(int w) +{ + setupHfwLayoutData(); + + int h = 0; + int mh = 0; + + for (int r = 0; r < vLayoutCount; ++r) { + int spacing = hfwLayouts.at(r).spacing; + h += hfwLayouts.at(r).sizeHint + spacing; + mh += hfwLayouts.at(r).minimumSize + spacing; + } + + if (sh_width > 0 && sh_width == w) { + hfw_sh_height = qMin(QLAYOUTSIZE_MAX, h); + hfw_sh_minheight = qMin(QLAYOUTSIZE_MAX, mh); + } else { + hfw_width = w; + hfw_height = qMin(QLAYOUTSIZE_MAX, h); + hfw_minheight = qMin(QLAYOUTSIZE_MAX, mh); + } +} + +void QFormLayoutPrivate::setupHfwLayoutData() +{ + // setupVerticalLayoutData must be called before this + // setupHorizontalLayoutData must also be called before this + // copies non hfw data into hfw + // then updates size and min + + + // Note: QGridLayout doesn't call minimumHeightForWidth, + // but instead uses heightForWidth for both min and sizeHint. + // For the common case where minimumHeightForWidth just calls + // heightForWidth, we do the calculation twice, which can be + // very expensive for word wrapped QLabels/QTextEdits, for example. + // So we just use heightForWidth as well. + int i; + int rr = m_matrix.rowCount(); + + hfwLayouts.clear(); + hfwLayouts.resize(vLayoutCount); + for (i = 0; i < vLayoutCount; ++i) + hfwLayouts[i] = vLayouts.at(i); + + for (i = 0; i < rr; ++i) { + QFormLayoutItem *label = m_matrix(i, 0); + QFormLayoutItem *field = m_matrix(i, 1); + + if (label) { + if (label->isHfw) { + // We don't check sideBySide here, since a label is only + // ever side by side with its field + int hfw = label->heightForWidth(label->layoutWidth); + hfwLayouts[label->vLayoutIndex].minimumSize = hfw; + hfwLayouts[label->vLayoutIndex].sizeHint = hfw; + } else { + // Reset these here, so the field can do a qMax below (the previous value may have + // been the fields non-hfw values, which are often larger than hfw) + hfwLayouts[label->vLayoutIndex].sizeHint = label->sizeHint.height(); + hfwLayouts[label->vLayoutIndex].minimumSize = label->minSize.height(); + } + } + + if (field) { + int hfw = field->isHfw ? field->heightForWidth(field->layoutWidth) : 0; + int h = field->isHfw ? hfw : field->sizeHint.height(); + int mh = field->isHfw ? hfw : field->minSize.height(); + + if (field->sideBySide) { + int oh = hfwLayouts.at(field->vLayoutIndex).sizeHint; + int omh = hfwLayouts.at(field->vLayoutIndex).minimumSize; + + hfwLayouts[field->vLayoutIndex].sizeHint = qMax(h, oh); + hfwLayouts[field->vLayoutIndex].minimumSize = qMax(mh, omh); + } else { + hfwLayouts[field->vLayoutIndex].sizeHint = h; + hfwLayouts[field->vLayoutIndex].minimumSize = mh; + } + } + } +} + +/* + Given up to four items involved in a vertical spacing calculation + (two rows * two columns), return the max vertical spacing for the + row containing item1 (which may also include item2) + We assume parent and item1 are not null. + + If a particular row is split, then the spacings for that row and + the following row are affected, and this function should be + called with recalculate = true for both rows (note: only rows with both + a label and a field can be split). + + In particular: + + 1) the split label's row vspace needs to be changed to qMax(label/prevLabel, label/prevField) + [call with item1 = label, item2 = null, prevItem1 & prevItem2 as before] + 2) the split field's row vspace needs to be changed to the label/field spacing + [call with item1 = field, item2 = null, prevItem1 = label, prevItem2 = null] + + [if the next row has one item, 'item'] + 3a) the following row's vspace needs to be changed to item/field spacing (would + previously been the qMax(item/label, item/field) spacings) + [call with item1 = item, item2 = null, prevItem1 = field, prevItem2 = null] + + [if the next row has two items, 'label2' and 'field2'] + 3b) the following row's vspace needs to be changed to be qMax(field/label2, field/field2) spacing + [call with item1 = label2, item2 = field2, prevItem1 = field, prevItem2 = null] + + In the (common) non split case, we can just use the precalculated vspace (possibly qMaxed between + label and field). + + If recalculate is true, we expect: + - parent != null + - item1 != null + - item2 can be null + - prevItem1 can be null + - if item2 is not null, prevItem2 will be null (e.g. steps 1 or 3 above) + - if prevItem1 is null, prevItem2 will be null +*/ +static inline int spacingHelper(QWidget* parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem* item1, QFormLayoutItem* item2, QFormLayoutItem* prevItem1, QFormLayoutItem *prevItem2) +{ + int spacing = userVSpacing; + if (spacing < 0) { + if (!recalculate) { + if (item1) + spacing = item1->vSpace; + if (item2) + spacing = qMax(spacing, item2->vSpace); + } else { + if (style && prevItem1) { + QSizePolicy::ControlTypes itemtypes = + QSizePolicy::ControlTypes(item1 ? item1->controlTypes() : QSizePolicy::DefaultType); + int spacing2 = 0; + + spacing = style->combinedLayoutSpacing(itemtypes, prevItem1->controlTypes(), Qt::Vertical, 0, parent); + + // At most of one of item2 and prevItem2 will be nonnull + if (item2) + spacing2 = style->combinedLayoutSpacing(item2->controlTypes(), prevItem1->controlTypes(), Qt::Vertical, 0, parent); + else if (prevItem2) + spacing2 = style->combinedLayoutSpacing(itemtypes, prevItem2->controlTypes(), Qt::Vertical, 0, parent); + + spacing = qMax(spacing, spacing2); + } + } + } else { + if (prevItem1) { + QWidget *wid = prevItem1->item->widget(); + if (wid) + spacing = qMax(spacing, prevItem1->geometry().top() - wid->geometry().top() ); + } + if (prevItem2) { + QWidget *wid = prevItem2->item->widget(); + if (wid) + spacing = qMax(spacing, prevItem2->geometry().top() - wid->geometry().top() ); + } + } + return spacing; +} + +static inline void initLayoutStruct(QLayoutStruct& sl, QFormLayoutItem* item) +{ + sl.init(item->vStretch(), item->minSize.height()); + sl.sizeHint = item->sizeHint.height(); + sl.maximumSize = item->maxSize.height(); + sl.expansive = (item->expandingDirections() & Qt::Vertical); + sl.empty = false; +} + +void QFormLayoutPrivate::setupVerticalLayoutData(int width) +{ + Q_Q(QFormLayout); + + // Early out if we have no changes that would cause a change in vertical layout + if ((width == layoutWidth || (width >= thresh_width && layoutWidth >= thresh_width)) && !dirty && !sizesDirty) + return; + + layoutWidth = width; + + int rr = m_matrix.rowCount(); + int vidx = 1; + QFormLayout::RowWrapPolicy rowWrapPolicy = q->rowWrapPolicy(); + bool wrapAllRows = (rowWrapPolicy == QFormLayout::WrapAllRows); + bool addTopBottomStretch = true; + + vLayouts.clear(); + vLayouts.resize((2 * rr) + 2); // a max, some may be unused + + QStyle *style = 0; + + int userVSpacing = q->verticalSpacing(); + + if (userVSpacing < 0) { + if (QWidget *widget = q->parentWidget()) + style = widget->style(); + } + + // make sure our sizes are up to date + updateSizes(); + + // Grab the widest label width here + // This might be different from the value computed during + // sizeHint/minSize, since we don't count label/field pairs that + // are split. + maxLabelWidth = 0; + if (!wrapAllRows) { + for (int i = 0; i < rr; ++i) { + const QFormLayoutItem *label = m_matrix(i, 0); + const QFormLayoutItem *field = m_matrix(i, 1); + if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width)) + maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width()); + } + } else { + maxLabelWidth = width; + } + + QFormLayoutItem *prevItem1 = 0; + QFormLayoutItem *prevItem2 = 0; + bool prevRowSplit = false; + + for (int i = 0; i < rr; ++i) { + QFormLayoutItem *label = m_matrix(i, 0); + QFormLayoutItem *field = m_matrix(i, 1); + + // Totally ignore empty rows... + if (!label && !field) + continue; + + QSize min1; + QSize min2; + QSize sh1; + QSize sh2; + if (label) { + min1 = label->minSize; + sh1 = label->sizeHint; + } + if (field) { + min2 = field->minSize; + sh2 = field->sizeHint; + } + + // In separate lines, we make a vLayout for everything that isn't null + // in side by side, we only separate label/field if we're going to wrap it + bool splitSideBySide = (rowWrapPolicy == QFormLayout::WrapLongRows) + && ((maxLabelWidth < sh1.width()) || (width < (maxLabelWidth + min2.width()))); + + if (wrapAllRows || splitSideBySide) { + if (label) { + initLayoutStruct(vLayouts[vidx], label); + + if (vidx > 1) + vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, label, 0, prevItem1, prevItem2); + + label->vLayoutIndex = vidx; + label->sideBySide = false; + + prevItem1 = label; + prevItem2 = 0; + + if (vLayouts[vidx].stretch > 0) + addTopBottomStretch = false; + + ++vidx; + } + + if (field) { + initLayoutStruct(vLayouts[vidx], field); + + if (vidx > 1) + vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, field, 0, prevItem1, prevItem2); + + field->vLayoutIndex = vidx; + field->sideBySide = false; + + prevItem1 = field; + prevItem2 = 0; + + if (vLayouts[vidx].stretch > 0) + addTopBottomStretch = false; + + ++vidx; + } + + prevRowSplit = splitSideBySide; + } else { + // we're in side by side mode, and we have enough space to do that + QSize max1(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + QSize max2(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + + int stretch1 = 0; + int stretch2 = 0; + bool expanding = false; + + if (label) { + max1 = label->maxSize; + if (label->expandingDirections() & Qt::Vertical) + expanding = true; + + label->sideBySide = (field != 0); + label->vLayoutIndex = vidx; + stretch1 = label->vStretch(); + } + + if (field) { + max2 = field->maxSize; + if (field->expandingDirections() & Qt::Vertical) + expanding = true; + + field->sideBySide = (label || !field->fullRow); + field->vLayoutIndex = vidx; + stretch2 = field->vStretch(); + } + + vLayouts[vidx].init(qMax(stretch1, stretch2), qMax(min1.height(), min2.height())); + vLayouts[vidx].sizeHint = qMax(sh1.height(), sh2.height()); + vLayouts[vidx].maximumSize = qMin(max1.height(), max2.height()); + vLayouts[vidx].expansive = expanding || (vLayouts[vidx].stretch > 0); + vLayouts[vidx].empty = false; + + if (vLayouts[vidx].stretch > 0) + addTopBottomStretch = false; + + if (vidx > 1) + vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, prevRowSplit, label, field, prevItem1, prevItem2); + + if (label) { + prevItem1 = label; + prevItem2 = field; + } else { + prevItem1 = field; + prevItem2 = 0; + } + + prevRowSplit = false; + ++vidx; + } + } + + if (addTopBottomStretch) { + Qt::Alignment formAlignment = q->formAlignment(); + + if (!(formAlignment & Qt::AlignBottom)) { + // AlignTop (default if unspecified) or AlignVCenter: We add a stretch at the bottom + vLayouts[vidx].init(1, 0); + vLayouts[vidx].expansive = true; + ++vidx; + } + + if (formAlignment & (Qt::AlignVCenter | Qt::AlignBottom)) { + // AlignVCenter or AlignBottom: We add a stretch at the top + vLayouts[0].init(1, 0); + vLayouts[0].expansive = true; + } else { + vLayouts[0].init(0, 0); + } + } else { + vLayouts[0].init(0, 0); + } + + vLayoutCount = vidx; + dirty = false; +} + +void QFormLayoutPrivate::setupHorizontalLayoutData(int width) +{ + Q_Q(QFormLayout); + + // requires setupVerticalLayoutData to be called first + + int fieldMaxWidth = 0; + + int rr = m_matrix.rowCount(); + bool wrapAllRows = (q->rowWrapPolicy() == QFormLayout::WrapAllRows); + + for (int i = 0; i < rr; ++i) { + QFormLayoutItem *label = m_matrix(i, 0); + QFormLayoutItem *field = m_matrix(i, 1); + + // Totally ignore empty rows... + if (!label && !field) + continue; + + if (label) { + // if there is a field, and we're side by side, we use maxLabelWidth + // otherwise we just use the sizehint + label->layoutWidth = (field && label->sideBySide) ? maxLabelWidth : label->sizeHint.width(); + label->layoutPos = 0; + } + + if (field) { + // This is the default amount allotted to fields in sbs + int fldwidth = width - maxLabelWidth - field->sbsHSpace; + + // If we've split a row, we still decide to align + // the field with all the other field if it will fit + // Fields in sbs mode get the remnants of the maxLabelWidth + if (!field->sideBySide) { + if (wrapAllRows || (!label && field->fullRow) || field->sizeHint.width() > fldwidth) { + field->layoutWidth = width; + field->layoutPos = 0; + } else { + field->layoutWidth = fldwidth; + field->layoutPos = width - fldwidth; + } + } else { + // We're sbs, so we should have a label + field->layoutWidth = fldwidth; + field->layoutPos = width - fldwidth; + } + + fieldMaxWidth = qMax(fieldMaxWidth, field->maxSize.width()); + } + } + + formMaxWidth = maxLabelWidth + fieldMaxWidth; +} + +void QFormLayoutPrivate::calcSizeHints() +{ + Q_Q(QFormLayout); + + int leftMargin, topMargin, rightMargin, bottomMargin; + q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + + updateSizes(); + setupVerticalLayoutData(QLAYOUTSIZE_MAX); + // Don't need to call setupHorizontal here + + int h = topMargin + bottomMargin; + int mh = topMargin + bottomMargin; + + // The following are set in updateSizes + int w = sh_width + leftMargin + rightMargin; + int mw = min_width + leftMargin + rightMargin; + + for (int i = 0; i < vLayoutCount; ++i) { + int spacing = vLayouts.at(i).spacing; + h += vLayouts.at(i).sizeHint + spacing; + mh += vLayouts.at(i).minimumSize + spacing; + } + + minSize.rwidth() = qMin(mw, QLAYOUTSIZE_MAX); + minSize.rheight() = qMin(mh, QLAYOUTSIZE_MAX); + prefSize.rwidth() = qMin(w, QLAYOUTSIZE_MAX); + prefSize.rheight() = qMin(h, QLAYOUTSIZE_MAX); +} + +int QFormLayoutPrivate::insertRow(int row) +{ + int rowCnt = m_matrix.rowCount(); + if (uint(row) > uint(rowCnt)) + row = rowCnt; + + insertRows(row, 1); + return row; +} + +void QFormLayoutPrivate::insertRows(int row, int count) +{ + while (count > 0) { + m_matrix.insertRow(row, 0); + --count; + } +} + +void QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item) +{ + const bool fullRow = role == QFormLayout::SpanningRole; + const int column = role == QFormLayout::SpanningRole ? 1 : static_cast(role); + if (uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U) { + qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column); + return; + } + + if (!item) + return; + + if (m_matrix(row, column)) { + qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column); + return; + } + + QFormLayoutItem *i = new QFormLayoutItem(item); + i->fullRow = fullRow; + m_matrix(row, column) = i; + + m_things.append(i); +} + +void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout *layout) +{ + if (layout) { + Q_Q(QFormLayout); + q->addChildLayout(layout); + setItem(row, role, layout); + } +} + +void QFormLayoutPrivate::setWidget(int row, QFormLayout::ItemRole role, QWidget *widget) +{ + if (widget) { + Q_Q(QFormLayout); + q->addChildWidget(widget); + setItem(row, role, QLayoutPrivate::createWidgetItem(q, widget)); + } +} + +QStyle* QFormLayoutPrivate::getStyle() const +{ + Q_Q(const QFormLayout); + + // ### cache + if (QWidget *parentWidget = q->parentWidget()) + return parentWidget->style(); + else + return QApplication::style(); +} + +/*! + \class QFormLayout + \since 4.4 + \brief The QFormLayout class manages forms of input widgets and their associated labels. + + \ingroup geomanagement + + + QFormLayout is a convenience layout class that lays out its + children in a two-column form. The left column consists of labels + and the right column consists of "field" widgets (line editors, + spin boxes, etc.). + + Traditionally, such two-column form layouts were achieved using + QGridLayout. QFormLayout is a higher-level alternative that + provides the following advantages: + + \list + \o \bold{Adherence to the different platform's look and feel guidelines.} + + For example, the + \l{Mac OS X Aqua} and KDE guidelines specify that the + labels should be right-aligned, whereas Windows and GNOME + applications normally use left-alignment. + + \o \bold{Support for wrapping long rows.} + + For devices with small displays, QFormLayout can be set to + \l{WrapLongRows}{wrap long rows}, or even to + \l{WrapAllRows}{wrap all rows}. + + \o \bold{Convenient API for creating label--field pairs.} + + The addRow() overload that takes a QString and a QWidget * + creates a QLabel behind the scenes and automatically set up + its buddy. We can then write code like this: + + \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 0 + + Compare this with the following code, written using QGridLayout: + + \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 1 + \endlist + + The table below shows the default appearance in different styles. + + \table + \header + \o QCommonStyle derived styles (except QPlastiqueStyle) + \o QMacStyle + \o QPlastiqueStyle + \o Qt Extended styles + \row + \o \inlineimage qformlayout-win.png + \o \inlineimage qformlayout-mac.png + \o \inlineimage qformlayout-kde.png + \o \inlineimage qformlayout-qpe.png + \row + \o Traditional style used for Windows, GNOME, and earlier + versions of KDE. Labels are left aligned, and expanding + fields grow to fill the available space. (This normally + corresponds to what we would get using a two-column + QGridLayout.) + \o Style based on the + \l{Mac OS X Aqua} guidelines. Labels are right-aligned, + the fields don't grow beyond their size hint, and the + form is horizontally centered. + \o Recommended style for + \l{KDE applications}. Similar to MacStyle, except that the form + is left-aligned and all fields grow to fill the available + space. + \o Default style for Qt Extended styles. Labels are right-aligned, + expanding fields grow to fill the available space, and row + wrapping is enabled for long lines. + \endtable + + The form styles can be also be overridden individually by calling + setLabelAlignment(), setFormAlignment(), setFieldGrowthPolicy(), + and setRowWrapPolicy(). For example, to simulate the form layout + appearance of QMacStyle on all platforms, but with left-aligned + labels, you could write: + + \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 2 + + \sa QGridLayout, QBoxLayout, QStackedLayout +*/ + + +/*! + \enum QFormLayout::FieldGrowthPolicy + + This enum specifies the different policies that can be used to + control the way in which the form's fields grow. + + \value FieldsStayAtSizeHint + The fields never grow beyond their + \l{QWidgetItem::sizeHint()}{effective size hint}. This is + the default for QMacStyle. + + \value ExpandingFieldsGrow + Fields with an horizontal \l{QSizePolicy}{size policy} of + \l{QSizePolicy::}{Expanding} or + \l{QSizePolicy::}{MinimumExpanding} will grow to fill the + available space. The other fields will not grow beyond + their effective size hint. This is the default policy for + Plastique. + + \value AllNonFixedFieldsGrow + All fields with a size policy that allows them to grow + will grow to fill the available space. This is the default + policy for most styles. + + \sa fieldGrowthPolicy +*/ + +/*! + \enum QFormLayout::RowWrapPolicy + + This enum specifies the different policies that can be used to + control the way in which the form's rows wrap. + + \value DontWrapRows + Fields are always laid out next to their label. This is + the default policy for all styles except Qt Extended styles + and QS60Style. + + \value WrapLongRows + Labels are given enough horizontal space to fit the widest label, + and the rest of the space is given to the fields. If the minimum + size of a field pair is wider than the available space, the field + is wrapped to the next line. This is the default policy for + Qt Extended styles and and QS60Style. + + \value WrapAllRows + Fields are always laid out below their label. + + \sa rowWrapPolicy +*/ + +/*! + \enum QFormLayout::ItemRole + + This enum specifies the types of widgets (or other layout items) + that may appear in a row. + + \value LabelRole A label widget. + \value FieldRole A field widget. + \value SpanningRole A widget that spans label and field columns. + + \sa itemAt(), getItemPosition() +*/ + +/*! + Constructs a new form layout with the given \a parent widget. + + \sa QWidget::setLayout() +*/ +QFormLayout::QFormLayout(QWidget *parent) + : QLayout(*new QFormLayoutPrivate, 0, parent) +{ +} + +/*! + Destroys the form layout. +*/ +QFormLayout::~QFormLayout() +{ + Q_D(QFormLayout); + + /* + The clearing and destruction order here is important. We start by clearing + m_things so that QLayout and the rest of the world know that we don't babysit + the layout items anymore and don't care if they are destroyed. + */ + d->m_things.clear(); + qDeleteAll(d->m_matrix.storage()); + d->m_matrix.clear(); +} + +/*! + Adds a new row to the bottom of this form layout, with the given + \a label and \a field. + + \sa insertRow() +*/ +void QFormLayout::addRow(QWidget *label, QWidget *field) +{ + insertRow(-1, label, field); +} + +/*! + \overload +*/ +void QFormLayout::addRow(QWidget *label, QLayout *field) +{ + insertRow(-1, label, field); +} + +/*! + \overload + + This overload automatically creates a QLabel behind the scenes + with \a labelText as its text. The \a field is set as the new + QLabel's \l{QLabel::setBuddy()}{buddy}. +*/ +void QFormLayout::addRow(const QString &labelText, QWidget *field) +{ + insertRow(-1, labelText, field); +} + +/*! + \overload + + This overload automatically creates a QLabel behind the scenes + with \a labelText as its text. +*/ +void QFormLayout::addRow(const QString &labelText, QLayout *field) +{ + insertRow(-1, labelText, field); +} + +/*! + \overload + + Adds the specified \a widget at the end of this form layout. The + \a widget spans both columns. +*/ +void QFormLayout::addRow(QWidget *widget) +{ + insertRow(-1, widget); +} + +/*! + \overload + + Adds the specified \a layout at the end of this form layout. The + \a layout spans both columns. +*/ +void QFormLayout::addRow(QLayout *layout) +{ + insertRow(-1, layout); +} + +/*! + Inserts a new row at position \a row in this form layout, with + the given \a label and \a field. If \a row is out of bounds, the + new row is added at the end. + + \sa addRow() +*/ +void QFormLayout::insertRow(int row, QWidget *label, QWidget *field) +{ + Q_D(QFormLayout); + + row = d->insertRow(row); + if (label) + d->setWidget(row, LabelRole, label); + if (field) + d->setWidget(row, FieldRole, field); + invalidate(); +} + +/*! + \overload +*/ +void QFormLayout::insertRow(int row, QWidget *label, QLayout *field) +{ + Q_D(QFormLayout); + + row = d->insertRow(row); + if (label) + d->setWidget(row, LabelRole, label); + if (field) + d->setLayout(row, FieldRole, field); + invalidate(); +} + +/*! + \overload + + This overload automatically creates a QLabel behind the scenes + with \a labelText as its text. The \a field is set as the new + QLabel's \l{QLabel::setBuddy()}{buddy}. +*/ +void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field) +{ + QLabel *label = 0; + if (!labelText.isEmpty()) { + label = new QLabel(labelText); +#ifndef QT_NO_SHORTCUT + label->setBuddy(field); +#endif + } + insertRow(row, label, field); +} + +/*! + \overload + + This overload automatically creates a QLabel behind the scenes + with \a labelText as its text. +*/ +void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field) +{ + insertRow(row, labelText.isEmpty() ? 0 : new QLabel(labelText), field); +} + +/*! + \overload + + Inserts the specified \a widget at position \a row in this form + layout. The \a widget spans both columns. If \a row is out of + bounds, the widget is added at the end. +*/ +void QFormLayout::insertRow(int row, QWidget *widget) +{ + Q_D(QFormLayout); + + if (!widget) { + qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName())); + return; + } + + row = d->insertRow(row); + d->setWidget(row, SpanningRole, widget); + invalidate(); +} + +/*! + \overload + + Inserts the specified \a layout at position \a row in this form + layout. The \a layout spans both columns. If \a row is out of + bounds, the widget is added at the end. +*/ +void QFormLayout::insertRow(int row, QLayout *layout) +{ + Q_D(QFormLayout); + + if (!layout) { + qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName())); + return; + } + + row = d->insertRow(row); + d->setLayout(row, SpanningRole, layout); + invalidate(); +} + +/*! + \reimp +*/ +void QFormLayout::addItem(QLayoutItem *item) +{ + Q_D(QFormLayout); + + int row = d->insertRow(d->m_matrix.rowCount()); + d->setItem(row, FieldRole, item); + invalidate(); +} + +/*! + \reimp +*/ +int QFormLayout::count() const +{ + Q_D(const QFormLayout); + return d->m_things.count(); +} + +/*! + \reimp +*/ +QLayoutItem *QFormLayout::itemAt(int index) const +{ + Q_D(const QFormLayout); + if (QFormLayoutItem *formItem = d->m_things.value(index)) + return formItem->item; + return 0; +} + +/*! + \reimp +*/ +QLayoutItem *QFormLayout::takeAt(int index) +{ + Q_D(QFormLayout); + + const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index)); + if (storageIndex == -1) { + qWarning("QFormLayout::takeAt: Invalid index %d", index); + return 0; + } + + int row, col; + QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col); + Q_ASSERT(d->m_matrix(row, col)); + + QFormLayoutItem *item = d->m_matrix(row, col); + Q_ASSERT(item); + d->m_things.removeAt(index); + d->m_matrix(row, col) = 0; + + invalidate(); + + // grab ownership back from the QFormLayoutItem + QLayoutItem *i = item->item; + item->item = 0; + delete item; + return i; +} + +/*! + \reimp +*/ +Qt::Orientations QFormLayout::expandingDirections() const +{ + Q_D(const QFormLayout); + QFormLayoutPrivate *e = const_cast(d); + e->updateSizes(); + + Qt::Orientations o = 0; + if (e->expandHorizontal) + o = Qt::Horizontal; + if (e->expandVertical) + o |= Qt::Vertical; + return o; +} + +/*! + \reimp +*/ +bool QFormLayout::hasHeightForWidth() const +{ + Q_D(const QFormLayout); + QFormLayoutPrivate *e = const_cast(d); + e->updateSizes(); + return (d->has_hfw || rowWrapPolicy() == WrapLongRows); +} + +/*! + \reimp +*/ +int QFormLayout::heightForWidth(int width) const +{ + Q_D(const QFormLayout); + if (!hasHeightForWidth()) + return -1; + + int leftMargin, topMargin, rightMargin, bottomMargin; + getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + + int targetWidth = width - leftMargin - rightMargin; + + if (!d->haveHfwCached(targetWidth)) { + QFormLayoutPrivate *dat = const_cast(d); + dat->setupVerticalLayoutData(targetWidth); + dat->setupHorizontalLayoutData(targetWidth); + dat->recalcHFW(targetWidth); + } + if (targetWidth == d->sh_width) + return d->hfw_sh_height + topMargin + bottomMargin; + else + return d->hfw_height + topMargin + bottomMargin; +} + +/*! + \reimp +*/ +void QFormLayout::setGeometry(const QRect &rect) +{ + Q_D(QFormLayout); + if (d->dirty || rect != geometry()) { + QRect cr = rect; + int leftMargin, topMargin, rightMargin, bottomMargin; + getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin); + + bool hfw = hasHeightForWidth(); + d->setupVerticalLayoutData(cr.width()); + d->setupHorizontalLayoutData(cr.width()); + if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount)) + d->recalcHFW(cr.width()); + if (hfw) { + qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height()); + d->arrangeWidgets(d->hfwLayouts, cr); + } else { + qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height()); + d->arrangeWidgets(d->vLayouts, cr); + } + QLayout::setGeometry(rect); + } +} + +/*! + \reimp +*/ +QSize QFormLayout::sizeHint() const +{ + Q_D(const QFormLayout); + if (!d->prefSize.isValid()) { + QFormLayoutPrivate *dat = const_cast(d); + dat->calcSizeHints(); + } + return d->prefSize; +} + +/*! + \reimp +*/ +QSize QFormLayout::minimumSize() const +{ + // ### fix minimumSize if hfw + Q_D(const QFormLayout); + if (!d->minSize.isValid()) { + QFormLayoutPrivate *dat = const_cast(d); + dat->calcSizeHints(); + } + return d->minSize; +} + +/*! + \reimp +*/ +void QFormLayout::invalidate() +{ + Q_D(QFormLayout); + d->dirty = true; + d->sizesDirty = true; + d->minSize = QSize(); + d->prefSize = QSize(); + d->formMaxWidth = -1; + d->hfw_width = -1; + d->sh_width = -1; + d->layoutWidth = -1; + d->hfw_sh_height = -1; + QLayout::invalidate(); +} + +/*! + Returns the number of rows in the form. + + \sa QLayout::count() +*/ +int QFormLayout::rowCount() const +{ + Q_D(const QFormLayout); + return d->m_matrix.rowCount(); +} + +/*! + Returns the layout item in the given \a row with the specified \a + role (column). Returns 0 if there is no such item. + + \sa QLayout::itemAt(), setItem() +*/ +QLayoutItem *QFormLayout::itemAt(int row, ItemRole role) const +{ + Q_D(const QFormLayout); + if (uint(row) >= uint(d->m_matrix.rowCount())) + return 0; + switch (role) { + case SpanningRole: + if (QFormLayoutItem *item = d->m_matrix(row, 1)) + if (item->fullRow) + return item->item; + break; + case LabelRole: + case FieldRole: + if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1)) + return item->item; + break; + } + return 0; +} + +/*! + Retrieves the row and role (column) of the item at the specified + \a index. If \a index is out of bounds, *\a rowPtr is set to -1; + otherwise the row is stored in *\a rowPtr and the role is stored + in *\a rolePtr. + + \sa itemAt(), count(), getLayoutPosition(), getWidgetPosition() +*/ +void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const +{ + Q_D(const QFormLayout); + int col = -1; + int row = -1; + + const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index)); + if (storageIndex != -1) + QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col); + + if (rowPtr) + *rowPtr = row; + if (rolePtr && col != -1) { + const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow; + if (spanning) { + *rolePtr = SpanningRole; + } else { + *rolePtr = ItemRole(col); + } + } +} + +/*! + Retrieves the row and role (column) of the specified child \a + layout. If \a layout is not in the form layout, *\a rowPtr is set + to -1; otherwise the row is stored in *\a rowPtr and the role is stored + in *\a rolePtr. +*/ +void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const +{ + int n = count(); + int index = 0; + while (index < n) { + if (itemAt(index) == layout) + break; + ++index; + } + getItemPosition(index, rowPtr, rolePtr); +} + +/*! + Retrieves the row and role (column) of the specified \a widget in + the layout. If \a widget is not in the layout, *\a rowPtr is set + to -1; otherwise the row is stored in *\a rowPtr and the role is stored + in *\a rolePtr. + + \sa getItemPosition(), itemAt() +*/ +void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const +{ + getItemPosition(indexOf(widget), rowPtr, rolePtr); +} + +// ### eliminate labelForField() + +/*! + Returns the label associated with the given \a field. + + \sa itemAt() +*/ +QWidget *QFormLayout::labelForField(QWidget *field) const +{ + Q_D(const QFormLayout); + + int row; + ItemRole role; + + getWidgetPosition(field, &row, &role); + + if (row != -1 && role == FieldRole) { + if (QFormLayoutItem *label = d->m_matrix(row, LabelRole)) + return label->widget(); + } + return 0; +} + +/*! + \overload +*/ +QWidget *QFormLayout::labelForField(QLayout *field) const +{ + Q_D(const QFormLayout); + + int row; + ItemRole role; + + getLayoutPosition(field, &row, &role); + + if (row != -1 && role == FieldRole) { + if (QFormLayoutItem *label = d->m_matrix(row, LabelRole)) + return label->widget(); + } + return 0; +} + +/*! + \property QFormLayout::fieldGrowthPolicy + \brief the way in which the form's fields grow + + The default value depends on the widget or application style. For + QMacStyle, the default is FieldsStayAtSizeHint; for QCommonStyle + derived styles (like Plastique and Windows), the default + is ExpandingFieldsGrow; for Qt Extended styles, the default is + AllNonFixedFieldsGrow. + + If none of the fields can grow and the form is resized, extra + space is distributed according to the current + \l{formAlignment}{form alignment}. + + \sa formAlignment, rowWrapPolicy +*/ + +void QFormLayout::setFieldGrowthPolicy(FieldGrowthPolicy policy) +{ + Q_D(QFormLayout); + if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) { + d->fieldGrowthPolicy = policy; + invalidate(); + } +} + +QFormLayout::FieldGrowthPolicy QFormLayout::fieldGrowthPolicy() const +{ + Q_D(const QFormLayout); + if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) { + return QFormLayout::FieldGrowthPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutFieldGrowthPolicy)); + } else { + return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy); + } +} + +/*! + \property QFormLayout::rowWrapPolicy + \brief the way in which the form's rows wrap + + The default value depends on the widget or application style. For + Qt Extended styles and QS60Style, the default is WrapLongRows; + for the other styles, the default is DontWrapRows. + + If you want to display each label above its associated field + (instead of next to it), set this property to WrapAllRows. + + \sa fieldGrowthPolicy +*/ + +void QFormLayout::setRowWrapPolicy(RowWrapPolicy policy) +{ + Q_D(QFormLayout); + if (RowWrapPolicy(d->rowWrapPolicy) != policy) { + d->rowWrapPolicy = policy; + invalidate(); + } +} + +QFormLayout::RowWrapPolicy QFormLayout::rowWrapPolicy() const +{ + Q_D(const QFormLayout); + if (d->rowWrapPolicy == DefaultRowWrapPolicy) { + return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy)); + } else { + return QFormLayout::RowWrapPolicy(d->rowWrapPolicy); + } +} + +/*! + \property QFormLayout::labelAlignment + \brief the horizontal alignment of the labels + + The default value depends on the widget or application style. For + QCommonStyle derived styles, except for QPlastiqueStyle, the + default is Qt::AlignLeft; for the other styles, the default is + Qt::AlignRight. + + \sa formAlignment +*/ + +void QFormLayout::setLabelAlignment(Qt::Alignment alignment) +{ + Q_D(QFormLayout); + if (d->labelAlignment != alignment) { + d->labelAlignment = alignment; + invalidate(); + } +} + +Qt::Alignment QFormLayout::labelAlignment() const +{ + Q_D(const QFormLayout); + if (!d->labelAlignment) { + return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); + } else { + return d->labelAlignment; + } +} + +/*! + \property QFormLayout::formAlignment + \brief the alignment of the form layout's contents within the layout's geometry + + The default value depends on the widget or application style. For + QMacStyle, the default is Qt::AlignHCenter | Qt::AlignTop; for the + other styles, the default is Qt::AlignLeft | Qt::AlignTop. + + \sa labelAlignment, rowWrapPolicy +*/ + +void QFormLayout::setFormAlignment(Qt::Alignment alignment) +{ + Q_D(QFormLayout); + if (d->formAlignment != alignment) { + d->formAlignment = alignment; + invalidate(); + } +} + +Qt::Alignment QFormLayout::formAlignment() const +{ + Q_D(const QFormLayout); + if (!d->formAlignment) { + return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment)); + } else { + return d->formAlignment; + } +} + +/*! + \property QFormLayout::horizontalSpacing + \brief the spacing between widgets that are laid out side by side + + By default, if no value is explicitly set, the layout's horizontal + spacing is inherited from the parent layout, or from the style settings + for the parent widget. + + \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing} +*/ +void QFormLayout::setHorizontalSpacing(int spacing) +{ + Q_D(QFormLayout); + if (spacing != d->hSpacing) { + d->hSpacing = spacing; + invalidate(); + } +} + +int QFormLayout::horizontalSpacing() const +{ + Q_D(const QFormLayout); + if (d->hSpacing >= 0) { + return d->hSpacing; + } else { + return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing); + } +} + +/*! + \property QFormLayout::verticalSpacing + \brief the spacing between widgets that are laid out vertically + + By default, if no value is explicitly set, the layout's vertical spacing is + inherited from the parent layout, or from the style settings for the parent + widget. + + \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing} +*/ +void QFormLayout::setVerticalSpacing(int spacing) +{ + Q_D(QFormLayout); + if (spacing != d->vSpacing) { + d->vSpacing = spacing; + invalidate(); + } +} + +int QFormLayout::verticalSpacing() const +{ + Q_D(const QFormLayout); + if (d->vSpacing >= 0) { + return d->vSpacing; + } else { + return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing); + } +} + +/*! + This function sets both the vertical and horizontal spacing to + \a spacing. + + \sa setVerticalSpacing(), setHorizontalSpacing() +*/ +void QFormLayout::setSpacing(int spacing) +{ + Q_D(QFormLayout); + d->vSpacing = d->hSpacing = spacing; + invalidate(); +} + +/*! + If the vertical spacing is equal to the horizontal spacing, + this function returns that value; otherwise it returns -1. + + \sa setSpacing(), verticalSpacing(), horizontalSpacing() +*/ +int QFormLayout::spacing() const +{ + int hSpacing = horizontalSpacing(); + if (hSpacing == verticalSpacing()) { + return hSpacing; + } else { + return -1; + } +} + +void QFormLayoutPrivate::arrangeWidgets(const QVector& layouts, QRect &rect) +{ + Q_Q(QFormLayout); + + int i; + const int rr = m_matrix.rowCount(); + QWidget *w = q->parentWidget(); + Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection(); + + Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection); + int leftOffset = 0; + int delta = rect.width() - formMaxWidth; + if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) { + leftOffset = delta; + if (formAlignment & Qt::AlignHCenter) + leftOffset >>= 1; + } + + for (i = 0; i < rr; ++i) { + QFormLayoutItem *label = m_matrix(i, 0); + QFormLayoutItem *field = m_matrix(i, 1); + + if (label) { + int height = layouts.at(label->vLayoutIndex).size; + if ((label->expandingDirections() & Qt::Vertical) == 0) { + /* + If the field on the right-hand side is tall, + we want the label to be top-aligned, but not too + much. So we introduce a 7 / 4 factor so that it + gets some extra pixels at the top. + */ + height = qMin(height, + qMin(label->sizeHint.height() * 7 / 4, + label->maxSize.height())); + } + + QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height); + int x = leftOffset + rect.x() + label->layoutPos; + if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight) + x += label->layoutWidth - sz.width(); + QPoint p(x, layouts.at(label->vLayoutIndex).pos); + // ### expansion & sizepolicy stuff + + label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz))); + } + + if (field) { + QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size); + QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos); +/* + if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag)) + || (field->layout() && sz.width() < field->maxSize.width())) { + sz.rwidth() = field->layoutWidth; + } +*/ + if (field->maxSize.isValid()) + sz = sz.boundedTo(field->maxSize); + + field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz))); + } + } +} + +/*! + Sets the widget in the given \a row for the given \a role to \a widget, extending the + layout with empty rows if necessary. + + If the cell is already occupied, the \a widget is not inserted and an error message is + sent to the console. + + \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setWidget(). + + \sa setLayout() +*/ +void QFormLayout::setWidget(int row, ItemRole role, QWidget *widget) +{ + Q_D(QFormLayout); + int rowCnt = rowCount(); + if (row >= rowCnt) + d->insertRows(rowCnt, row - rowCnt + 1); + d->setWidget(row, role, widget); +} + +/*! + Sets the sub-layout in the given \a row for the given \a role to \a layout, extending the + form layout with empty rows if necessary. + + If the cell is already occupied, the \a layout is not inserted and an error message is + sent to the console. + + \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setLayout(). + + \sa setWidget() +*/ +void QFormLayout::setLayout(int row, ItemRole role, QLayout *layout) +{ + Q_D(QFormLayout); + int rowCnt = rowCount(); + if (row >= rowCnt) + d->insertRows(rowCnt, row - rowCnt + 1); + d->setLayout(row, role, layout); +} + +/*! + Sets the item in the given \a row for the given \a role to \a item, extending the + layout with empty rows if necessary. + + If the cell is already occupied, the \a item is not inserted and an error message is + sent to the console. + The \a item spans both columns. + + \warning Do not use this function to add child layouts or child + widget items. Use setLayout() or setWidget() instead. + + \sa setLayout() +*/ +void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item) +{ + Q_D(QFormLayout); + int rowCnt = rowCount(); + if (row >= rowCnt) + d->insertRows(rowCnt, row - rowCnt + 1); + d->setItem(row, role, item); +} + +/*! + \internal + */ + +void QFormLayout::resetFieldGrowthPolicy() +{ + Q_D(QFormLayout); + d->fieldGrowthPolicy = DefaultFieldGrowthPolicy; +} + +/*! + \internal + */ + +void QFormLayout::resetRowWrapPolicy() +{ + Q_D(QFormLayout); + d->rowWrapPolicy = DefaultRowWrapPolicy; +} + +/*! + \internal + */ + +void QFormLayout::resetFormAlignment() +{ + Q_D(QFormLayout); + d->formAlignment = 0; +} + +/*! + \internal + */ + +void QFormLayout::resetLabelAlignment() +{ + Q_D(QFormLayout); + d->labelAlignment = 0; +} + +#if 0 +void QFormLayout::dump() const +{ + Q_D(const QFormLayout); + for (int i = 0; i < rowCount(); ++i) { + for (int j = 0; j < 2; ++j) { + qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j)); + } + } + for (int i = 0; i < d->m_things.count(); ++i) + qDebug("m_things[%d] = %p", i, d->m_things.at(i)); +} +#endif + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qformlayout.h b/src/widgets/kernel/qformlayout.h new file mode 100644 index 0000000000..f229ac2d83 --- /dev/null +++ b/src/widgets/kernel/qformlayout.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFORMLAYOUT_H +#define QFORMLAYOUT_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QFormLayoutPrivate; + +class Q_GUI_EXPORT QFormLayout : public QLayout +{ + Q_OBJECT + Q_ENUMS(FormStyle FieldGrowthPolicy RowWrapPolicy ItemRole) + Q_DECLARE_PRIVATE(QFormLayout) + Q_PROPERTY(FieldGrowthPolicy fieldGrowthPolicy READ fieldGrowthPolicy WRITE setFieldGrowthPolicy RESET resetFieldGrowthPolicy) + Q_PROPERTY(RowWrapPolicy rowWrapPolicy READ rowWrapPolicy WRITE setRowWrapPolicy RESET resetRowWrapPolicy) + Q_PROPERTY(Qt::Alignment labelAlignment READ labelAlignment WRITE setLabelAlignment RESET resetLabelAlignment) + Q_PROPERTY(Qt::Alignment formAlignment READ formAlignment WRITE setFormAlignment RESET resetFormAlignment) + Q_PROPERTY(int horizontalSpacing READ horizontalSpacing WRITE setHorizontalSpacing) + Q_PROPERTY(int verticalSpacing READ verticalSpacing WRITE setVerticalSpacing) + +public: + enum FieldGrowthPolicy { + FieldsStayAtSizeHint, + ExpandingFieldsGrow, + AllNonFixedFieldsGrow + }; + + enum RowWrapPolicy { + DontWrapRows, + WrapLongRows, + WrapAllRows + }; + + enum ItemRole { + LabelRole = 0, + FieldRole = 1, + SpanningRole = 2 + }; + + explicit QFormLayout(QWidget *parent = 0); + ~QFormLayout(); + + void setFieldGrowthPolicy(FieldGrowthPolicy policy); + FieldGrowthPolicy fieldGrowthPolicy() const; + void setRowWrapPolicy(RowWrapPolicy policy); + RowWrapPolicy rowWrapPolicy() const; + void setLabelAlignment(Qt::Alignment alignment); + Qt::Alignment labelAlignment() const; + void setFormAlignment(Qt::Alignment alignment); + Qt::Alignment formAlignment() const; + + void setHorizontalSpacing(int spacing); + int horizontalSpacing() const; + void setVerticalSpacing(int spacing); + int verticalSpacing() const; + + int spacing() const; + void setSpacing(int); + + void addRow(QWidget *label, QWidget *field); + void addRow(QWidget *label, QLayout *field); + void addRow(const QString &labelText, QWidget *field); + void addRow(const QString &labelText, QLayout *field); + void addRow(QWidget *widget); + void addRow(QLayout *layout); + + void insertRow(int row, QWidget *label, QWidget *field); + void insertRow(int row, QWidget *label, QLayout *field); + void insertRow(int row, const QString &labelText, QWidget *field); + void insertRow(int row, const QString &labelText, QLayout *field); + void insertRow(int row, QWidget *widget); + void insertRow(int row, QLayout *layout); + + void setItem(int row, ItemRole role, QLayoutItem *item); + void setWidget(int row, ItemRole role, QWidget *widget); + void setLayout(int row, ItemRole role, QLayout *layout); + + QLayoutItem *itemAt(int row, ItemRole role) const; + void getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const; + void getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const; + void getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const; + QWidget *labelForField(QWidget *field) const; + QWidget *labelForField(QLayout *field) const; + + // reimplemented from QLayout + void addItem(QLayoutItem *item); + QLayoutItem *itemAt(int index) const; + QLayoutItem *takeAt(int index); + + void setGeometry(const QRect &rect); + QSize minimumSize() const; + QSize sizeHint() const; + void invalidate(); + + bool hasHeightForWidth() const; + int heightForWidth(int width) const; + Qt::Orientations expandingDirections() const; + int count() const; + + int rowCount() const; + +#if 0 + void dump() const; +#endif + +private: + void resetFieldGrowthPolicy(); + void resetRowWrapPolicy(); + void resetLabelAlignment(); + void resetFormAlignment(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/widgets/kernel/qgesture.cpp b/src/widgets/kernel/qgesture.cpp new file mode 100644 index 0000000000..daabe4f436 --- /dev/null +++ b/src/widgets/kernel/qgesture.cpp @@ -0,0 +1,1118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesture.h" +#include "private/qgesture_p.h" +#include "private/qstandardgestures_p.h" +#include "qgraphicsview.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + + /*! + \class QGesture + \since 4.6 + \ingroup gestures + + \brief The QGesture class represents a gesture, containing properties that + describe the corresponding user input. + + Gesture objects are not constructed directly by developers. They are created by + the QGestureRecognizer object that is registered with the application; see + QGestureRecognizer::registerRecognizer(). + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \section1 Gesture Properties + + The class has a list of properties that can be queried by the user to get + some gesture-specific arguments. For example, the pinch gesture has a scale + factor that is exposed as a property. + + Developers of custom gesture recognizers can add additional properties in + order to provide additional information about a gesture. This can be done + by adding new dynamic properties to a QGesture object, or by subclassing + the QGesture class (or one of its subclasses). + + \section1 Lifecycle of a Gesture Object + + A QGesture instance is implicitly created when needed and is owned by Qt. + Developers should never destroy them or store them for later use as Qt may + destroy particular instances of them and create new ones to replace them. + + The registered gesture recognizer monitors the input events for the target + object via its \l{QGestureRecognizer::}{recognize()} function, updating the + properties of the gesture object as required. + + The gesture object may be delivered to the target object in a QGestureEvent if + the corresponding gesture is active or has just been canceled. Each event that + is delivered contains a list of gesture objects, since support for more than + one gesture may be enabled for the target object. Due to the way events are + handled in Qt, gesture events may be filtered by other objects. + + \sa QGestureEvent, QGestureRecognizer +*/ + +/*! + Constructs a new gesture object with the given \a parent. + + QGesture objects are created by gesture recognizers in the + QGestureRecognizer::create() function. +*/ +QGesture::QGesture(QObject *parent) + : QObject(*new QGesturePrivate, parent) +{ + d_func()->gestureType = Qt::CustomGesture; +} + +/*! + \internal +*/ +QGesture::QGesture(QGesturePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Destroys the gesture object. +*/ +QGesture::~QGesture() +{ +} + +/*! + \property QGesture::state + \brief the current state of the gesture +*/ + +/*! + \property QGesture::gestureType + \brief the type of the gesture +*/ + +/*! + \property QGesture::hotSpot + + \brief The point that is used to find the receiver for the gesture event. + + The hot-spot is a point in the global coordinate system, use + QWidget::mapFromGlobal() or QGestureEvent::mapToGraphicsScene() to get a + local hot-spot. + + The hot-spot should be set by the gesture recognizer to allow gesture event + delivery to a QGraphicsObject. +*/ + +/*! + \property QGesture::hasHotSpot + \brief whether the gesture has a hot-spot +*/ + +Qt::GestureType QGesture::gestureType() const +{ + return d_func()->gestureType; +} + +Qt::GestureState QGesture::state() const +{ + return d_func()->state; +} + +QPointF QGesture::hotSpot() const +{ + return d_func()->hotSpot; +} + +void QGesture::setHotSpot(const QPointF &value) +{ + Q_D(QGesture); + d->hotSpot = value; + d->isHotSpotSet = true; +} + +bool QGesture::hasHotSpot() const +{ + return d_func()->isHotSpotSet; +} + +void QGesture::unsetHotSpot() +{ + d_func()->isHotSpotSet = false; +} + +/*! + \property QGesture::gestureCancelPolicy + \brief the policy for deciding what happens on accepting a gesture + + On accepting one gesture Qt can automatically cancel other gestures + that belong to other targets. The policy is normally set to not cancel + any other gestures and can be set to cancel all active gestures in the + context. For example for all child widgets. +*/ + +/*! + \enum QGesture::GestureCancelPolicy + + This enum describes how accepting a gesture can cancel other gestures + automatically. + + \value CancelNone On accepting this gesture no other gestures will be affected. + + \value CancelAllInContext On accepting this gesture all gestures that are + active in the context (respecting the Qt::GestureFlag that were specified + when subscribed to the gesture) will be cancelled. +*/ + +void QGesture::setGestureCancelPolicy(GestureCancelPolicy policy) +{ + Q_D(QGesture); + d->gestureCancelPolicy = static_cast(policy); +} + +QGesture::GestureCancelPolicy QGesture::gestureCancelPolicy() const +{ + Q_D(const QGesture); + return static_cast(d->gestureCancelPolicy); +} + +/*! + \class QPanGesture + \since 4.6 + \brief The QPanGesture class describes a panning gesture made by the user. + \ingroup gestures + + \image pangesture.png + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \sa QPinchGesture, QSwipeGesture +*/ + +/*! + \property QPanGesture::lastOffset + \brief the last offset recorded for this gesture + + The last offset contains the change in position of the user's input as + reported in the \l offset property when a previous gesture event was + delivered for this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains a zero size. +*/ + +/*! + \property QPanGesture::offset + \brief the total offset from the first input position to the current input + position + + The offset measures the total change in position of the user's input + covered by the gesture on the input device. +*/ + +/*! + \property QPanGesture::delta + \brief the offset from the previous input position to the current input + + This is essentially the same as the difference between offset() and + lastOffset(). +*/ + +/*! + \property QPanGesture::acceleration + \brief the acceleration in the motion of the touch point for this gesture +*/ + +/*! + \property QPanGesture::horizontalVelocity + \brief the horizontal component of the motion of the touch point for this + gesture + \since 4.7.1 + \internal + + \sa verticalVelocity, acceleration +*/ + +/*! + \property QPanGesture::verticalVelocity + \brief the vertical component of the motion of the touch point for this + gesture + \since 4.7.1 + \internal + + \sa horizontalVelocity, acceleration +*/ + +/*! + \internal +*/ +QPanGesture::QPanGesture(QObject *parent) + : QGesture(*new QPanGesturePrivate, parent) +{ + d_func()->gestureType = Qt::PanGesture; +} + + +QPointF QPanGesture::lastOffset() const +{ + return d_func()->lastOffset; +} + +QPointF QPanGesture::offset() const +{ + return d_func()->offset; +} + +QPointF QPanGesture::delta() const +{ + Q_D(const QPanGesture); + return d->offset - d->lastOffset; +} + +qreal QPanGesture::acceleration() const +{ + return d_func()->acceleration; +} + +void QPanGesture::setLastOffset(const QPointF &value) +{ + d_func()->lastOffset = value; +} + +void QPanGesture::setOffset(const QPointF &value) +{ + d_func()->offset = value; +} + +void QPanGesture::setAcceleration(qreal value) +{ + d_func()->acceleration = value; +} + +/*! + \class QPinchGesture + \since 4.6 + \brief The QPinchGesture class describes a pinch gesture made by the user. + \ingroup touch + \ingroup gestures + + A pinch gesture is a form of touch user input in which the user typically + touches two points on the input device with a thumb and finger, before moving + them closer together or further apart to change the scale factor, zoom, or level + of detail of the user interface. + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \image pinchgesture.png + + Instead of repeatedly applying the same pinching gesture, the user may + continue to touch the input device in one place, and apply a second touch + to a new point, continuing the gesture. When this occurs, gesture events + will continue to be delivered to the target object, containing an instance + of QPinchGesture in the Qt::GestureUpdated state. + + \sa QPanGesture, QSwipeGesture +*/ + +/*! + \enum QPinchGesture::ChangeFlag + + This enum describes the changes that can occur to the properties of + the gesture object. + + \value ScaleFactorChanged The scale factor held by scaleFactor changed. + \value RotationAngleChanged The rotation angle held by rotationAngle changed. + \value CenterPointChanged The center point held by centerPoint changed. + + \sa changeFlags, totalChangeFlags +*/ + +/*! + \property QPinchGesture::totalChangeFlags + \brief the property of the gesture that has change + + This property indicates which of the other properties has changed since the + gesture has started. You can use this information to determine which aspect + of your user interface needs to be updated. + + \sa changeFlags, scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::changeFlags + \brief the property of the gesture that has changed in the current step + + This property indicates which of the other properties has changed since + the previous gesture event included information about this gesture. You + can use this information to determine which aspect of your user interface + needs to be updated. + + \sa totalChangeFlags, scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::totalScaleFactor + \brief the total scale factor + + The total scale factor measures the total change in scale factor from the + original value to the current scale factor. + + \sa scaleFactor, lastScaleFactor +*/ +/*! + \property QPinchGesture::lastScaleFactor + \brief the last scale factor recorded for this gesture + + The last scale factor contains the scale factor reported in the + \l scaleFactor property when a previous gesture event included + information about this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains zero. + + \sa scaleFactor, totalScaleFactor +*/ +/*! + \property QPinchGesture::scaleFactor + \brief the current scale factor + + The scale factor measures the scale factor associated with the distance + between two of the user's inputs on a touch device. + + \sa totalScaleFactor, lastScaleFactor +*/ + +/*! + \property QPinchGesture::totalRotationAngle + \brief the total angle covered by the gesture + + This total angle measures the complete angle covered by the gesture. Usually, this + is equal to the value held by the \l rotationAngle property, except in the case where + the user performs multiple rotations by removing and repositioning one of the touch + points, as described above. In this case, the total angle will be the sum of the + rotation angles for the multiple stages of the gesture. + + \sa rotationAngle, lastRotationAngle +*/ +/*! + \property QPinchGesture::lastRotationAngle + \brief the last reported angle covered by the gesture motion + + The last rotation angle is the angle as reported in the \l rotationAngle property + when a previous gesture event was delivered for this gesture. + + \sa rotationAngle, totalRotationAngle +*/ +/*! + \property QPinchGesture::rotationAngle + \brief the angle covered by the gesture motion + + \sa totalRotationAngle, lastRotationAngle +*/ + +/*! + \property QPinchGesture::startCenterPoint + \brief the starting position of the center point + + \sa centerPoint, lastCenterPoint +*/ +/*! + \property QPinchGesture::lastCenterPoint + \brief the last position of the center point recorded for this gesture + + \sa centerPoint, startCenterPoint +*/ +/*! + \property QPinchGesture::centerPoint + \brief the current center point + + The center point is the midpoint between the two input points in the gesture. + + \sa startCenterPoint, lastCenterPoint +*/ + +/*! + \internal +*/ +QPinchGesture::QPinchGesture(QObject *parent) + : QGesture(*new QPinchGesturePrivate, parent) +{ + d_func()->gestureType = Qt::PinchGesture; +} + +QPinchGesture::ChangeFlags QPinchGesture::totalChangeFlags() const +{ + return d_func()->totalChangeFlags; +} + +void QPinchGesture::setTotalChangeFlags(QPinchGesture::ChangeFlags value) +{ + d_func()->totalChangeFlags = value; +} + +QPinchGesture::ChangeFlags QPinchGesture::changeFlags() const +{ + return d_func()->changeFlags; +} + +void QPinchGesture::setChangeFlags(QPinchGesture::ChangeFlags value) +{ + d_func()->changeFlags = value; +} + +QPointF QPinchGesture::startCenterPoint() const +{ + return d_func()->startCenterPoint; +} + +QPointF QPinchGesture::lastCenterPoint() const +{ + return d_func()->lastCenterPoint; +} + +QPointF QPinchGesture::centerPoint() const +{ + return d_func()->centerPoint; +} + +void QPinchGesture::setStartCenterPoint(const QPointF &value) +{ + d_func()->startCenterPoint = value; +} + +void QPinchGesture::setLastCenterPoint(const QPointF &value) +{ + d_func()->lastCenterPoint = value; +} + +void QPinchGesture::setCenterPoint(const QPointF &value) +{ + d_func()->centerPoint = value; +} + + +qreal QPinchGesture::totalScaleFactor() const +{ + return d_func()->totalScaleFactor; +} + +qreal QPinchGesture::lastScaleFactor() const +{ + return d_func()->lastScaleFactor; +} + +qreal QPinchGesture::scaleFactor() const +{ + return d_func()->scaleFactor; +} + +void QPinchGesture::setTotalScaleFactor(qreal value) +{ + d_func()->totalScaleFactor = value; +} + +void QPinchGesture::setLastScaleFactor(qreal value) +{ + d_func()->lastScaleFactor = value; +} + +void QPinchGesture::setScaleFactor(qreal value) +{ + d_func()->scaleFactor = value; +} + + +qreal QPinchGesture::totalRotationAngle() const +{ + return d_func()->totalRotationAngle; +} + +qreal QPinchGesture::lastRotationAngle() const +{ + return d_func()->lastRotationAngle; +} + +qreal QPinchGesture::rotationAngle() const +{ + return d_func()->rotationAngle; +} + +void QPinchGesture::setTotalRotationAngle(qreal value) +{ + d_func()->totalRotationAngle = value; +} + +void QPinchGesture::setLastRotationAngle(qreal value) +{ + d_func()->lastRotationAngle = value; +} + +void QPinchGesture::setRotationAngle(qreal value) +{ + d_func()->rotationAngle = value; +} + +/*! + \class QSwipeGesture + \since 4.6 + \brief The QSwipeGesture class describes a swipe gesture made by the user. + \ingroup gestures + + \image swipegesture.png + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \sa QPanGesture, QPinchGesture +*/ + +/*! + \enum QSwipeGesture::SwipeDirection + + This enum describes the possible directions for the gesture's motion + along the horizontal and vertical axes. + + \value NoDirection The gesture had no motion associated with it on a particular axis. + \value Left The gesture involved a horizontal motion to the left. + \value Right The gesture involved a horizontal motion to the right. + \value Up The gesture involved an upward vertical motion. + \value Down The gesture involved a downward vertical motion. +*/ + +/*! + \property QSwipeGesture::horizontalDirection + \brief the horizontal direction of the gesture + + If the gesture has a horizontal component, the horizontal direction + is either Left or Right; otherwise, it is NoDirection. + + \sa verticalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::verticalDirection + \brief the vertical direction of the gesture + + If the gesture has a vertical component, the vertical direction + is either Up or Down; otherwise, it is NoDirection. + + \sa horizontalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::swipeAngle + \brief the angle of the motion associated with the gesture + + If the gesture has either a horizontal or vertical component, the + swipe angle describes the angle between the direction of motion and the + x-axis as defined using the standard widget + \l{Coordinate System}{coordinate system}. + + \sa horizontalDirection, verticalDirection +*/ + +/*! + \property QSwipeGesture::velocity + \since 4.7.1 + \internal +*/ + +/*! + \internal +*/ +QSwipeGesture::QSwipeGesture(QObject *parent) + : QGesture(*new QSwipeGesturePrivate, parent) +{ + d_func()->gestureType = Qt::SwipeGesture; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 90 || d->swipeAngle > 270) + return QSwipeGesture::Right; + else + return QSwipeGesture::Left; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle <= 0 || d->swipeAngle == 180) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 180) + return QSwipeGesture::Up; + else + return QSwipeGesture::Down; +} + +qreal QSwipeGesture::swipeAngle() const +{ + return d_func()->swipeAngle; +} + +void QSwipeGesture::setSwipeAngle(qreal value) +{ + d_func()->swipeAngle = value; +} + +/*! + \class QTapGesture + \since 4.6 + \brief The QTapGesture class describes a tap gesture made by the user. + \ingroup gestures + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \sa QPanGesture, QPinchGesture +*/ + +/*! + \property QTapGesture::position + \brief the position of the tap +*/ + +/*! + \internal +*/ +QTapGesture::QTapGesture(QObject *parent) + : QGesture(*new QTapGesturePrivate, parent) +{ + d_func()->gestureType = Qt::TapGesture; +} + +QPointF QTapGesture::position() const +{ + return d_func()->position; +} + +void QTapGesture::setPosition(const QPointF &value) +{ + d_func()->position = value; +} +/*! + \class QTapAndHoldGesture + \since 4.6 + \brief The QTapAndHoldGesture class describes a tap-and-hold (aka LongTap) + gesture made by the user. + \ingroup gestures + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \sa QPanGesture, QPinchGesture +*/ + +/*! + \property QTapAndHoldGesture::position + \brief the position of the tap +*/ + +/*! + \internal +*/ +QTapAndHoldGesture::QTapAndHoldGesture(QObject *parent) + : QGesture(*new QTapAndHoldGesturePrivate, parent) +{ + d_func()->gestureType = Qt::TapAndHoldGesture; +} + +QPointF QTapAndHoldGesture::position() const +{ + return d_func()->position; +} + +void QTapAndHoldGesture::setPosition(const QPointF &value) +{ + d_func()->position = value; +} + +/*! + Set the timeout, in milliseconds, before the gesture triggers. + + The recognizer will detect a touch down and and if \a msecs + later the touch is still down, it will trigger the QTapAndHoldGesture. + The default value is 700 milliseconds. +*/ +// static +void QTapAndHoldGesture::setTimeout(int msecs) +{ + QTapAndHoldGesturePrivate::Timeout = msecs; +} + +/*! + Gets the timeout, in milliseconds, before the gesture triggers. + + The recognizer will detect a touch down and and if timeout() + later the touch is still down, it will trigger the QTapAndHoldGesture. + The default value is 700 milliseconds. +*/ +// static +int QTapAndHoldGesture::timeout() +{ + return QTapAndHoldGesturePrivate::Timeout; +} + +int QTapAndHoldGesturePrivate::Timeout = 700; // in ms + + +/*! + \class QGestureEvent + \since 4.6 + \ingroup events + \ingroup gestures + + \brief The QGestureEvent class provides the description of triggered gestures. + + The QGestureEvent class contains a list of gestures, which can be obtained using the + gestures() function. + + The gestures are either active or canceled. A list of those that are currently being + executed can be obtained using the activeGestures() function. A list of those which + were previously active and have been canceled can be accessed using the + canceledGestures() function. A gesture might be canceled if the current window loses + focus, for example, or because of a timeout, or for other reasons. + + If the event handler does not accept the event by calling the generic + QEvent::accept() function, all individual QGesture object that were not + accepted and in the Qt::GestureStarted state will be propagated up the + parent widget chain until a widget accepts them individually, by calling + QGestureEvent::accept() for each of them, or an event filter consumes the + event. + + \section1 Further Reading + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \sa QGesture, QGestureRecognizer, + QWidget::grabGesture(), QGraphicsObject::grabGesture() +*/ + +/*! + Creates new QGestureEvent containing a list of \a gestures. +*/ +QGestureEvent::QGestureEvent(const QList &gestures) + : QEvent(QEvent::Gesture) +{ + d = reinterpret_cast(new QGestureEventPrivate(gestures)); +} + +/*! + Destroys QGestureEvent. +*/ +QGestureEvent::~QGestureEvent() +{ + delete reinterpret_cast(d); +} + +/*! + Returns all gestures that are delivered in the event. +*/ +QList QGestureEvent::gestures() const +{ + return d_func()->gestures; +} + +/*! + Returns a gesture object by \a type. +*/ +QGesture *QGestureEvent::gesture(Qt::GestureType type) const +{ + const QGestureEventPrivate *d = d_func(); + for(int i = 0; i < d->gestures.size(); ++i) + if (d->gestures.at(i)->gestureType() == type) + return d->gestures.at(i); + return 0; +} + +/*! + Returns a list of active (not canceled) gestures. +*/ +QList QGestureEvent::activeGestures() const +{ + QList gestures; + foreach (QGesture *gesture, d_func()->gestures) { + if (gesture->state() != Qt::GestureCanceled) + gestures.append(gesture); + } + return gestures; +} + +/*! + Returns a list of canceled gestures. +*/ +QList QGestureEvent::canceledGestures() const +{ + QList gestures; + foreach (QGesture *gesture, d_func()->gestures) { + if (gesture->state() == Qt::GestureCanceled) + gestures.append(gesture); + } + return gestures; +} + +/*! + Sets the accept flag of the given \a gesture object to the specified \a value. + + Setting the accept flag indicates that the event receiver wants the \a gesture. + Unwanted gestures may be propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gesture)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gesture)}. +*/ +void QGestureEvent::setAccepted(QGesture *gesture, bool value) +{ + if (gesture) + setAccepted(gesture->gestureType(), value); +} + +/*! + Sets the accept flag of the given \a gesture object, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gesture, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(QGesture *gesture) +{ + if (gesture) + setAccepted(gesture->gestureType(), true); +} + +/*! + Clears the accept flag parameter of the given \a gesture object, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(QGesture *gesture) +{ + if (gesture) + setAccepted(gesture->gestureType(), false); +} + +/*! + Returns true if the \a gesture is accepted; otherwise returns false. +*/ +bool QGestureEvent::isAccepted(QGesture *gesture) const +{ + return gesture ? isAccepted(gesture->gestureType()) : false; +} + +/*! + Sets the accept flag of the given \a gestureType object to the specified + \a value. + + Setting the accept flag indicates that the event receiver wants to receive + gestures of the specified type, \a gestureType. Unwanted gestures may be + propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gestureType)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gestureType)}. +*/ +void QGestureEvent::setAccepted(Qt::GestureType gestureType, bool value) +{ + setAccepted(false); + d_func()->accepted[gestureType] = value; +} + +/*! + Sets the accept flag of the given \a gestureType, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gestureType, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(Qt::GestureType gestureType) +{ + setAccepted(gestureType, true); +} + +/*! + Clears the accept flag parameter of the given \a gestureType, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propgated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(Qt::GestureType gestureType) +{ + setAccepted(gestureType, false); +} + +/*! + Returns true if the gesture of type \a gestureType is accepted; otherwise + returns false. +*/ +bool QGestureEvent::isAccepted(Qt::GestureType gestureType) const +{ + return d_func()->accepted.value(gestureType, true); +} + +/*! + \internal + + Sets the widget for this event to the \a widget specified. +*/ +void QGestureEvent::setWidget(QWidget *widget) +{ + d_func()->widget = widget; +} + +/*! + Returns the widget on which the event occurred. +*/ +QWidget *QGestureEvent::widget() const +{ + return d_func()->widget; +} + +#ifndef QT_NO_GRAPHICSVIEW +/*! + Returns the scene-local coordinates if the \a gesturePoint is inside a + graphics view. + + This functional might be useful when the gesture event is delivered to a + QGraphicsObject to translate a point in screen coordinates to scene-local + coordinates. + + \sa QPointF::isNull(). +*/ +QPointF QGestureEvent::mapToGraphicsScene(const QPointF &gesturePoint) const +{ + QWidget *w = widget(); + if (w) // we get the viewport as widget, not the graphics view + w = w->parentWidget(); + QGraphicsView *view = qobject_cast(w); + if (view) { + return view->mapToScene(view->mapFromGlobal(gesturePoint.toPoint())); + } + return QPointF(); +} +#endif //QT_NO_GRAPHICSVIEW + +/*! + \internal +*/ +QGestureEventPrivate *QGestureEvent::d_func() +{ + return reinterpret_cast(d); +} + +/*! + \internal +*/ +const QGestureEventPrivate *QGestureEvent::d_func() const +{ + return reinterpret_cast(d); +} + +#ifdef Q_NO_USING_KEYWORD +/*! + \fn void QGestureEvent::setAccepted(bool accepted) + + Sets or clears the event's internal flag that determines whether it should + be delivered to other objects. + + Calling this function with a value of true for \a accepted indicates that the + caller has accepted the event and that it should not be propagated further. + Calling this function with a value of false indicates that the caller has + ignored the event and that it should be delivered to other objects. + + For convenience, the accept flag can also be set with accept(), and cleared + with ignore(). + + \sa QEvent::accepted +*/ +/*! + \fn bool QGestureEvent::isAccepted() const + + Returns true is the event has been accepted; otherwise returns false. + + \sa QEvent::accepted +*/ +/*! + \fn void QGestureEvent::accept() + + Accepts the event, the equivalent of calling setAccepted(true). + + \sa QEvent::accept() +*/ +/*! + \fn void QGestureEvent::ignore() + + Ignores the event, the equivalent of calling setAccepted(false). + + \sa QEvent::ignore() +*/ +#endif + +QT_END_NAMESPACE + +#include + +#endif // QT_NO_GESTURES diff --git a/src/widgets/kernel/qgesture.h b/src/widgets/kernel/qgesture.h new file mode 100644 index 0000000000..78fd2e47f1 --- /dev/null +++ b/src/widgets/kernel/qgesture.h @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_H +#define QGESTURE_H + +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_GESTURES + +QT_BEGIN_HEADER + +Q_DECLARE_METATYPE(Qt::GestureState) +Q_DECLARE_METATYPE(Qt::GestureType) + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QGesturePrivate; +class Q_GUI_EXPORT QGesture : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGesture) + + Q_PROPERTY(Qt::GestureState state READ state) + Q_PROPERTY(Qt::GestureType gestureType READ gestureType) + Q_PROPERTY(QGesture::GestureCancelPolicy gestureCancelPolicy READ gestureCancelPolicy WRITE setGestureCancelPolicy) + Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) + Q_PROPERTY(bool hasHotSpot READ hasHotSpot) + +public: + explicit QGesture(QObject *parent = 0); + ~QGesture(); + + Qt::GestureType gestureType() const; + + Qt::GestureState state() const; + + QPointF hotSpot() const; + void setHotSpot(const QPointF &value); + bool hasHotSpot() const; + void unsetHotSpot(); + + enum GestureCancelPolicy { + CancelNone = 0, + CancelAllInContext + }; + + void setGestureCancelPolicy(GestureCancelPolicy policy); + GestureCancelPolicy gestureCancelPolicy() const; + +protected: + QGesture(QGesturePrivate &dd, QObject *parent); + +private: + friend class QGestureEvent; + friend class QGestureRecognizer; + friend class QGestureManager; + friend class QGraphicsScenePrivate; +}; + +class QPanGesturePrivate; +class Q_GUI_EXPORT QPanGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPanGesture) + + Q_PROPERTY(QPointF lastOffset READ lastOffset WRITE setLastOffset) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) + Q_PROPERTY(QPointF delta READ delta STORED false) + Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration) + Q_PRIVATE_PROPERTY(QPanGesture::d_func(), qreal horizontalVelocity READ horizontalVelocity WRITE setHorizontalVelocity) + Q_PRIVATE_PROPERTY(QPanGesture::d_func(), qreal verticalVelocity READ verticalVelocity WRITE setVerticalVelocity) + +public: + QPanGesture(QObject *parent = 0); + + QPointF lastOffset() const; + QPointF offset() const; + QPointF delta() const; + qreal acceleration() const; + + void setLastOffset(const QPointF &value); + void setOffset(const QPointF &value); + void setAcceleration(qreal value); + + friend class QPanGestureRecognizer; + friend class QWinNativePanGestureRecognizer; +}; + +class QPinchGesturePrivate; +class Q_GUI_EXPORT QPinchGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPinchGesture) + Q_FLAGS(ChangeFlags ChangeFlag) + +public: + enum ChangeFlag { + ScaleFactorChanged = 0x1, + RotationAngleChanged = 0x2, + CenterPointChanged = 0x4 + }; + Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag) + + Q_PROPERTY(ChangeFlags totalChangeFlags READ totalChangeFlags WRITE setTotalChangeFlags) + Q_PROPERTY(ChangeFlags changeFlags READ changeFlags WRITE setChangeFlags) + + Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor WRITE setTotalScaleFactor) + Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor WRITE setLastScaleFactor) + Q_PROPERTY(qreal scaleFactor READ scaleFactor WRITE setScaleFactor) + + Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle WRITE setTotalRotationAngle) + Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle WRITE setLastRotationAngle) + Q_PROPERTY(qreal rotationAngle READ rotationAngle WRITE setRotationAngle) + + Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint WRITE setStartCenterPoint) + Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint WRITE setLastCenterPoint) + Q_PROPERTY(QPointF centerPoint READ centerPoint WRITE setCenterPoint) + +public: + QPinchGesture(QObject *parent = 0); + + ChangeFlags totalChangeFlags() const; + void setTotalChangeFlags(ChangeFlags value); + + ChangeFlags changeFlags() const; + void setChangeFlags(ChangeFlags value); + + QPointF startCenterPoint() const; + QPointF lastCenterPoint() const; + QPointF centerPoint() const; + void setStartCenterPoint(const QPointF &value); + void setLastCenterPoint(const QPointF &value); + void setCenterPoint(const QPointF &value); + + qreal totalScaleFactor() const; + qreal lastScaleFactor() const; + qreal scaleFactor() const; + void setTotalScaleFactor(qreal value); + void setLastScaleFactor(qreal value); + void setScaleFactor(qreal value); + + qreal totalRotationAngle() const; + qreal lastRotationAngle() const; + qreal rotationAngle() const; + void setTotalRotationAngle(qreal value); + void setLastRotationAngle(qreal value); + void setRotationAngle(qreal value); + + friend class QPinchGestureRecognizer; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QPinchGesture::ChangeFlags) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPinchGesture::ChangeFlags) + +QT_BEGIN_NAMESPACE + +class QSwipeGesturePrivate; +class Q_GUI_EXPORT QSwipeGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSwipeGesture) + Q_ENUMS(SwipeDirection) + + Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection STORED false) + Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection STORED false) + Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle) + Q_PRIVATE_PROPERTY(QSwipeGesture::d_func(), qreal velocity READ velocity WRITE setVelocity) + +public: + enum SwipeDirection { NoDirection, Left, Right, Up, Down }; + QSwipeGesture(QObject *parent = 0); + + SwipeDirection horizontalDirection() const; + SwipeDirection verticalDirection() const; + + qreal swipeAngle() const; + void setSwipeAngle(qreal value); + + friend class QSwipeGestureRecognizer; +}; + +class QTapGesturePrivate; +class Q_GUI_EXPORT QTapGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTapGesture) + + Q_PROPERTY(QPointF position READ position WRITE setPosition) + +public: + QTapGesture(QObject *parent = 0); + + QPointF position() const; + void setPosition(const QPointF &pos); + + friend class QTapGestureRecognizer; +}; + +class QTapAndHoldGesturePrivate; +class Q_GUI_EXPORT QTapAndHoldGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTapAndHoldGesture) + + Q_PROPERTY(QPointF position READ position WRITE setPosition) + +public: + QTapAndHoldGesture(QObject *parent = 0); + + QPointF position() const; + void setPosition(const QPointF &pos); + + static void setTimeout(int msecs); + static int timeout(); + + friend class QTapAndHoldGestureRecognizer; +}; + +class QGesture; +class QGestureEventPrivate; +class Q_GUI_EXPORT QGestureEvent : public QEvent +{ +public: + QGestureEvent(const QList &gestures); + ~QGestureEvent(); + + QList gestures() const; + QGesture *gesture(Qt::GestureType type) const; + + QList activeGestures() const; + QList canceledGestures() const; + +#ifdef Q_NO_USING_KEYWORD + inline void setAccepted(bool accepted) { QEvent::setAccepted(accepted); } + inline bool isAccepted() const { return QEvent::isAccepted(); } + + inline void accept() { QEvent::accept(); } + inline void ignore() { QEvent::ignore(); } +#else + using QEvent::setAccepted; + using QEvent::isAccepted; + using QEvent::accept; + using QEvent::ignore; +#endif + + void setAccepted(QGesture *, bool); + void accept(QGesture *); + void ignore(QGesture *); + bool isAccepted(QGesture *) const; + + void setAccepted(Qt::GestureType, bool); + void accept(Qt::GestureType); + void ignore(Qt::GestureType); + bool isAccepted(Qt::GestureType) const; + + void setWidget(QWidget *widget); + QWidget *widget() const; + +#ifndef QT_NO_GRAPHICSVIEW + QPointF mapToGraphicsScene(const QPointF &gesturePoint) const; +#endif + +private: + QGestureEventPrivate *d_func(); + const QGestureEventPrivate *d_func() const; + + friend class QApplication; + friend class QGestureManager; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QGesture::GestureCancelPolicy) +QT_END_HEADER + +#endif // QT_NO_GESTURES + +#endif // QGESTURE_H diff --git a/src/widgets/kernel/qgesture_p.h b/src/widgets/kernel/qgesture_p.h new file mode 100644 index 0000000000..9dd089cc9e --- /dev/null +++ b/src/widgets/kernel/qgesture_p.h @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_P_H +#define QGESTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrect.h" +#include "qpoint.h" +#include "qgesture.h" +#include "qelapsedtimer.h" +#include "private/qobject_p.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +class QGesturePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGesture) + +public: + QGesturePrivate() + : gestureType(Qt::CustomGesture), state(Qt::NoGesture), + isHotSpotSet(false), gestureCancelPolicy(0) + { + } + + Qt::GestureType gestureType; + Qt::GestureState state; + QPointF hotSpot; + QPointF sceneHotSpot; + uint isHotSpotSet : 1; + uint gestureCancelPolicy : 2; +}; + +class QPanGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPanGesture) + +public: + QPanGesturePrivate() + : acceleration(0), xVelocity(0), yVelocity(0) + { + } + + qreal horizontalVelocity() const { return xVelocity; } + void setHorizontalVelocity(qreal value) { xVelocity = value; } + qreal verticalVelocity() const { return yVelocity; } + void setVerticalVelocity(qreal value) { yVelocity = value; } + + QPointF lastOffset; + QPointF offset; + QPoint startPosition; + qreal acceleration; + qreal xVelocity; + qreal yVelocity; +}; + +class QPinchGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPinchGesture) + +public: + QPinchGesturePrivate() + : totalChangeFlags(0), changeFlags(0), + totalScaleFactor(1), lastScaleFactor(1), scaleFactor(1), + totalRotationAngle(0), lastRotationAngle(0), rotationAngle(0), + isNewSequence(true) + { + } + + QPinchGesture::ChangeFlags totalChangeFlags; + QPinchGesture::ChangeFlags changeFlags; + + QPointF startCenterPoint; + QPointF lastCenterPoint; + QPointF centerPoint; + + qreal totalScaleFactor; + qreal lastScaleFactor; + qreal scaleFactor; + + qreal totalRotationAngle; + qreal lastRotationAngle; + qreal rotationAngle; + + bool isNewSequence; + QPointF startPosition[2]; +}; + +class QSwipeGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QSwipeGesture) + +public: + QSwipeGesturePrivate() + : horizontalDirection(QSwipeGesture::NoDirection), + verticalDirection(QSwipeGesture::NoDirection), + swipeAngle(0), + started(false), velocityValue(0) + { + } + + qreal velocity() const { return velocityValue; } + void setVelocity(qreal value) { velocityValue = value; } + + QSwipeGesture::SwipeDirection horizontalDirection; + QSwipeGesture::SwipeDirection verticalDirection; + qreal swipeAngle; + + QPoint lastPositions[3]; + bool started; + qreal velocityValue; + QElapsedTimer time; +}; + +class QTapGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QTapGesture) + +public: + QTapGesturePrivate() + { + } + + QPointF position; +}; + +class QTapAndHoldGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QTapAndHoldGesture) + +public: + QTapAndHoldGesturePrivate() + : timerId(0) + { + } + + QPointF position; + int timerId; + static int Timeout; +}; + +#ifndef QT_NO_GESTURES +class QNativeGestureEvent : public QEvent +{ +public: + enum Type { + None, + GestureBegin, + GestureEnd, + Pan, + Zoom, + Rotate, + Swipe + }; + + QNativeGestureEvent() + : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0) +#ifdef Q_WS_WIN + , sequenceId(0), argument(0) +#endif + { + } + + Type gestureType; + float percentage; + QPoint position; + float angle; +#ifdef Q_WS_WIN + ulong sequenceId; + quint64 argument; +#endif +}; + +class QGestureEventPrivate +{ +public: + inline QGestureEventPrivate(const QList &list) + : gestures(list), widget(0) + { + } + + QList gestures; + QWidget *widget; + QMap accepted; + QMap targetWidgets; +}; +#endif // QT_NO_GESTURES + + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES + +#endif // QGESTURE_P_H diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp new file mode 100644 index 0000000000..5359fb37e8 --- /dev/null +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qgesturemanager_p.h" +#include "private/qstandardgestures_p.h" +#include "private/qwidget_p.h" +#include "private/qgesture_p.h" +#include "private/qgraphicsitem_p.h" +#include "private/qevent_p.h" +#include "private/qapplication_p.h" +#include "qgesture.h" +#include "qevent.h" +#include "qgraphicsitem.h" + +#ifdef Q_WS_MAC +#include "qmacgesturerecognizer_mac_p.h" +#endif +#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES) +#include "qwinnativepangesturerecognizer_win_p.h" +#endif + +#include "qdebug.h" + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +QGestureManager::QGestureManager(QObject *parent) + : QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture) +{ + qRegisterMetaType(); + +#if defined(Q_WS_MAC) + registerGestureRecognizer(new QMacSwipeGestureRecognizer); + registerGestureRecognizer(new QMacPinchGestureRecognizer); + #if defined(QT_MAC_USE_COCOA) + registerGestureRecognizer(new QMacPanGestureRecognizer); + #endif +#else + registerGestureRecognizer(new QPanGestureRecognizer); + registerGestureRecognizer(new QPinchGestureRecognizer); + registerGestureRecognizer(new QSwipeGestureRecognizer); + registerGestureRecognizer(new QTapGestureRecognizer); +#endif +#if defined(Q_OS_WIN) + #if !defined(QT_NO_NATIVE_GESTURES) + if (QApplicationPrivate::HasTouchSupport) + registerGestureRecognizer(new QWinNativePanGestureRecognizer); + #endif +#else + registerGestureRecognizer(new QTapAndHoldGestureRecognizer); +#endif +} + +QGestureManager::~QGestureManager() +{ + qDeleteAll(m_recognizers.values()); + foreach (QGestureRecognizer *recognizer, m_obsoleteGestures.keys()) { + qDeleteAll(m_obsoleteGestures.value(recognizer)); + delete recognizer; + } + m_obsoleteGestures.clear(); +} + +Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + QGesture *dummy = recognizer->create(0); + if (!dummy) { + qWarning("QGestureManager::registerGestureRecognizer: " + "the recognizer fails to create a gesture object, skipping registration."); + return Qt::GestureType(0); + } + Qt::GestureType type = dummy->gestureType(); + if (type == Qt::CustomGesture) { + // generate a new custom gesture id + ++m_lastCustomGestureId; + type = Qt::GestureType(m_lastCustomGestureId); + } + m_recognizers.insertMulti(type, recognizer); + delete dummy; + return type; +} + +void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type) +{ + QList list = m_recognizers.values(type); + while (QGestureRecognizer *recognizer = m_recognizers.take(type)) { + if (!m_obsoleteGestures.contains(recognizer)) { + // inserting even an empty QSet will cause the recognizer to be deleted on destruction of the manager + m_obsoleteGestures.insert(recognizer, QSet()); + } + } + foreach (QGesture *g, m_gestureToRecognizer.keys()) { + QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g); + if (list.contains(recognizer)) { + m_deletedRecognizers.insert(g, recognizer); + } + } + + QMap >::const_iterator iter = m_objectGestures.begin(); + while (iter != m_objectGestures.end()) { + ObjectGesture objectGesture = iter.key(); + if (objectGesture.gesture == type) { + foreach (QGesture *g, iter.value()) { + if (QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g)) { + m_gestureToRecognizer.remove(g); + m_obsoleteGestures[recognizer].insert(g); + } + } + } + ++iter; + } +} + +void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type) +{ + QMap >::Iterator iter = m_objectGestures.begin(); + while (iter != m_objectGestures.end()) { + ObjectGesture objectGesture = iter.key(); + if (objectGesture.gesture == type && target == objectGesture.object) { + QSet gestures = iter.value().toSet(); + for (QHash >::iterator + it = m_obsoleteGestures.begin(), e = m_obsoleteGestures.end(); it != e; ++it) { + it.value() -= gestures; + } + foreach (QGesture *g, gestures) { + m_deletedRecognizers.remove(g); + m_gestureToRecognizer.remove(g); + m_maybeGestures.remove(g); + m_activeGestures.remove(g); + m_gestureOwners.remove(g); + m_gestureTargets.remove(g); + m_gesturesToDelete.insert(g); + } + + iter = m_objectGestures.erase(iter); + } else { + ++iter; + } + } +} + +// get or create a QGesture object that will represent the state for a given object, used by the recognizer +QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type) +{ + // if the widget is being deleted we should be careful not to + // create a new state, as it will create QWeakPointer which doesn't work + // from the destructor. + if (object->isWidgetType()) { + if (static_cast(object)->d_func()->data.in_destructor) + return 0; + } else if (QGesture *g = qobject_cast(object)) { + return g; +#ifndef QT_NO_GRAPHICSVIEW + } else { + Q_ASSERT(qobject_cast(object)); + QGraphicsObject *graphicsObject = static_cast(object); + if (graphicsObject->QGraphicsItem::d_func()->inDestructor) + return 0; +#endif + } + + // check if the QGesture for this recognizer has already been created + foreach (QGesture *state, m_objectGestures.value(QGestureManager::ObjectGesture(object, type))) { + if (m_gestureToRecognizer.value(state) == recognizer) + return state; + } + + Q_ASSERT(recognizer); + QGesture *state = recognizer->create(object); + if (!state) + return 0; + state->setParent(this); + if (state->gestureType() == Qt::CustomGesture) { + // if the recognizer didn't fill in the gesture type, then this + // is a custom gesture with autogenerated id and we fill it. + state->d_func()->gestureType = type; +#if defined(GESTURE_DEBUG) + state->setObjectName(QString::number((int)type)); +#endif + } + m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state); + m_gestureToRecognizer[state] = recognizer; + m_gestureOwners[state] = object; + + return state; +} + +bool QGestureManager::filterEventThroughContexts(const QMultiMap &contexts, + QEvent *event) +{ + QSet triggeredGestures; + QSet finishedGestures; + QSet newMaybeGestures; + QSet notGestures; + + // TODO: sort contexts by the gesture type and check if one of the contexts + // is already active. + + bool consumeEventHint = false; + + // filter the event through recognizers + typedef QMultiMap::const_iterator ContextIterator; + ContextIterator contextEnd = contexts.end(); + for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) { + Qt::GestureType gestureType = context.value(); + QMap::const_iterator + typeToRecognizerIterator = m_recognizers.lowerBound(gestureType), + typeToRecognizerEnd = m_recognizers.upperBound(gestureType); + for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) { + QGestureRecognizer *recognizer = typeToRecognizerIterator.value(); + QObject *target = context.key(); + QGesture *state = getState(target, recognizer, gestureType); + if (!state) + continue; + QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event); + QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask; + QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask; + if (recognizerState == QGestureRecognizer::TriggerGesture) { + DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state; + triggeredGestures << state; + } else if (recognizerState == QGestureRecognizer::FinishGesture) { + DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state; + finishedGestures << state; + } else if (recognizerState == QGestureRecognizer::MayBeGesture) { + DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state; + newMaybeGestures << state; + } else if (recognizerState == QGestureRecognizer::CancelGesture) { + DEBUG() << "QGestureManager:Recognizer: not gesture: " << state; + notGestures << state; + } else if (recognizerState == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state; + } else { + DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer" + << "ignored the event: " << state; + } + if (resultHint & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " + << state; + consumeEventHint = true; + } + } + } + if (triggeredGestures.isEmpty() && finishedGestures.isEmpty() + && newMaybeGestures.isEmpty() && notGestures.isEmpty()) + return consumeEventHint; + + QSet startedGestures = triggeredGestures - m_activeGestures; + triggeredGestures &= m_activeGestures; + + // check if a running gesture switched back to maybe state + QSet activeToMaybeGestures = m_activeGestures & newMaybeGestures; + + // check if a maybe gesture switched to canceled - reset it but don't send an event + QSet maybeToCanceledGestures = m_maybeGestures & notGestures; + + // check if a running gesture switched back to not gesture state, + // i.e. were canceled + QSet canceledGestures = m_activeGestures & notGestures; + + // new gestures in maybe state + m_maybeGestures += newMaybeGestures; + + // gestures that were in maybe state + QSet notMaybeGestures = (startedGestures | triggeredGestures + | finishedGestures | canceledGestures + | notGestures); + m_maybeGestures -= notMaybeGestures; + + Q_ASSERT((startedGestures & finishedGestures).isEmpty()); + Q_ASSERT((startedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((startedGestures & canceledGestures).isEmpty()); + Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((finishedGestures & canceledGestures).isEmpty()); + Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty()); + + QSet notStarted = finishedGestures - m_activeGestures; + if (!notStarted.isEmpty()) { + // there are some gestures that claim to be finished, but never started. + // probably those are "singleshot" gestures so we'll fake the started state. + foreach (QGesture *gesture, notStarted) + gesture->d_func()->state = Qt::GestureStarted; + QSet undeliveredGestures; + deliverEvents(notStarted, &undeliveredGestures); + finishedGestures -= undeliveredGestures; + } + + m_activeGestures += startedGestures; + // sanity check: all triggered gestures should already be in active gestures list + Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size()); + m_activeGestures -= finishedGestures; + m_activeGestures -= activeToMaybeGestures; + m_activeGestures -= canceledGestures; + + // set the proper gesture state on each gesture + foreach (QGesture *gesture, startedGestures) + gesture->d_func()->state = Qt::GestureStarted; + foreach (QGesture *gesture, triggeredGestures) + gesture->d_func()->state = Qt::GestureUpdated; + foreach (QGesture *gesture, finishedGestures) + gesture->d_func()->state = Qt::GestureFinished; + foreach (QGesture *gesture, canceledGestures) + gesture->d_func()->state = Qt::GestureCanceled; + foreach (QGesture *gesture, activeToMaybeGestures) + gesture->d_func()->state = Qt::GestureFinished; + + if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() || + !startedGestures.isEmpty() || !triggeredGestures.isEmpty() || + !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) { + DEBUG() << "QGestureManager::filterEventThroughContexts:" + << "\n\tactiveGestures:" << m_activeGestures + << "\n\tmaybeGestures:" << m_maybeGestures + << "\n\tstarted:" << startedGestures + << "\n\ttriggered:" << triggeredGestures + << "\n\tfinished:" << finishedGestures + << "\n\tcanceled:" << canceledGestures + << "\n\tmaybe-canceled:" << maybeToCanceledGestures; + } + + QSet undeliveredGestures; + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, + &undeliveredGestures); + + foreach (QGesture *g, startedGestures) { + if (undeliveredGestures.contains(g)) + continue; + if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { + DEBUG() << "lets try to cancel some"; + // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them + cancelGesturesForChildren(g); + } + } + + m_activeGestures -= undeliveredGestures; + + // reset gestures that ended + QSet endedGestures = + finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures; + foreach (QGesture *gesture, endedGestures) { + recycle(gesture); + m_gestureTargets.remove(gesture); + } + + //Clean up the Gestures + qDeleteAll(m_gesturesToDelete); + m_gesturesToDelete.clear(); + + return consumeEventHint; +} + +// Cancel all gestures of children of the widget that original is associated with +void QGestureManager::cancelGesturesForChildren(QGesture *original) +{ + Q_ASSERT(original); + QWidget *originatingWidget = m_gestureTargets.value(original); + Q_ASSERT(originatingWidget); + + // iterate over all active gestures and all maybe gestures + // for each find the owner + // if the owner is part of our sub-hierarchy, cancel it. + + QSet cancelledGestures; + QSet::Iterator iter = m_activeGestures.begin(); + while (iter != m_activeGestures.end()) { + QWidget *widget = m_gestureTargets.value(*iter); + // note that we don't touch the gestures for our originatingWidget + if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) { + DEBUG() << " found a gesture to cancel" << (*iter); + (*iter)->d_func()->state = Qt::GestureCanceled; + cancelledGestures << *iter; + iter = m_activeGestures.erase(iter); + } else { + ++iter; + } + } + + // TODO handle 'maybe' gestures too + + // sort them per target widget by cherry picking from almostCanceledGestures and delivering + QSet almostCanceledGestures = cancelledGestures; + while (!almostCanceledGestures.isEmpty()) { + QWidget *target = 0; + QSet gestures; + iter = almostCanceledGestures.begin(); + // sort per target widget + while (iter != almostCanceledGestures.end()) { + QWidget *widget = m_gestureTargets.value(*iter); + if (target == 0) + target = widget; + if (target == widget) { + gestures << *iter; + iter = almostCanceledGestures.erase(iter); + } else { + ++iter; + } + } + Q_ASSERT(target); + + QSet undeliveredGestures; + deliverEvents(gestures, &undeliveredGestures); + } + + for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter) + recycle(*iter); +} + +void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture) +{ + QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture); + if(!recognizer) //The Gesture is removed while in the even loop, so the recognizers for this gestures was removed + return; + m_deletedRecognizers.remove(gesture); + if (m_deletedRecognizers.keys(recognizer).isEmpty()) { + // no more active gestures, cleanup! + qDeleteAll(m_obsoleteGestures.value(recognizer)); + m_obsoleteGestures.remove(recognizer); + delete recognizer; + } +} + +// return true if accepted (consumed) +bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) +{ + QMap types; + QMultiMap contexts; + QWidget *w = receiver; + typedef QMap::const_iterator ContextIterator; + if (!w->d_func()->gestureContext.isEmpty()) { + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key(), 0); + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->isWindow() ? 0 : w->parentWidget(); + while (w) + { + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (!(it.value() & Qt::DontStartGestureOnChildren)) { + if (!types.contains(it.key())) { + types.insert(it.key(), 0); + contexts.insertMulti(w, it.key()); + } + } + } + if (w->isWindow()) + break; + w = w->parentWidget(); + } + return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); +} + +#ifndef QT_NO_GRAPHICSVIEW +bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) +{ + QMap types; + QMultiMap contexts; + QGraphicsObject *item = receiver; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key(), 0); + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the graphics object tree + item = item->parentObject(); + while (item) + { + typedef QMap::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (!(it.value() & Qt::DontStartGestureOnChildren)) { + if (!types.contains(it.key())) { + types.insert(it.key(), 0); + contexts.insertMulti(item, it.key()); + } + } + } + item = item->parentObject(); + } + return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); +} +#endif + +bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) +{ + if (!m_gestureToRecognizer.contains(static_cast(receiver))) + return false; + QGesture *state = static_cast(receiver); + QMultiMap contexts; + contexts.insert(state, state->gestureType()); + return filterEventThroughContexts(contexts, event); +} + +void QGestureManager::getGestureTargets(const QSet &gestures, + QMap > *conflicts, + QMap > *normal) +{ + typedef QHash > GestureByTypes; + GestureByTypes gestureByTypes; + + // sort gestures by types + foreach (QGesture *gesture, gestures) { + QWidget *receiver = m_gestureTargets.value(gesture, 0); + Q_ASSERT(receiver); + gestureByTypes[gesture->gestureType()].insert(receiver, gesture); + } + + // for each gesture type + foreach (Qt::GestureType type, gestureByTypes.keys()) { + QHash gestures = gestureByTypes.value(type); + foreach (QWidget *widget, gestures.keys()) { + QWidget *w = widget->parentWidget(); + while (w) { + QMap::const_iterator it + = w->d_func()->gestureContext.find(type); + if (it != w->d_func()->gestureContext.end()) { + // i.e. 'w' listens to gesture 'type' + Qt::GestureFlags flags = it.value(); + if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) { + // conflicting gesture! + (*conflicts)[widget].append(gestures[widget]); + break; + } + } + if (w->isWindow()) { + w = 0; + break; + } + w = w->parentWidget(); + } + if (!w) + (*normal)[widget].append(gestures[widget]); + } + } +} + +void QGestureManager::deliverEvents(const QSet &gestures, + QSet *undeliveredGestures) +{ + if (gestures.isEmpty()) + return; + + typedef QMap > GesturesPerWidget; + GesturesPerWidget conflictedGestures; + GesturesPerWidget normalStartedGestures; + + QSet startedGestures; + // first figure out the initial receivers of gestures + for (QSet::const_iterator it = gestures.begin(), + e = gestures.end(); it != e; ++it) { + QGesture *gesture = *it; + QWidget *target = m_gestureTargets.value(gesture, 0); + if (!target) { + // the gesture has just started and doesn't have a target yet. + Q_ASSERT(gesture->state() == Qt::GestureStarted); + if (gesture->hasHotSpot()) { + // guess the target widget using the hotspot of the gesture + QPoint pt = gesture->hotSpot().toPoint(); + if (QWidget *topLevel = qApp->topLevelAt(pt)) { + QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt)); + target = child ? child : topLevel; + } + } else { + // or use the context of the gesture + QObject *context = m_gestureOwners.value(gesture, 0); + if (context->isWidgetType()) + target = static_cast(context); + } + if (target) + m_gestureTargets.insert(gesture, target); + } + + Qt::GestureType gestureType = gesture->gestureType(); + Q_ASSERT(gestureType != Qt::CustomGesture); + Q_UNUSED(gestureType); + + if (target) { + if (gesture->state() == Qt::GestureStarted) { + startedGestures.insert(gesture); + } else { + normalStartedGestures[target].append(gesture); + } + } else { + DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture" + << gesture->gestureType(); + qWarning("QGestureManager::deliverEvent: could not find the target for gesture"); + undeliveredGestures->insert(gesture); + } + } + + getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures); + DEBUG() << "QGestureManager::deliverEvents:" + << "\nstarted: " << startedGestures + << "\nconflicted: " << conflictedGestures + << "\nnormal: " << normalStartedGestures + << "\n"; + + // if there are conflicting gestures, send the GestureOverride event + for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(), + e = conflictedGestures.end(); it != e; ++it) { + QWidget *receiver = it.key(); + QList gestures = it.value(); + DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" + << receiver + << "gestures:" << gestures; + QGestureEvent event(gestures); + event.t = QEvent::GestureOverride; + // mark event and individual gestures as ignored + event.ignore(); + foreach(QGesture *g, gestures) + event.setAccepted(g, false); + + QApplication::sendEvent(receiver, &event); + bool eventAccepted = event.isAccepted(); + foreach(QGesture *gesture, event.gestures()) { + if (eventAccepted || event.isAccepted(gesture)) { + QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); + Q_ASSERT(w); + DEBUG() << "override event: gesture was accepted:" << gesture << w; + QList &gestures = normalStartedGestures[w]; + gestures.append(gesture); + // override the target + m_gestureTargets[gesture] = w; + } else { + DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture; + QList &gestures = normalStartedGestures[receiver]; + gestures.append(gesture); + } + } + } + + // delivering gestures that are not in conflicted state + for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(), + e = normalStartedGestures.end(); it != e; ++it) { + if (!it.value().isEmpty()) { + DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() + << "gestures:" << it.value(); + QGestureEvent event(it.value()); + QApplication::sendEvent(it.key(), &event); + bool eventAccepted = event.isAccepted(); + foreach (QGesture *gesture, event.gestures()) { + if (gesture->state() == Qt::GestureStarted && + (eventAccepted || event.isAccepted(gesture))) { + QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); + Q_ASSERT(w); + DEBUG() << "started gesture was delivered and accepted by" << w; + m_gestureTargets[gesture] = w; + } + } + } + } +} + +void QGestureManager::recycle(QGesture *gesture) +{ + QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0); + if (recognizer) { + gesture->setGestureCancelPolicy(QGesture::CancelNone); + recognizer->reset(gesture); + m_activeGestures.remove(gesture); + } else { + cleanupGesturesForRemovedRecognizer(gesture); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES + +#include "moc_qgesturemanager_p.cpp" diff --git a/src/widgets/kernel/qgesturemanager_p.h b/src/widgets/kernel/qgesturemanager_p.h new file mode 100644 index 0000000000..b4d9f61ec0 --- /dev/null +++ b/src/widgets/kernel/qgesturemanager_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTUREMANAGER_P_H +#define QGESTUREMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qobject.h" +#include "qbasictimer.h" +#include "private/qwidget_p.h" +#include "qgesturerecognizer.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +class QBasicTimer; +class QGraphicsObject; +class QGestureManager : public QObject +{ + Q_OBJECT +public: + QGestureManager(QObject *parent); + ~QGestureManager(); + + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + + bool filterEvent(QWidget *receiver, QEvent *event); + bool filterEvent(QObject *receiver, QEvent *event); +#ifndef QT_NO_GRAPHICSVIEW + bool filterEvent(QGraphicsObject *receiver, QEvent *event); +#endif //QT_NO_GRAPHICSVIEW + + static QGestureManager* instance(); // declared in qapplication.cpp + + void cleanupCachedGestures(QObject *target, Qt::GestureType type); + + void recycle(QGesture *gesture); + +protected: + bool filterEventThroughContexts(const QMultiMap &contexts, + QEvent *event); + +private: + QMultiMap m_recognizers; + + QSet m_activeGestures; + QSet m_maybeGestures; + + enum State { + Gesture, + NotGesture, + MaybeGesture // this means timers are up and waiting for some + // more events, and input events are handled by + // gesture recognizer explicitly + } state; + + struct ObjectGesture + { + QObject* object; + Qt::GestureType gesture; + + ObjectGesture(QObject *o, const Qt::GestureType &g) : object(o), gesture(g) { } + inline bool operator<(const ObjectGesture &rhs) const + { + if (object < rhs.object) + return true; + if (object == rhs.object) + return gesture < rhs.gesture; + return false; + } + }; + + QMap > m_objectGestures; + QHash m_gestureToRecognizer; + QHash m_gestureOwners; + + QHash m_gestureTargets; + + int m_lastCustomGestureId; + + QHash > m_obsoleteGestures; + QHash m_deletedRecognizers; + QSet m_gesturesToDelete; + void cleanupGesturesForRemovedRecognizer(QGesture *gesture); + + QGesture *getState(QObject *widget, QGestureRecognizer *recognizer, + Qt::GestureType gesture); + void deliverEvents(const QSet &gestures, + QSet *undeliveredGestures); + void getGestureTargets(const QSet &gestures, + QMap > *conflicts, + QMap > *normal); + + void cancelGesturesForChildren(QGesture *originatingGesture); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES + +#endif // QGESTUREMANAGER_P_H diff --git a/src/widgets/kernel/qgesturerecognizer.cpp b/src/widgets/kernel/qgesturerecognizer.cpp new file mode 100644 index 0000000000..f7a4a189b9 --- /dev/null +++ b/src/widgets/kernel/qgesturerecognizer.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesturerecognizer.h" + +#include "private/qgesture_p.h" +#include "private/qgesturemanager_p.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +/*! + \class QGestureRecognizer + \since 4.6 + \brief The QGestureRecognizer class provides the infrastructure for gesture recognition. + \ingroup gestures + + Gesture recognizers are responsible for creating and managing QGesture objects and + monitoring input events sent to QWidget and QGraphicsObject subclasses. + QGestureRecognizer is the base class for implementing custom gestures. + + Developers that only need to provide gesture recognition for standard gestures do not + need to use this class directly. Instances will be created behind the scenes by the + framework. + + For an overview of gesture handling in Qt and information on using gestures + in your applications, see the \l{Gestures Programming} document. + + \section1 Recognizing Gestures + + The process of recognizing gestures involves filtering input events sent to specific + objects, and modifying the associated QGesture objects to include relevant information + about the user's input. + + Gestures are created when the framework calls create() to handle user input + for a particular instance of a QWidget or QGraphicsObject subclass. A QGesture object + is created for each widget or item that is configured to use gestures. + + Once a QGesture has been created for a target object, the gesture recognizer will + receive events for it in its recognize() handler function. + + When a gesture is canceled, the reset() function is called, giving the recognizer the + chance to update the appropriate properties in the corresponding QGesture object. + + \section1 Supporting New Gestures + + To add support for new gestures, you need to derive from QGestureRecognizer to create + a custom recognizer class, construct an instance of this class, and register it with + the application by calling QGestureRecognizer::registerRecognizer(). You can also + subclass QGesture to create a custom gesture class, or rely on dynamic properties + to express specific details of the gesture you want to handle. + + Your custom QGestureRecognizer subclass needs to reimplement the recognize() + function to handle and filter the incoming input events for QWidget and + QGraphicsObject subclasses. Although the logic for gesture recognition is + implemented in this function, you can store persistent information about the + state of the recognition process in the QGesture object supplied. The + recognize() function must return a value of QGestureRecognizer::Result that + indicates the state of recognition for a given gesture and target object. + This determines whether or not a gesture event will be delivered to a target + object. + + If you choose to represent a gesture by a custom QGesture subclass, you will need to + reimplement the create() function to construct instances of your gesture class. + Similarly, you may need to reimplement the reset() function if your custom gesture + objects need to be specially handled when a gesture is canceled. + + \sa QGesture +*/ + +/*! + \enum QGestureRecognizer::ResultFlag + + This enum describes the result of the current event filtering step in + a gesture recognizer state machine. + + The result consists of a state value (one of Ignore, MayBeGesture, + TriggerGesture, FinishGesture, CancelGesture) and an optional hint + (ConsumeEventHint). + + \value Ignore The event does not change the state of the recognizer. + + \value MayBeGesture The event changed the internal state of the recognizer, + but it isn't clear yet if it is a gesture or not. The recognizer needs to + filter more events to decide. Gesture recognizers in the MayBeGesture state + may be reset automatically if they take too long to recognize gestures. + + \value TriggerGesture The gesture has been triggered and the appropriate + QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value FinishGesture The gesture has been finished successfully and the + appropriate QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value CancelGesture The event made it clear that it is not a gesture. If + the gesture recognizer was in GestureTriggered state before, then the + gesture is canceled and the appropriate QGesture object will be delivered + to the target as a part of a QGestureEvent. + + \value ConsumeEventHint This hint specifies that the gesture framework + should consume the filtered event and not deliver it to the receiver. + + \omitvalue ResultState_Mask + \omitvalue ResultHint_Mask + + \sa QGestureRecognizer::recognize() +*/ + +/*! + Constructs a new gesture recognizer object. +*/ +QGestureRecognizer::QGestureRecognizer() +{ +} + +/*! + Destroys the gesture recognizer. +*/ +QGestureRecognizer::~QGestureRecognizer() +{ +} + +/*! + This function is called by Qt to create a new QGesture object for the + given \a target (QWidget or QGraphicsObject). + + Reimplement this function to create a custom QGesture-derived gesture + object if necessary. + + The application takes ownership of the created gesture object. +*/ +QGesture *QGestureRecognizer::create(QObject *target) +{ + Q_UNUSED(target); + return new QGesture; +} + +/*! + This function is called by the framework to reset a given \a gesture. + + Reimplement this function to implement additional requirements for custom QGesture + objects. This may be necessary if you implement a custom QGesture whose properties + need special handling when the gesture is reset. +*/ +void QGestureRecognizer::reset(QGesture *gesture) +{ + if (gesture) { + QGesturePrivate *d = gesture->d_func(); + d->state = Qt::NoGesture; + d->hotSpot = QPointF(); + d->sceneHotSpot = QPointF(); + d->isHotSpotSet = false; + } +} + +/*! + \fn QGestureRecognizer::recognize(QGesture *gesture, QObject *watched, QEvent *event) + + Handles the given \a event for the \a watched object, updating the state of the \a gesture + object as required, and returns a suitable result for the current recognition step. + + This function is called by the framework to allow the recognizer to filter input events + dispatched to QWidget or QGraphicsObject instances that it is monitoring. + + The result reflects how much of the gesture has been recognized. The state of the + \a gesture object is set depending on the result. + + \sa QGestureRecognizer::Result +*/ + +/*! + Registers the given \a recognizer in the gesture framework and returns a gesture ID + for it. + + The application takes ownership of the \a recognizer and returns the gesture type + ID associated with it. For gesture recognizers which handle custom QGesture + objects (i.e., those which return Qt::CustomGesture in a QGesture::gestureType() + function) the return value is a generated gesture ID with the Qt::CustomGesture + flag set. + + \sa unregisterRecognizer(), QGestureRecognizer::create(), QGesture +*/ +Qt::GestureType QGestureRecognizer::registerRecognizer(QGestureRecognizer *recognizer) +{ + return QGestureManager::instance()->registerGestureRecognizer(recognizer); +} + +/*! + Unregisters all gesture recognizers of the specified \a type. + + \sa registerRecognizer() +*/ +void QGestureRecognizer::unregisterRecognizer(Qt::GestureType type) +{ + QGestureManager::instance()->unregisterGestureRecognizer(type); +} + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES diff --git a/src/widgets/kernel/qgesturerecognizer.h b/src/widgets/kernel/qgesturerecognizer.h new file mode 100644 index 0000000000..80d978d6bb --- /dev/null +++ b/src/widgets/kernel/qgesturerecognizer.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURERECOGNIZER_H +#define QGESTURERECOGNIZER_H + +#include +#include + +#ifndef QT_NO_GESTURES + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QObject; +class QEvent; +class QGesture; +class Q_GUI_EXPORT QGestureRecognizer +{ +public: + enum ResultFlag + { + Ignore = 0x0001, + + MayBeGesture = 0x0002, + TriggerGesture = 0x0004, + FinishGesture = 0x0008, + CancelGesture = 0x0010, + + ResultState_Mask = 0x00ff, + + ConsumeEventHint = 0x0100, + // StoreEventHint = 0x0200, + // ReplayStoredEventsHint = 0x0400, + // DiscardStoredEventsHint = 0x0800, + + ResultHint_Mask = 0xff00 + }; + Q_DECLARE_FLAGS(Result, ResultFlag) + + QGestureRecognizer(); + virtual ~QGestureRecognizer(); + + virtual QGesture *create(QObject *target); + virtual Result recognize(QGesture *state, QObject *watched, + QEvent *event) = 0; + virtual void reset(QGesture *state); + + static Qt::GestureType registerRecognizer(QGestureRecognizer *recognizer); + static void unregisterRecognizer(Qt::GestureType type); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QGestureRecognizer::Result) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_GESTURES + +#endif // QGESTURERECOGNIZER_H diff --git a/src/widgets/kernel/qgridlayout.cpp b/src/widgets/kernel/qgridlayout.cpp new file mode 100644 index 0000000000..19d101a0b0 --- /dev/null +++ b/src/widgets/kernel/qgridlayout.cpp @@ -0,0 +1,1889 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgridlayout.h" +#include "qapplication.h" +#include "qwidget.h" +#include "qlist.h" +#include "qsizepolicy.h" +#include "qvector.h" +#include "qvarlengtharray.h" +#include "qlayoutengine_p.h" +#include "qlayout_p.h" + +QT_BEGIN_NAMESPACE + +struct QGridLayoutSizeTriple +{ + QSize minS; + QSize hint; + QSize maxS; +}; + +/* + Three internal classes related to QGridLayout: (1) QGridBox is a + QLayoutItem with (row, column) information and (torow, tocolumn) information; (3) QGridLayoutData is + the internal representation of a QGridLayout. +*/ + +class QGridBox +{ +public: + QGridBox(QLayoutItem *lit) { item_ = lit; } + + QGridBox(const QLayout *l, QWidget *wid) { item_ = QLayoutPrivate::createWidgetItem(l, wid); } + ~QGridBox() { delete item_; } + + QSize sizeHint() const { return item_->sizeHint(); } + QSize minimumSize() const { return item_->minimumSize(); } + QSize maximumSize() const { return item_->maximumSize(); } + Qt::Orientations expandingDirections() const { return item_->expandingDirections(); } + bool isEmpty() const { return item_->isEmpty(); } + + bool hasHeightForWidth() const { return item_->hasHeightForWidth(); } + int heightForWidth(int w) const { return item_->heightForWidth(w); } + + void setAlignment(Qt::Alignment a) { item_->setAlignment(a); } + void setGeometry(const QRect &r) { item_->setGeometry(r); } + Qt::Alignment alignment() const { return item_->alignment(); } + QLayoutItem *item() { return item_; } + QLayoutItem *takeItem() { QLayoutItem *i = item_; item_ = 0; return i; } + + int hStretch() { return item_->widget() ? + item_->widget()->sizePolicy().horizontalStretch() : 0; } + int vStretch() { return item_->widget() ? + item_->widget()->sizePolicy().verticalStretch() : 0; } + +private: + friend class QGridLayoutPrivate; + friend class QGridLayout; + + inline int toRow(int rr) const { return torow >= 0 ? torow : rr - 1; } + inline int toCol(int cc) const { return tocol >= 0 ? tocol : cc - 1; } + + QLayoutItem *item_; + int row, col; + int torow, tocol; +}; + +class QGridLayoutPrivate : public QLayoutPrivate +{ + Q_DECLARE_PUBLIC(QGridLayout) +public: + QGridLayoutPrivate(); + + void add(QGridBox*, int row, int col); + void add(QGridBox*, int row1, int row2, int col1, int col2); + QSize sizeHint(int hSpacing, int vSpacing) const; + QSize minimumSize(int hSpacing, int vSpacing) const; + QSize maximumSize(int hSpacing, int vSpacing) const; + + Qt::Orientations expandingDirections(int hSpacing, int vSpacing) const; + + void distribute(QRect rect, int hSpacing, int vSpacing); + inline int numRows() const { return rr; } + inline int numCols() const { return cc; } + inline void expand(int rows, int cols) + { setSize(qMax(rows, rr), qMax(cols, cc)); } + inline void setRowStretch(int r, int s) + { expand(r + 1, 0); rStretch[r] = s; setDirty(); } + inline void setColStretch(int c, int s) + { expand(0, c + 1); cStretch[c] = s; setDirty(); } + inline int rowStretch(int r) const { return rStretch.at(r); } + inline int colStretch(int c) const { return cStretch.at(c); } + inline void setRowMinimumHeight(int r, int s) + { expand(r + 1, 0); rMinHeights[r] = s; setDirty(); } + inline void setColumnMinimumWidth(int c, int s) + { expand(0, c + 1); cMinWidths[c] = s; setDirty(); } + inline int rowSpacing(int r) const { return rMinHeights.at(r); } + inline int colSpacing(int c) const { return cMinWidths.at(c); } + + inline void setReversed(bool r, bool c) { hReversed = c; vReversed = r; } + inline bool horReversed() const { return hReversed; } + inline bool verReversed() const { return vReversed; } + inline void setDirty() { needRecalc = true; hfw_width = -1; } + inline bool isDirty() const { return needRecalc; } + bool hasHeightForWidth(int hSpacing, int vSpacing); + int heightForWidth(int width, int hSpacing, int vSpacing); + int minimumHeightForWidth(int width, int hSpacing, int vSpacing); + + inline void getNextPos(int &row, int &col) { row = nextR; col = nextC; } + inline int count() const { return things.count(); } + QRect cellRect(int row, int col) const; + + inline QLayoutItem *itemAt(int index) const { + if (index < things.count()) + return things.at(index)->item(); + else + return 0; + } + inline QLayoutItem *takeAt(int index) { + QLayoutItem *item = 0; + if (index < things.count()) { + QGridBox *b = things.takeAt(index); + if (b) { + item = b->takeItem(); + delete b; + } + } + return item; + } + + void getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) { + if (index < things.count()) { + QGridBox *b = things.at(index); + int toRow = b->toRow(rr); + int toCol = b->toCol(cc); + *row = b->row; + *column = b->col; + *rowSpan = toRow - *row + 1; + *columnSpan = toCol - *column +1; + } + } + void deleteAll(); + +private: + void setNextPosAfter(int r, int c); + void recalcHFW(int w); + void addHfwData(QGridBox *box, int width); + void init(); + QSize findSize(int QLayoutStruct::*, int hSpacing, int vSpacing) const; + void addData(QGridBox *b, const QGridLayoutSizeTriple &sizes, bool r, bool c); + void setSize(int rows, int cols); + void setupSpacings(QVector &chain, QGridBox *grid[], int fixedSpacing, + Qt::Orientation orientation); + void setupLayoutData(int hSpacing, int vSpacing); + void setupHfwLayoutData(); + void effectiveMargins(int *left, int *top, int *right, int *bottom) const; + + int rr; + int cc; + QVector rowData; + QVector colData; + QVector *hfwData; + QVector rStretch; + QVector cStretch; + QVector rMinHeights; + QVector cMinWidths; + QList things; + + int hfw_width; + int hfw_height; + int hfw_minheight; + int nextR; + int nextC; + + int horizontalSpacing; + int verticalSpacing; + int leftMargin; + int topMargin; + int rightMargin; + int bottomMargin; + + uint hReversed : 1; + uint vReversed : 1; + uint needRecalc : 1; + uint has_hfw : 1; + uint addVertical : 1; +}; + +void QGridLayoutPrivate::effectiveMargins(int *left, int *top, int *right, int *bottom) const +{ + int l = leftMargin; + int t = topMargin; + int r = rightMargin; + int b = bottomMargin; +#ifdef Q_WS_MAC + int leftMost = INT_MAX; + int topMost = INT_MAX; + int rightMost = 0; + int bottomMost = 0; + + QWidget *w = 0; + const int n = things.count(); + for (int i = 0; i < n; ++i) { + QGridBox *box = things.at(i); + QLayoutItem *itm = box->item(); + w = itm->widget(); + if (w) { + bool visualHReversed = hReversed != (w->layoutDirection() == Qt::RightToLeft); + QRect lir = itm->geometry(); + QRect wr = w->geometry(); + if (box->col <= leftMost) { + if (box->col < leftMost) { + // we found an item even closer to the margin, discard. + leftMost = box->col; + if (visualHReversed) + r = rightMargin; + else + l = leftMargin; + } + if (visualHReversed) { + r = qMax(r, wr.right() - lir.right()); + } else { + l = qMax(l, lir.left() - wr.left()); + } + } + if (box->row <= topMost) { + if (box->row < topMost) { + // we found an item even closer to the margin, discard. + topMost = box->row; + if (vReversed) + b = bottomMargin; + else + t = topMargin; + } + if (vReversed) + b = qMax(b, wr.bottom() - lir.bottom()); + else + t = qMax(t, lir.top() - wr.top()); + } + if (box->toCol(cc) >= rightMost) { + if (box->toCol(cc) > rightMost) { + // we found an item even closer to the margin, discard. + rightMost = box->toCol(cc); + if (visualHReversed) + l = leftMargin; + else + r = rightMargin; + } + if (visualHReversed) { + l = qMax(l, lir.left() - wr.left()); + } else { + r = qMax(r, wr.right() - lir.right()); + } + + } + if (box->toRow(rr) >= bottomMost) { + if (box->toRow(rr) > bottomMost) { + // we found an item even closer to the margin, discard. + bottomMost = box->toRow(rr); + if (vReversed) + t = topMargin; + else + b = bottomMargin; + } + if (vReversed) + t = qMax(t, lir.top() - wr.top()); + else + b = qMax(b, wr.bottom() - lir.bottom()); + } + } + } + +#endif + if (left) + *left = l; + if (top) + *top = t; + if (right) + *right = r; + if (bottom) + *bottom = b; +} + +QGridLayoutPrivate::QGridLayoutPrivate() +{ + addVertical = false; + setDirty(); + rr = cc = 0; + nextR = nextC = 0; + hfwData = 0; + hReversed = false; + vReversed = false; + horizontalSpacing = -1; + verticalSpacing = -1; +} + +#if 0 +QGridLayoutPrivate::QGridLayoutPrivate(int nRows, int nCols) + : rowData(0), colData(0) +{ + init(); + if (nRows < 0) { + nRows = 1; + addVertical = false; + } + if (nCols < 0) { + nCols = 1; + addVertical = true; + } + setSize(nRows, nCols); +} +#endif + +void QGridLayoutPrivate::deleteAll() +{ + while (!things.isEmpty()) + delete things.takeFirst(); + delete hfwData; +} + +bool QGridLayoutPrivate::hasHeightForWidth(int hSpacing, int vSpacing) +{ + setupLayoutData(hSpacing, vSpacing); + return has_hfw; +} + +/* + Assumes that setupLayoutData() has been called, and that + qGeomCalc() has filled in colData with appropriate values. +*/ +void QGridLayoutPrivate::recalcHFW(int w) +{ + /* + Go through all children, using colData and heightForWidth() + and put the results in hfwData. + */ + if (!hfwData) + hfwData = new QVector(rr); + setupHfwLayoutData(); + QVector &rData = *hfwData; + + int h = 0; + int mh = 0; + for (int r = 0; r < rr; r++) { + int spacing = rData.at(r).spacing; + h += rData.at(r).sizeHint + spacing; + mh += rData.at(r).minimumSize + spacing; + } + + hfw_width = w; + hfw_height = qMin(QLAYOUTSIZE_MAX, h); + hfw_minheight = qMin(QLAYOUTSIZE_MAX, mh); +} + +int QGridLayoutPrivate::heightForWidth(int w, int hSpacing, int vSpacing) +{ + setupLayoutData(hSpacing, vSpacing); + if (!has_hfw) + return -1; + int left, top, right, bottom; + effectiveMargins(&left, &top, &right, &bottom); + + int hMargins = left + right; + if (w - hMargins != hfw_width) { + qGeomCalc(colData, 0, cc, 0, w - hMargins); + recalcHFW(w - hMargins); + } + return hfw_height + top + bottom; +} + +int QGridLayoutPrivate::minimumHeightForWidth(int w, int hSpacing, int vSpacing) +{ + (void)heightForWidth(w, hSpacing, vSpacing); + if (!has_hfw) + return -1; + int top, bottom; + effectiveMargins(0, &top, 0, &bottom); + return hfw_minheight + top + bottom; +} + +QSize QGridLayoutPrivate::findSize(int QLayoutStruct::*size, int hSpacing, int vSpacing) const +{ + QGridLayoutPrivate *that = const_cast(this); + that->setupLayoutData(hSpacing, vSpacing); + + int w = 0; + int h = 0; + + for (int r = 0; r < rr; r++) + h += rowData.at(r).*size + rowData.at(r).spacing; + for (int c = 0; c < cc; c++) + w += colData.at(c).*size + colData.at(c).spacing; + + w = qMin(QLAYOUTSIZE_MAX, w); + h = qMin(QLAYOUTSIZE_MAX, h); + + return QSize(w, h); +} + +Qt::Orientations QGridLayoutPrivate::expandingDirections(int hSpacing, int vSpacing) const +{ + QGridLayoutPrivate *that = const_cast(this); + that->setupLayoutData(hSpacing, vSpacing); + Qt::Orientations ret; + + for (int r = 0; r < rr; r++) { + if (rowData.at(r).expansive) { + ret |= Qt::Vertical; + break; + } + } + for (int c = 0; c < cc; c++) { + if (colData.at(c).expansive) { + ret |= Qt::Horizontal; + break; + } + } + return ret; +} + +QSize QGridLayoutPrivate::sizeHint(int hSpacing, int vSpacing) const +{ + return findSize(&QLayoutStruct::sizeHint, hSpacing, vSpacing); +} + +QSize QGridLayoutPrivate::maximumSize(int hSpacing, int vSpacing) const +{ + return findSize(&QLayoutStruct::maximumSize, hSpacing, vSpacing); +} + +QSize QGridLayoutPrivate::minimumSize(int hSpacing, int vSpacing) const +{ + return findSize(&QLayoutStruct::minimumSize, hSpacing, vSpacing); +} + +void QGridLayoutPrivate::setSize(int r, int c) +{ + if ((int)rowData.size() < r) { + int newR = qMax(r, rr * 2); + rowData.resize(newR); + rStretch.resize(newR); + rMinHeights.resize(newR); + for (int i = rr; i < newR; i++) { + rowData[i].init(); + rowData[i].maximumSize = 0; + rowData[i].pos = 0; + rowData[i].size = 0; + rStretch[i] = 0; + rMinHeights[i] = 0; + } + } + if ((int)colData.size() < c) { + int newC = qMax(c, cc * 2); + colData.resize(newC); + cStretch.resize(newC); + cMinWidths.resize(newC); + for (int i = cc; i < newC; i++) { + colData[i].init(); + colData[i].maximumSize = 0; + colData[i].pos = 0; + colData[i].size = 0; + cStretch[i] = 0; + cMinWidths[i] = 0; + } + } + + if (hfwData && (int)hfwData->size() < r) { + delete hfwData; + hfwData = 0; + hfw_width = -1; + } + rr = r; + cc = c; +} + +void QGridLayoutPrivate::setNextPosAfter(int row, int col) +{ + if (addVertical) { + if (col > nextC || (col == nextC && row >= nextR)) { + nextR = row + 1; + nextC = col; + if (nextR >= rr) { + nextR = 0; + nextC++; + } + } + } else { + if (row > nextR || (row == nextR && col >= nextC)) { + nextR = row; + nextC = col + 1; + if (nextC >= cc) { + nextC = 0; + nextR++; + } + } + } +} + +void QGridLayoutPrivate::add(QGridBox *box, int row, int col) +{ + expand(row + 1, col + 1); + box->row = box->torow = row; + box->col = box->tocol = col; + things.append(box); + setDirty(); + setNextPosAfter(row, col); +} + +void QGridLayoutPrivate::add(QGridBox *box, int row1, int row2, int col1, int col2) +{ + if (row2 >= 0 && row2 < row1) + qWarning("QGridLayout: Multi-cell fromRow greater than toRow"); + if (col2 >= 0 && col2 < col1) + qWarning("QGridLayout: Multi-cell fromCol greater than toCol"); + if (row1 == row2 && col1 == col2) { + add(box, row1, col1); + return; + } + expand(row2 + 1, col2 + 1); + box->row = row1; + box->col = col1; + + box->torow = row2; + box->tocol = col2; + + things.append(box); + setDirty(); + if (col2 < 0) + col2 = cc - 1; + + setNextPosAfter(row2, col2); +} + +void QGridLayoutPrivate::addData(QGridBox *box, const QGridLayoutSizeTriple &sizes, bool r, bool c) +{ + const QWidget *widget = box->item()->widget(); + + if (box->isEmpty() && widget) + return; + + if (c) { + QLayoutStruct *data = &colData[box->col]; + if (!cStretch.at(box->col)) + data->stretch = qMax(data->stretch, box->hStretch()); + data->sizeHint = qMax(sizes.hint.width(), data->sizeHint); + data->minimumSize = qMax(sizes.minS.width(), data->minimumSize); + + qMaxExpCalc(data->maximumSize, data->expansive, data->empty, sizes.maxS.width(), + box->expandingDirections() & Qt::Horizontal, box->isEmpty()); + } + if (r) { + QLayoutStruct *data = &rowData[box->row]; + if (!rStretch.at(box->row)) + data->stretch = qMax(data->stretch, box->vStretch()); + data->sizeHint = qMax(sizes.hint.height(), data->sizeHint); + data->minimumSize = qMax(sizes.minS.height(), data->minimumSize); + + qMaxExpCalc(data->maximumSize, data->expansive, data->empty, sizes.maxS.height(), + box->expandingDirections() & Qt::Vertical, box->isEmpty()); + } +} + +static void initEmptyMultiBox(QVector &chain, int start, int end) +{ + for (int i = start; i <= end; i++) { + QLayoutStruct *data = &chain[i]; + if (data->empty && data->maximumSize == 0) // truly empty box + data->maximumSize = QWIDGETSIZE_MAX; + data->empty = false; + } +} + +static void distributeMultiBox(QVector &chain, int start, int end, int minSize, + int sizeHint, QVector &stretchArray, int stretch) +{ + int i; + int w = 0; + int wh = 0; + int max = 0; + + for (i = start; i <= end; i++) { + QLayoutStruct *data = &chain[i]; + w += data->minimumSize; + wh += data->sizeHint; + max += data->maximumSize; + if (stretchArray.at(i) == 0) + data->stretch = qMax(data->stretch, stretch); + + if (i != end) { + int spacing = data->spacing; + w += spacing; + wh += spacing; + max += spacing; + } + } + + if (max < minSize) { // implies w < minSize + /* + We must increase the maximum size of at least one of the + items. qGeomCalc() will put the extra space in between the + items. We must recover that extra space and put it + somewhere. It does not really matter where, since the user + can always specify stretch factors and avoid this code. + */ + qGeomCalc(chain, start, end - start + 1, 0, minSize); + int pos = 0; + for (i = start; i <= end; i++) { + QLayoutStruct *data = &chain[i]; + int nextPos = (i == end) ? minSize : chain.at(i + 1).pos; + int realSize = nextPos - pos; + if (i != end) + realSize -= data->spacing; + if (data->minimumSize < realSize) + data->minimumSize = realSize; + if (data->maximumSize < data->minimumSize) + data->maximumSize = data->minimumSize; + pos = nextPos; + } + } else if (w < minSize) { + qGeomCalc(chain, start, end - start + 1, 0, minSize); + for (i = start; i <= end; i++) { + QLayoutStruct *data = &chain[i]; + if (data->minimumSize < data->size) + data->minimumSize = data->size; + } + } + + if (wh < sizeHint) { + qGeomCalc(chain, start, end - start + 1, 0, sizeHint); + for (i = start; i <= end; i++) { + QLayoutStruct *data = &chain[i]; + if (data->sizeHint < data->size) + data->sizeHint = data->size; + } + } +} + +static QGridBox *&gridAt(QGridBox *grid[], int r, int c, int cc, + Qt::Orientation orientation = Qt::Vertical) +{ + if (orientation == Qt::Horizontal) + qSwap(r, c); + return grid[(r * cc) + c]; +} + +void QGridLayoutPrivate::setupSpacings(QVector &chain, + QGridBox *grid[], int fixedSpacing, + Qt::Orientation orientation) +{ + Q_Q(QGridLayout); + int numRows = rr; // or columns if orientation is horizontal + int numColumns = cc; // or rows if orientation is horizontal + + if (orientation == Qt::Horizontal) { + qSwap(numRows, numColumns); + } + + QStyle *style = 0; + if (fixedSpacing < 0) { + if (QWidget *parentWidget = q->parentWidget()) + style = parentWidget->style(); + } + + for (int c = 0; c < numColumns; ++c) { + QGridBox *previousBox = 0; + int previousRow = -1; // previous *non-empty* row + + for (int r = 0; r < numRows; ++r) { + if (chain.at(r).empty) + continue; + + QGridBox *box = gridAt(grid, r, c, cc, orientation); + if (previousRow != -1 && (!box || previousBox != box)) { + int spacing = fixedSpacing; + if (spacing < 0) { + QSizePolicy::ControlTypes controlTypes1 = QSizePolicy::DefaultType; + QSizePolicy::ControlTypes controlTypes2 = QSizePolicy::DefaultType; + if (previousBox) + controlTypes1 = previousBox->item()->controlTypes(); + if (box) + controlTypes2 = box->item()->controlTypes(); + + if ((orientation == Qt::Horizontal && hReversed) + || (orientation == Qt::Vertical && vReversed)) + qSwap(controlTypes1, controlTypes2); + + if (style) + spacing = style->combinedLayoutSpacing(controlTypes1, controlTypes2, + orientation, 0, q->parentWidget()); + } else { + if (orientation == Qt::Vertical) { + QGridBox *sibling = vReversed ? previousBox : box; + if (sibling) { + QWidget *wid = sibling->item()->widget(); + if (wid) + spacing = qMax(spacing, sibling->item()->geometry().top() - wid->geometry().top() ); + } + } + } + + if (spacing > chain.at(previousRow).spacing) + chain[previousRow].spacing = spacing; + } + + previousBox = box; + previousRow = r; + } + } +} + +//#define QT_LAYOUT_DISABLE_CACHING + +void QGridLayoutPrivate::setupLayoutData(int hSpacing, int vSpacing) +{ + Q_Q(QGridLayout); + +#ifndef QT_LAYOUT_DISABLE_CACHING + if (!needRecalc) + return; +#endif + has_hfw = false; + int i; + + for (i = 0; i < rr; i++) { + rowData[i].init(rStretch.at(i), rMinHeights.at(i)); + rowData[i].maximumSize = rStretch.at(i) ? QLAYOUTSIZE_MAX : rMinHeights.at(i); + } + for (i = 0; i < cc; i++) { + colData[i].init(cStretch.at(i), cMinWidths.at(i)); + colData[i].maximumSize = cStretch.at(i) ? QLAYOUTSIZE_MAX : cMinWidths.at(i); + } + + int n = things.size(); + QVarLengthArray sizes(n); + + bool has_multi = false; + + /* + Grid of items. We use it to determine which items are + adjacent to which and compute the spacings correctly. + */ + QVarLengthArray grid(rr * cc); + qMemSet(grid.data(), 0, rr * cc * sizeof(QGridBox *)); + + /* + Initialize 'sizes' and 'grid' data structures, and insert + non-spanning items to our row and column data structures. + */ + for (i = 0; i < n; ++i) { + QGridBox * const box = things.at(i); + sizes[i].minS = box->minimumSize(); + sizes[i].hint = box->sizeHint(); + sizes[i].maxS = box->maximumSize(); + + if (box->hasHeightForWidth()) + has_hfw = true; + + if (box->row == box->toRow(rr)) { + addData(box, sizes[i], true, false); + } else { + initEmptyMultiBox(rowData, box->row, box->toRow(rr)); + has_multi = true; + } + + if (box->col == box->toCol(cc)) { + addData(box, sizes[i], false, true); + } else { + initEmptyMultiBox(colData, box->col, box->toCol(cc)); + has_multi = true; + } + + for (int r = box->row; r <= box->toRow(rr); ++r) { + for (int c = box->col; c <= box->toCol(cc); ++c) { + gridAt(grid.data(), r, c, cc) = box; + } + } + } + + setupSpacings(colData, grid.data(), hSpacing, Qt::Horizontal); + setupSpacings(rowData, grid.data(), vSpacing, Qt::Vertical); + + /* + Insert multicell items to our row and column data structures. + This must be done after the non-spanning items to obtain a + better distribution in distributeMultiBox(). + */ + if (has_multi) { + for (i = 0; i < n; ++i) { + QGridBox * const box = things.at(i); + + if (box->row != box->toRow(rr)) + distributeMultiBox(rowData, box->row, box->toRow(rr), sizes[i].minS.height(), + sizes[i].hint.height(), rStretch, box->vStretch()); + if (box->col != box->toCol(cc)) + distributeMultiBox(colData, box->col, box->toCol(cc), sizes[i].minS.width(), + sizes[i].hint.width(), cStretch, box->hStretch()); + } + } + + for (i = 0; i < rr; i++) + rowData[i].expansive = rowData.at(i).expansive || rowData.at(i).stretch > 0; + for (i = 0; i < cc; i++) + colData[i].expansive = colData.at(i).expansive || colData.at(i).stretch > 0; + + q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + + needRecalc = false; +} + +void QGridLayoutPrivate::addHfwData(QGridBox *box, int width) +{ + QVector &rData = *hfwData; + if (box->hasHeightForWidth()) { + int hint = box->heightForWidth(width); + rData[box->row].sizeHint = qMax(hint, rData.at(box->row).sizeHint); + rData[box->row].minimumSize = qMax(hint, rData.at(box->row).minimumSize); + } else { + QSize hint = box->sizeHint(); + QSize minS = box->minimumSize(); + rData[box->row].sizeHint = qMax(hint.height(), rData.at(box->row).sizeHint); + rData[box->row].minimumSize = qMax(minS.height(), rData.at(box->row).minimumSize); + } +} + +/* + Similar to setupLayoutData(), but uses heightForWidth(colData) + instead of sizeHint(). Assumes that setupLayoutData() and + qGeomCalc(colData) has been called. +*/ +void QGridLayoutPrivate::setupHfwLayoutData() +{ + QVector &rData = *hfwData; + for (int i = 0; i < rr; i++) { + rData[i] = rowData.at(i); + rData[i].minimumSize = rData[i].sizeHint = rMinHeights.at(i); + } + + for (int pass = 0; pass < 2; ++pass) { + for (int i = 0; i < things.size(); ++i) { + QGridBox *box = things.at(i); + int r1 = box->row; + int c1 = box->col; + int r2 = box->toRow(rr); + int c2 = box->toCol(cc); + int w = colData.at(c2).pos + colData.at(c2).size - colData.at(c1).pos; + + if (r1 == r2) { + if (pass == 0) + addHfwData(box, w); + } else { + if (pass == 0) { + initEmptyMultiBox(rData, r1, r2); + } else { + QSize hint = box->sizeHint(); + QSize min = box->minimumSize(); + if (box->hasHeightForWidth()) { + int hfwh = box->heightForWidth(w); + if (hfwh > hint.height()) + hint.setHeight(hfwh); + if (hfwh > min.height()) + min.setHeight(hfwh); + } + distributeMultiBox(rData, r1, r2, min.height(), hint.height(), + rStretch, box->vStretch()); + } + } + } + } + for (int i = 0; i < rr; i++) + rData[i].expansive = rData.at(i).expansive || rData.at(i).stretch > 0; +} + +void QGridLayoutPrivate::distribute(QRect r, int hSpacing, int vSpacing) +{ + Q_Q(QGridLayout); + bool visualHReversed = hReversed; + QWidget *parent = q->parentWidget(); + if (parent && parent->isRightToLeft()) + visualHReversed = !visualHReversed; + + setupLayoutData(hSpacing, vSpacing); + + int left, top, right, bottom; + effectiveMargins(&left, &top, &right, &bottom); + r.adjust(+left, +top, -right, -bottom); + + qGeomCalc(colData, 0, cc, r.x(), r.width()); + QVector *rDataPtr; + if (has_hfw) { + recalcHFW(r.width()); + qGeomCalc(*hfwData, 0, rr, r.y(), r.height()); + rDataPtr = hfwData; + } else { + qGeomCalc(rowData, 0, rr, r.y(), r.height()); + rDataPtr = &rowData; + } + QVector &rData = *rDataPtr; + int i; + + bool reverse = ((r.bottom() > rect.bottom()) || (r.bottom() == rect.bottom() + && ((r.right() > rect.right()) != visualHReversed))); + int n = things.size(); + for (i = 0; i < n; ++i) { + QGridBox *box = things.at(reverse ? n-i-1 : i); + int r2 = box->toRow(rr); + int c2 = box->toCol(cc); + + int x = colData.at(box->col).pos; + int y = rData.at(box->row).pos; + int x2p = colData.at(c2).pos + colData.at(c2).size; // x2+1 + int y2p = rData.at(r2).pos + rData.at(r2).size; // y2+1 + int w = x2p - x; + int h = y2p - y; + + if (visualHReversed) + x = r.left() + r.right() - x - w + 1; + if (vReversed) + y = r.top() + r.bottom() - y - h + 1; + + box->setGeometry(QRect(x, y, w, h)); + } +} + +QRect QGridLayoutPrivate::cellRect(int row, int col) const +{ + if (row < 0 || row >= rr || col < 0 || col >= cc) + return QRect(); + + const QVector *rDataPtr; + if (has_hfw && hfwData) + rDataPtr = hfwData; + else + rDataPtr = &rowData; + return QRect(colData.at(col).pos, rDataPtr->at(row).pos, + colData.at(col).size, rDataPtr->at(row).size); +} + +/*! + \class QGridLayout + + \brief The QGridLayout class lays out widgets in a grid. + + \ingroup geomanagement + + + QGridLayout takes the space made available to it (by its parent + layout or by the parentWidget()), divides it up into rows and + columns, and puts each widget it manages into the correct cell. + + Columns and rows behave identically; we will discuss columns, but + there are equivalent functions for rows. + + Each column has a minimum width and a stretch factor. The minimum + width is the greatest of that set using setColumnMinimumWidth() and the + minimum width of each widget in that column. The stretch factor is + set using setColumnStretch() and determines how much of the available + space the column will get over and above its necessary minimum. + + Normally, each managed widget or layout is put into a cell of its + own using addWidget(). It is also possible for a widget to occupy + multiple cells using the row and column spanning overloads of + addItem() and addWidget(). If you do this, QGridLayout will guess + how to distribute the size over the columns/rows (based on the + stretch factors). + + To remove a widget from a layout, call removeWidget(). Calling + QWidget::hide() on a widget also effectively removes the widget + from the layout until QWidget::show() is called. + + This illustration shows a fragment of a dialog with a five-column, + three-row grid (the grid is shown overlaid in magenta): + + \image gridlayout.png A grid layout + + Columns 0, 2 and 4 in this dialog fragment are made up of a + QLabel, a QLineEdit, and a QListBox. Columns 1 and 3 are + placeholders made with setColumnMinimumWidth(). Row 0 consists of three + QLabel objects, row 1 of three QLineEdit objects and row 2 of + three QListBox objects. We used placeholder columns (1 and 3) to + get the right amount of space between the columns. + + Note that the columns and rows are not equally wide or tall. If + you want two columns to have the same width, you must set their + minimum widths and stretch factors to be the same yourself. You do + this using setColumnMinimumWidth() and setColumnStretch(). + + If the QGridLayout is not the top-level layout (i.e. does not + manage all of the widget's area and children), you must add it to + its parent layout when you create it, but before you do anything + with it. The normal way to add a layout is by calling + addLayout() on the parent layout. + + Once you have added your layout you can start putting widgets and + other layouts into the cells of your grid layout using + addWidget(), addItem(), and addLayout(). + + QGridLayout also includes two margin widths: + the \l{getContentsMargins()}{contents margin} and the spacing(). + The contents margin is the width of the reserved space along each + of the QGridLayout's four sides. The spacing() is the width of the + automatically allocated spacing between neighboring boxes. + + The default contents margin values are provided by the + \l{QStyle::pixelMetric()}{style}. The default value Qt styles specify + is 9 for child widgets and 11 for windows. The spacing defaults to the same as + the margin width for a top-level layout, or to the same as the + parent layout. + + \sa QBoxLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} +*/ + + +/*! + Constructs a new QGridLayout with parent widget, \a parent. The + layout has one row and one column initially, and will expand when + new items are inserted. +*/ +QGridLayout::QGridLayout(QWidget *parent) + : QLayout(*new QGridLayoutPrivate, 0, parent) +{ + Q_D(QGridLayout); + d->expand(1, 1); +} + +/*! + Constructs a new grid layout. + + You must insert this grid into another layout. You can insert + widgets and layouts into this layout at any time, but laying out + will not be performed before this is inserted into another layout. +*/ +QGridLayout::QGridLayout() + : QLayout(*new QGridLayoutPrivate, 0, 0) +{ + Q_D(QGridLayout); + d->expand(1, 1); +} + + +#ifdef QT3_SUPPORT +/*! + \obsolete + Constructs a new QGridLayout with \a nRows rows, \a nCols columns + and parent widget, \a parent. \a parent may not be 0. The grid + layout is called \a name. + + \a margin is the number of pixels between the edge of the widget + and its managed children. \a space is the default number of pixels + between cells. If \a space is -1, the value of \a margin is used. +*/ +QGridLayout::QGridLayout(QWidget *parent, int nRows, int nCols, int margin, + int space, const char *name) + : QLayout(*new QGridLayoutPrivate, 0, parent) +{ + Q_D(QGridLayout); + d->expand(nRows, nCols); + setMargin(margin); + setSpacing(space < 0 ? margin : space); + setObjectName(QString::fromAscii(name)); +} + +/*! + \obsolete + + Constructs a new grid with \a nRows rows and \a nCols columns. If + \a spacing is -1, this QGridLayout inherits its parent's + spacing(); otherwise \a spacing is used. The grid layout is called + \a name. + + You must insert this grid into another layout. You can insert + widgets and layouts into this layout at any time, but laying out + will not be performed before this is inserted into another layout. +*/ +QGridLayout::QGridLayout(QLayout *parentLayout, int nRows, int nCols, + int spacing, const char *name) + : QLayout(*new QGridLayoutPrivate, parentLayout, 0) +{ + Q_D(QGridLayout); + d->expand(nRows, nCols); + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); +} + +/*! + \obsolete + + Constructs a new grid with \a nRows rows and \a nCols columns. If + \a spacing is -1, this QGridLayout inherits its parent's + spacing(); otherwise \a spacing is used. The grid layout is called + \a name. + + You must insert this grid into another layout. You can insert + widgets and layouts into this layout at any time, but laying out + will not be performed before this is inserted into another layout. +*/ +QGridLayout::QGridLayout(int nRows, int nCols, int spacing, const char *name) + : QLayout(*new QGridLayoutPrivate, 0, 0) +{ + Q_D(QGridLayout); + d->expand(nRows, nCols); + setSpacing(spacing); + setObjectName(QString::fromAscii(name)); +} +#endif + + +/*! +\internal (mostly) + +Sets the positioning mode used by addItem(). If \a orient is +Qt::Horizontal, this layout is expanded to \a n columns, and items +will be added columns-first. Otherwise it is expanded to \a n rows and +items will be added rows-first. +*/ + +void QGridLayout::setDefaultPositioning(int n, Qt::Orientation orient) +{ + Q_D(QGridLayout); + if (orient == Qt::Horizontal) { + d->expand(1, n); + d->addVertical = false; + } else { + d->expand(n,1); + d->addVertical = true; + } +} + + +/*! + Destroys the grid layout. Geometry management is terminated if + this is a top-level grid. + + The layout's widgets aren't destroyed. +*/ +QGridLayout::~QGridLayout() +{ + Q_D(QGridLayout); + d->deleteAll(); +} + +/*! + \property QGridLayout::horizontalSpacing + \brief the spacing between widgets that are laid out side by side + \since 4.3 + + If no value is explicitly set, the layout's horizontal spacing is + inherited from the parent layout, or from the style settings for + the parent widget. + + \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing} +*/ +void QGridLayout::setHorizontalSpacing(int spacing) +{ + Q_D(QGridLayout); + d->horizontalSpacing = spacing; + invalidate(); +} + +int QGridLayout::horizontalSpacing() const +{ + Q_D(const QGridLayout); + if (d->horizontalSpacing >= 0) { + return d->horizontalSpacing; + } else { + return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing); + } +} + +/*! + \property QGridLayout::verticalSpacing + \brief the spacing between widgets that are laid out on top of each other + \since 4.3 + + If no value is explicitly set, the layout's vertical spacing is + inherited from the parent layout, or from the style settings for + the parent widget. + + \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing} +*/ +void QGridLayout::setVerticalSpacing(int spacing) +{ + Q_D(QGridLayout); + d->verticalSpacing = spacing; + invalidate(); +} + +int QGridLayout::verticalSpacing() const +{ + Q_D(const QGridLayout); + if (d->verticalSpacing >= 0) { + return d->verticalSpacing; + } else { + return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing); + } +} + +/*! + This function sets both the vertical and horizontal spacing to + \a spacing. + + \sa setVerticalSpacing(), setHorizontalSpacing() +*/ +void QGridLayout::setSpacing(int spacing) +{ + Q_D(QGridLayout); + d->horizontalSpacing = d->verticalSpacing = spacing; + invalidate(); +} + +/*! + If the vertical spacing is equal to the horizontal spacing, + this function returns that value; otherwise it return -1. + + \sa setSpacing(), verticalSpacing(), horizontalSpacing() +*/ +int QGridLayout::spacing() const +{ + int hSpacing = horizontalSpacing(); + if (hSpacing == verticalSpacing()) { + return hSpacing; + } else { + return -1; + } +} + +/*! + Returns the number of rows in this grid. +*/ +int QGridLayout::rowCount() const +{ + Q_D(const QGridLayout); + return d->numRows(); +} + +/*! + Returns the number of columns in this grid. +*/ +int QGridLayout::columnCount() const +{ + Q_D(const QGridLayout); + return d->numCols(); +} + +/*! + \reimp +*/ +QSize QGridLayout::sizeHint() const +{ + Q_D(const QGridLayout); + QSize result(d->sizeHint(horizontalSpacing(), verticalSpacing())); + int left, top, right, bottom; + d->effectiveMargins(&left, &top, &right, &bottom); + result += QSize(left + right, top + bottom); + return result; +} + +/*! + \reimp +*/ +QSize QGridLayout::minimumSize() const +{ + Q_D(const QGridLayout); + QSize result(d->minimumSize(horizontalSpacing(), verticalSpacing())); + int left, top, right, bottom; + d->effectiveMargins(&left, &top, &right, &bottom); + result += QSize(left + right, top + bottom); + return result; +} + +/*! + \reimp +*/ +QSize QGridLayout::maximumSize() const +{ + Q_D(const QGridLayout); + + QSize s = d->maximumSize(horizontalSpacing(), verticalSpacing()); + int left, top, right, bottom; + d->effectiveMargins(&left, &top, &right, &bottom); + s += QSize(left + right, top + bottom); + s = s.boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX)); + if (alignment() & Qt::AlignHorizontal_Mask) + s.setWidth(QLAYOUTSIZE_MAX); + if (alignment() & Qt::AlignVertical_Mask) + s.setHeight(QLAYOUTSIZE_MAX); + return s; +} + +/*! + \reimp +*/ +bool QGridLayout::hasHeightForWidth() const +{ + return ((QGridLayout*)this)->d_func()->hasHeightForWidth(horizontalSpacing(), verticalSpacing()); +} + +/*! + \reimp +*/ +int QGridLayout::heightForWidth(int w) const +{ + Q_D(const QGridLayout); + QGridLayoutPrivate *dat = const_cast(d); + return dat->heightForWidth(w, horizontalSpacing(), verticalSpacing()); +} + +/*! + \reimp +*/ +int QGridLayout::minimumHeightForWidth(int w) const +{ + Q_D(const QGridLayout); + QGridLayoutPrivate *dat = const_cast(d); + return dat->minimumHeightForWidth(w, horizontalSpacing(), verticalSpacing()); +} + +#ifdef QT3_SUPPORT +/*! + \compat + + Searches for widget \a w in this layout (not including child + layouts). If \a w is found, it sets \c{*}\a{row} and + \c{*}\a{column} to the row and column that the widget + occupies and returns true; otherwise returns false. + + If the widget spans multiple rows/columns, the top-left cell + is returned. + + Use indexOf() and getItemPosition() instead. +*/ +bool QGridLayout::findWidget(QWidget* w, int *row, int *column) +{ + Q_D(QGridLayout); + int index = indexOf(w); + if (index < 0) + return false; + int dummy1, dummy2; + d->getItemPosition(index, row, column, &dummy1, &dummy2); + return true; +} +#endif +/*! + \reimp +*/ +int QGridLayout::count() const +{ + Q_D(const QGridLayout); + return d->count(); +} + + +/*! + \reimp +*/ +QLayoutItem *QGridLayout::itemAt(int index) const +{ + Q_D(const QGridLayout); + return d->itemAt(index); +} + +/*! + \since 4.4 + + Returns the layout item that occupies cell (\a row, \a column), or 0 if + the cell is empty. + + \sa getItemPosition(), indexOf() +*/ +QLayoutItem *QGridLayout::itemAtPosition(int row, int column) const +{ + Q_D(const QGridLayout); + int n = d->things.count(); + for (int i = 0; i < n; ++i) { + QGridBox *box = d->things.at(i); + if (row >= box->row && row <= box->toRow(d->rr) + && column >= box->col && column <= box->toCol(d->cc)) { + return box->item(); + } + } + return 0; +} + +/*! + \reimp +*/ +QLayoutItem *QGridLayout::takeAt(int index) +{ + Q_D(QGridLayout); + return d->takeAt(index); +} + +/*! + Returns the position information of the item with the given \a index. + + The variables passed as \a row and \a column are updated with the position of the + item in the layout, and the \a rowSpan and \a columnSpan variables are updated + with the vertical and horizontal spans of the item. + + \sa itemAtPosition(), itemAt() +*/ +void QGridLayout::getItemPosition(int index, int *row, int *column, int *rowSpan, int *columnSpan) +{ + Q_D(QGridLayout); + d->getItemPosition(index, row, column, rowSpan, columnSpan); +} + + +/*! + \reimp +*/ +void QGridLayout::setGeometry(const QRect &rect) +{ + Q_D(QGridLayout); + if (d->isDirty() || rect != geometry()) { + QRect cr = alignment() ? alignmentRect(rect) : rect; + d->distribute(cr, horizontalSpacing(), verticalSpacing()); + QLayout::setGeometry(rect); + } +} + +/*! + Returns the geometry of the cell with row \a row and column \a column + in the grid. Returns an invalid rectangle if \a row or \a column is + outside the grid. + + \warning in the current version of Qt this function does not + return valid results until setGeometry() has been called, i.e. + after the parentWidget() is visible. +*/ +QRect QGridLayout::cellRect(int row, int column) const +{ + Q_D(const QGridLayout); + return d->cellRect(row, column); +} +#ifdef QT3_SUPPORT +/*! + \obsolete + Expands this grid so that it will have \a nRows rows and \a nCols + columns. Will not shrink the grid. You should not need to call + this function because QGridLayout expands automatically as new + items are inserted. +*/ +void QGridLayout::expand(int nRows, int nCols) +{ + Q_D(QGridLayout); + d->expand(nRows, nCols); +} +#endif + +/*! + \reimp +*/ +void QGridLayout::addItem(QLayoutItem *item) +{ + Q_D(QGridLayout); + int r, c; + d->getNextPos(r, c); + addItem(item, r, c); +} + +/*! + Adds \a item at position \a row, \a column, spanning \a rowSpan + rows and \a columnSpan columns, and aligns it according to \a + alignment. If \a rowSpan and/or \a columnSpan is -1, then the item + will extend to the bottom and/or right edge, respectively. The + layout takes ownership of the \a item. + + \warning Do not use this function to add child layouts or child + widget items. Use addLayout() or addWidget() instead. +*/ +void QGridLayout::addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment) +{ + Q_D(QGridLayout); + QGridBox *b = new QGridBox(item); + b->setAlignment(alignment); + d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1); + invalidate(); +} + +/* + Returns true if the widget \a w can be added to the layout \a l; + otherwise returns false. +*/ +static bool checkWidget(QLayout *l, QWidget *w) +{ + if (!w) { + qWarning("QLayout: Cannot add null widget to %s/%s", l->metaObject()->className(), + l->objectName().toLocal8Bit().data()); + return false; + } + return true; +} + +/*! + Adds the given \a widget to the cell grid at \a row, \a column. The + top-left position is (0, 0) by default. + + The alignment is specified by \a alignment. The default + alignment is 0, which means that the widget fills the entire cell. + +*/ +void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment) +{ + if (!checkWidget(this, widget)) + return; + if (row < 0 || column < 0) { + qWarning("QGridLayout: Cannot add %s/%s to %s/%s at row %d column %d", + widget->metaObject()->className(), widget->objectName().toLocal8Bit().data(), + metaObject()->className(), objectName().toLocal8Bit().data(), row, column); + return; + } + addChildWidget(widget); + QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget); + addItem(b, row, column, 1, 1, alignment); +} + +/*! + \overload + + This version adds the given \a widget to the cell grid, spanning + multiple rows/columns. The cell will start at \a fromRow, \a + fromColumn spanning \a rowSpan rows and \a columnSpan columns. The + \a widget will have the given \a alignment. + + If \a rowSpan and/or \a columnSpan is -1, then the widget will + extend to the bottom and/or right edge, respectively. + +*/ +void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn, + int rowSpan, int columnSpan, Qt::Alignment alignment) +{ + Q_D(QGridLayout); + if (!checkWidget(this, widget)) + return; + int toRow = (rowSpan < 0) ? -1 : fromRow + rowSpan - 1; + int toColumn = (columnSpan < 0) ? -1 : fromColumn + columnSpan - 1; + addChildWidget(widget); + QGridBox *b = new QGridBox(this, widget); + b->setAlignment(alignment); + d->add(b, fromRow, toRow, fromColumn, toColumn); + invalidate(); +} + +/*! + \fn void QGridLayout::addWidget(QWidget *widget) + + \overload + \internal +*/ + +/*! + Places the \a layout at position (\a row, \a column) in the grid. The + top-left position is (0, 0). + + The alignment is specified by \a alignment. The default + alignment is 0, which means that the widget fills the entire cell. + + A non-zero alignment indicates that the layout should not grow to + fill the available space but should be sized according to + sizeHint(). + + + \a layout becomes a child of the grid layout. +*/ +void QGridLayout::addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment) +{ + Q_D(QGridLayout); + addChildLayout(layout); + QGridBox *b = new QGridBox(layout); + b->setAlignment(alignment); + d->add(b, row, column); +} + +/*! + \overload + This version adds the layout \a layout to the cell grid, spanning multiple + rows/columns. The cell will start at \a row, \a column spanning \a + rowSpan rows and \a columnSpan columns. + + If \a rowSpan and/or \a columnSpan is -1, then the layout will extend to the bottom + and/or right edge, respectively. +*/ +void QGridLayout::addLayout(QLayout *layout, int row, int column, + int rowSpan, int columnSpan, Qt::Alignment alignment) +{ + Q_D(QGridLayout); + addChildLayout(layout); + QGridBox *b = new QGridBox(layout); + b->setAlignment(alignment); + d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1); +} + +/*! + Sets the stretch factor of row \a row to \a stretch. The first row + is number 0. + + The stretch factor is relative to the other rows in this grid. + Rows with a higher stretch factor take more of the available + space. + + The default stretch factor is 0. If the stretch factor is 0 and no + other row in this table can grow at all, the row may still grow. + + \sa rowStretch(), setRowMinimumHeight(), setColumnStretch() +*/ +void QGridLayout::setRowStretch(int row, int stretch) +{ + Q_D(QGridLayout); + d->setRowStretch(row, stretch); + invalidate(); +} + +/*! + Returns the stretch factor for row \a row. + + \sa setRowStretch() +*/ +int QGridLayout::rowStretch(int row) const +{ + Q_D(const QGridLayout); + return d->rowStretch(row); +} + +/*! + Returns the stretch factor for column \a column. + + \sa setColumnStretch() +*/ +int QGridLayout::columnStretch(int column) const +{ + Q_D(const QGridLayout); + return d->colStretch(column); +} + +/*! + Sets the stretch factor of column \a column to \a stretch. The first + column is number 0. + + The stretch factor is relative to the other columns in this grid. + Columns with a higher stretch factor take more of the available + space. + + The default stretch factor is 0. If the stretch factor is 0 and no + other column in this table can grow at all, the column may still + grow. + + An alternative approach is to add spacing using addItem() with a + QSpacerItem. + + \sa columnStretch(), setRowStretch() +*/ +void QGridLayout::setColumnStretch(int column, int stretch) +{ + Q_D(QGridLayout); + d->setColStretch(column, stretch); + invalidate(); +} + + + +/*! + Sets the minimum height of row \a row to \a minSize pixels. + + \sa rowMinimumHeight(), setColumnMinimumWidth() +*/ +void QGridLayout::setRowMinimumHeight(int row, int minSize) +{ + Q_D(QGridLayout); + d->setRowMinimumHeight(row, minSize); + invalidate(); +} + +/*! + Returns the minimum width set for row \a row. + + \sa setRowMinimumHeight() +*/ +int QGridLayout::rowMinimumHeight(int row) const +{ + Q_D(const QGridLayout); + return d->rowSpacing(row); +} + +/*! + Sets the minimum width of column \a column to \a minSize pixels. + + \sa columnMinimumWidth(), setRowMinimumHeight() +*/ +void QGridLayout::setColumnMinimumWidth(int column, int minSize) +{ + Q_D(QGridLayout); + d->setColumnMinimumWidth(column, minSize); + invalidate(); +} + +/*! + Returns the column spacing for column \a column. + + \sa setColumnMinimumWidth() +*/ +int QGridLayout::columnMinimumWidth(int column) const +{ + Q_D(const QGridLayout); + return d->colSpacing(column); +} + +/*! + \reimp +*/ +Qt::Orientations QGridLayout::expandingDirections() const +{ + Q_D(const QGridLayout); + return d->expandingDirections(horizontalSpacing(), verticalSpacing()); +} + +/*! + Sets the grid's origin corner, i.e. position (0, 0), to \a corner. +*/ +void QGridLayout::setOriginCorner(Qt::Corner corner) +{ + Q_D(QGridLayout); + d->setReversed(corner == Qt::BottomLeftCorner || corner == Qt::BottomRightCorner, + corner == Qt::TopRightCorner || corner == Qt::BottomRightCorner); +} + +/*! + Returns the corner that's used for the grid's origin, i.e. for + position (0, 0). +*/ +Qt::Corner QGridLayout::originCorner() const +{ + Q_D(const QGridLayout); + if (d->horReversed()) { + return d->verReversed() ? Qt::BottomRightCorner : Qt::TopRightCorner; + } else { + return d->verReversed() ? Qt::BottomLeftCorner : Qt::TopLeftCorner; + } +} + +/*! + \reimp +*/ +void QGridLayout::invalidate() +{ + Q_D(QGridLayout); + d->setDirty(); + QLayout::invalidate(); +} + +/*! + \fn void QGridLayout::addRowSpacing(int row, int minsize) + + Use addItem(new QSpacerItem(0, minsize), row, 0) instead. +*/ + +/*! + \fn void QGridLayout::addColSpacing(int col, int minsize) + + Use addItem(new QSpacerItem(minsize, 0), 0, col) instead. +*/ + +/*! + \fn void QGridLayout::addMultiCellWidget(QWidget *widget, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment align = 0) + + Use an addWidget() overload that allows you to specify row and + column spans instead. +*/ + +/*! + \fn void QGridLayout::addMultiCell(QLayoutItem *l, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment align = 0) + + Use an addItem() overload that allows you to specify row and + column spans instead. +*/ + +/*! + \fn void QGridLayout::addMultiCellLayout(QLayout *layout, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment align = 0) + + Use an addLayout() overload that allows you to specify row and + column spans instead. +*/ + +/*! + \fn int QGridLayout::numRows() const + + Use rowCount() instead. +*/ + +/*! + \fn int QGridLayout::numCols() const + + Use columnCount() instead. +*/ + +/*! + \fn void QGridLayout::setColStretch(int col, int stretch) + + Use setColumnStretch() instead. +*/ + +/*! + \fn int QGridLayout::colStretch(int col) const + + Use columnStretch() instead. +*/ + +/*! + \fn void QGridLayout::setColSpacing(int col, int minSize) + + Use setColumnMinimumWidth() instead. +*/ + +/*! + \fn int QGridLayout::colSpacing(int col) const + + Use columnMinimumWidth() instead. +*/ + +/*! + \fn void QGridLayout::setRowSpacing(int row, int minSize) + + Use setRowMinimumHeight(\a row, \a minSize) instead. +*/ + +/*! + \fn int QGridLayout::rowSpacing(int row) const + + Use rowMinimumHeight(\a row) instead. +*/ + +/*! + \fn QRect QGridLayout::cellGeometry(int row, int column) const + + Use cellRect(\a row, \a column) instead. +*/ + +/*! + \fn void QGridLayout::setOrigin(Qt::Corner corner) + + Use setOriginCorner(\a corner) instead. +*/ + +/*! + \fn Qt::Corner QGridLayout::origin() const + + Use originCorner() instead. +*/ + + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qgridlayout.h b/src/widgets/kernel/qgridlayout.h new file mode 100644 index 0000000000..0ac66e8f87 --- /dev/null +++ b/src/widgets/kernel/qgridlayout.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRIDLAYOUT_H +#define QGRIDLAYOUT_H + +#include +#ifdef QT_INCLUDE_COMPAT +#include +#endif + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QGridLayoutPrivate; + +class Q_GUI_EXPORT QGridLayout : public QLayout +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGridLayout) + QDOC_PROPERTY(int horizontalSpacing READ horizontalSpacing WRITE setHorizontalSpacing) + QDOC_PROPERTY(int verticalSpacing READ verticalSpacing WRITE setVerticalSpacing) + +public: + explicit QGridLayout(QWidget *parent); + QGridLayout(); + +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QGridLayout(QWidget *parent, int nRows , int nCols = 1, int border = 0, + int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QGridLayout(int nRows , int nCols = 1, int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QGridLayout(QLayout *parentLayout, int nRows = 1, int nCols = 1, int spacing = -1, + const char *name = 0); +#endif + ~QGridLayout(); + + QSize sizeHint() const; + QSize minimumSize() const; + QSize maximumSize() const; + + void setHorizontalSpacing(int spacing); + int horizontalSpacing() const; + void setVerticalSpacing(int spacing); + int verticalSpacing() const; + void setSpacing(int spacing); + int spacing() const; + + void setRowStretch(int row, int stretch); + void setColumnStretch(int column, int stretch); + int rowStretch(int row) const; + int columnStretch(int column) const; + + void setRowMinimumHeight(int row, int minSize); + void setColumnMinimumWidth(int column, int minSize); + int rowMinimumHeight(int row) const; + int columnMinimumWidth(int column) const; + + int columnCount() const; + int rowCount() const; + + QRect cellRect(int row, int column) const; +#ifdef QT3_SUPPORT + inline QT3_SUPPORT QRect cellGeometry(int row, int column) const {return cellRect(row, column);} +#endif + + bool hasHeightForWidth() const; + int heightForWidth(int) const; + int minimumHeightForWidth(int) const; + + Qt::Orientations expandingDirections() const; + void invalidate(); + + inline void addWidget(QWidget *w) { QLayout::addWidget(w); } + void addWidget(QWidget *, int row, int column, Qt::Alignment = 0); + void addWidget(QWidget *, int row, int column, int rowSpan, int columnSpan, Qt::Alignment = 0); + void addLayout(QLayout *, int row, int column, Qt::Alignment = 0); + void addLayout(QLayout *, int row, int column, int rowSpan, int columnSpan, Qt::Alignment = 0); + + void setOriginCorner(Qt::Corner); + Qt::Corner originCorner() const; + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT void setOrigin(Qt::Corner corner) { setOriginCorner(corner); } + inline QT3_SUPPORT Qt::Corner origin() const { return originCorner(); } +#endif + QLayoutItem *itemAt(int index) const; + QLayoutItem *itemAtPosition(int row, int column) const; + QLayoutItem *takeAt(int index); + int count() const; + void setGeometry(const QRect&); + + void addItem(QLayoutItem *item, int row, int column, int rowSpan = 1, int columnSpan = 1, Qt::Alignment = 0); + + void setDefaultPositioning(int n, Qt::Orientation orient); + void getItemPosition(int idx, int *row, int *column, int *rowSpan, int *columnSpan); + +protected: +#ifdef QT3_SUPPORT + QT3_SUPPORT bool findWidget(QWidget* w, int *r, int *c); +#endif + void addItem(QLayoutItem *); + +private: + Q_DISABLE_COPY(QGridLayout) + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT void expand(int rows, int cols); + inline QT3_SUPPORT void addRowSpacing(int row, int minsize) { addItem(new QSpacerItem(0,minsize), row, 0); } + inline QT3_SUPPORT void addColSpacing(int col, int minsize) { addItem(new QSpacerItem(minsize,0), 0, col); } + inline QT3_SUPPORT void addMultiCellWidget(QWidget *w, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment _align = 0) + { addWidget(w, fromRow, fromCol, (toRow < 0) ? -1 : toRow - fromRow + 1, (toCol < 0) ? -1 : toCol - fromCol + 1, _align); } + inline QT3_SUPPORT void addMultiCell(QLayoutItem *l, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment _align = 0) + { addItem(l, fromRow, fromCol, (toRow < 0) ? -1 : toRow - fromRow + 1, (toCol < 0) ? -1 : toCol - fromCol + 1, _align); } + inline QT3_SUPPORT void addMultiCellLayout(QLayout *layout, int fromRow, int toRow, int fromCol, int toCol, Qt::Alignment _align = 0) + { addLayout(layout, fromRow, fromCol, (toRow < 0) ? -1 : toRow - fromRow + 1, (toCol < 0) ? -1 : toCol - fromCol + 1, _align); } + + inline QT3_SUPPORT int numRows() const { return rowCount(); } + inline QT3_SUPPORT int numCols() const { return columnCount(); } + inline QT3_SUPPORT void setColStretch(int col, int stretch) {setColumnStretch(col, stretch); } + inline QT3_SUPPORT int colStretch(int col) const {return columnStretch(col); } + inline QT3_SUPPORT void setColSpacing(int col, int minSize) { setColumnMinimumWidth(col, minSize); } + inline QT3_SUPPORT int colSpacing(int col) const { return columnMinimumWidth(col); } + inline QT3_SUPPORT void setRowSpacing(int row, int minSize) {setRowMinimumHeight(row, minSize); } + inline QT3_SUPPORT int rowSpacing(int row) const {return rowMinimumHeight(row); } +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGRIDLAYOUT_H diff --git a/src/widgets/kernel/qguieventdispatcher_glib.cpp b/src/widgets/kernel/qguieventdispatcher_glib.cpp new file mode 100644 index 0000000000..3fa10eb7e9 --- /dev/null +++ b/src/widgets/kernel/qguieventdispatcher_glib.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguieventdispatcher_glib_p.h" + +#include "qapplication.h" +#include "qx11info_x11.h" + +#include "qt_x11_p.h" + +#include + +QT_BEGIN_NAMESPACE + +struct GX11EventSource +{ + GSource source; + GPollFD pollfd; + QEventLoop::ProcessEventsFlags flags; + QGuiEventDispatcherGlib *q; + QGuiEventDispatcherGlibPrivate *d; +}; + +class QGuiEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate +{ + Q_DECLARE_PUBLIC(QGuiEventDispatcherGlib) + +public: + QGuiEventDispatcherGlibPrivate(); + GX11EventSource *x11EventSource; + QList queuedUserInputEvents; +}; + +static gboolean x11EventSourcePrepare(GSource *s, gint *timeout) +{ + if (timeout) + *timeout = -1; + GX11EventSource *source = reinterpret_cast(s); + return (XEventsQueued(X11->display, QueuedAfterFlush) + || (!(source->flags & QEventLoop::ExcludeUserInputEvents) + && !source->d->queuedUserInputEvents.isEmpty())); +} + +static gboolean x11EventSourceCheck(GSource *s) +{ + GX11EventSource *source = reinterpret_cast(s); + return (XEventsQueued(X11->display, QueuedAfterFlush) + || (!(source->flags & QEventLoop::ExcludeUserInputEvents) + && !source->d->queuedUserInputEvents.isEmpty())); +} + +static gboolean x11EventSourceDispatch(GSource *s, GSourceFunc callback, gpointer user_data) +{ + GX11EventSource *source = reinterpret_cast(s); + + ulong marker = XNextRequest(X11->display); + do { + XEvent event; + if (!(source->flags & QEventLoop::ExcludeUserInputEvents) + && !source->d->queuedUserInputEvents.isEmpty()) { + // process a pending user input event + event = source->d->queuedUserInputEvents.takeFirst(); + } else if (XEventsQueued(X11->display, QueuedAlready)) { + // process events from the X server + XNextEvent(X11->display, &event); + + if (source->flags & QEventLoop::ExcludeUserInputEvents) { + // queue user input events + switch (event.type) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case XKeyPress: + case XKeyRelease: + case EnterNotify: + case LeaveNotify: + source->d->queuedUserInputEvents.append(event); + continue; + + case ClientMessage: + // only keep the wm_take_focus and + // _qt_scrolldone protocols, queue all other + // client messages + if (event.xclient.format == 32) { + if (event.xclient.message_type == ATOM(WM_PROTOCOLS) && + (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) { + break; + } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) { + break; + } + } + source->d->queuedUserInputEvents.append(event); + continue; + + default: + break; + } + } + } else { + // no event to process + break; + } + + // send through event filter + if (source->q->filterEvent(&event)) + continue; + + if (qApp->x11ProcessEvent(&event) == 1) + return true; + + if (event.xany.serial >= marker) + goto out; + } while (XEventsQueued(X11->display, QueuedAfterFlush)); + + out: + + source->d->runTimersOnceWithNormalPriority(); + + if (callback) + callback(user_data); + return true; +} + +static GSourceFuncs x11EventSourceFuncs = { + x11EventSourcePrepare, + x11EventSourceCheck, + x11EventSourceDispatch, + NULL, + NULL, + NULL +}; + +QGuiEventDispatcherGlibPrivate::QGuiEventDispatcherGlibPrivate() +{ + x11EventSource = reinterpret_cast(g_source_new(&x11EventSourceFuncs, + sizeof(GX11EventSource))); + g_source_set_can_recurse(&x11EventSource->source, true); + + memset(&x11EventSource->pollfd, 0, sizeof(GPollFD)); + x11EventSource->flags = QEventLoop::AllEvents; + x11EventSource->q = 0; + x11EventSource->d = 0; + + g_source_attach(&x11EventSource->source, mainContext); +} + +QGuiEventDispatcherGlib::QGuiEventDispatcherGlib(QObject *parent) + : QEventDispatcherGlib(*new QGuiEventDispatcherGlibPrivate, parent) +{ +} + +QGuiEventDispatcherGlib::~QGuiEventDispatcherGlib() +{ + Q_D(QGuiEventDispatcherGlib); + + g_source_remove_poll(&d->x11EventSource->source, &d->x11EventSource->pollfd); + g_source_destroy(&d->x11EventSource->source); + d->x11EventSource = 0; +} + +bool QGuiEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + Q_D(QGuiEventDispatcherGlib); + QEventLoop::ProcessEventsFlags saved_flags = d->x11EventSource->flags; + d->x11EventSource->flags = flags; + bool returnValue = QEventDispatcherGlib::processEvents(flags); + d->x11EventSource->flags = saved_flags; + return returnValue; +} + +void QGuiEventDispatcherGlib::startingUp() +{ + Q_D(QGuiEventDispatcherGlib); + d->x11EventSource->pollfd.fd = XConnectionNumber(X11->display); + d->x11EventSource->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + d->x11EventSource->q = this; + d->x11EventSource->d = d; + g_source_add_poll(&d->x11EventSource->source, &d->x11EventSource->pollfd); +} + +void QGuiEventDispatcherGlib::flush() +{ + XFlush(X11->display); +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qguieventdispatcher_glib_p.h b/src/widgets/kernel/qguieventdispatcher_glib_p.h new file mode 100644 index 0000000000..d37db93679 --- /dev/null +++ b/src/widgets/kernel/qguieventdispatcher_glib_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIEVENTDISPATCHER_GLIB_P_H +#define QGUIEVENTDISPATCHER_GLIB_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QGuiEventDispatcherGlibPrivate; + +class QGuiEventDispatcherGlib : public QEventDispatcherGlib +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGuiEventDispatcherGlib) + +public: + explicit QGuiEventDispatcherGlib(QObject *parent = 0); + ~QGuiEventDispatcherGlib(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + + void startingUp(); + void flush(); +}; + +QT_END_NAMESPACE + +#endif // QGUIEVENTDISPATCHER_GLIB_P_H diff --git a/src/widgets/kernel/qguiplatformplugin.cpp b/src/widgets/kernel/qguiplatformplugin.cpp new file mode 100644 index 0000000000..011b816e77 --- /dev/null +++ b/src/widgets/kernel/qguiplatformplugin.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguiplatformplugin_p.h" +#include +#include +#include +#include +#include "private/qfactoryloader_p.h" +#include "qstylefactory.h" +#include "qapplication.h" +#include "qplatformdefs.h" +#include "qicon.h" + +#ifdef Q_WS_WINCE +#include "qguifunctions_wince.h" +extern bool qt_wince_is_smartphone(); //qguifunctions_wince.cpp +extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp +extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp +#endif + + +#if defined(Q_WS_X11) +#include +#include +#include +#endif + + +QT_BEGIN_NAMESPACE + + +/*! \internal + Return (an construct if necesseray) the Gui Platform plugin. + + The plugin key to be loaded is inside the QT_PLATFORM_PLUGIN environment variable. + If it is not set, it will be the DESKTOP_SESSION on X11. + + If no plugin can be loaded, the default one is returned. + */ +QGuiPlatformPlugin *qt_guiPlatformPlugin() +{ + static QGuiPlatformPlugin *plugin; + if (!plugin) + { +#ifndef QT_NO_LIBRARY + + QString key = QString::fromLocal8Bit(qgetenv("QT_PLATFORM_PLUGIN")); +#ifdef Q_WS_X11 + if (key.isEmpty()) { + switch(X11->desktopEnvironment) { + case DE_KDE: + key = QString::fromLatin1("kde"); + break; + default: + key = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION")); + break; + } + } +#endif + + if (!key.isEmpty() && QApplication::desktopSettingsAware()) { + QFactoryLoader loader(QGuiPlatformPluginInterface_iid, QLatin1String("/gui_platform")); + plugin = qobject_cast(loader.instance(key)); + } +#endif // QT_NO_LIBRARY + + if(!plugin) { + static QGuiPlatformPlugin def; + plugin = &def; + } + } + return plugin; +} + + +/* \class QPlatformPlugin + QGuiPlatformPlugin can be used to integrate Qt applications in a platform built on top of Qt. + The application developer should not know or use the plugin, it is only used by Qt internaly. + + But full platform that are built on top of Qt may provide a plugin so 3rd party Qt application + running in the platform are integrated. + */ + +/* + The constructor can be used to install hooks in Qt + */ +QGuiPlatformPlugin::QGuiPlatformPlugin(QObject *parent) : QObject(parent) {} +QGuiPlatformPlugin::~QGuiPlatformPlugin() {} + + +/* return the string key to be used by default the application */ +QString QGuiPlatformPlugin::styleName() +{ +#if defined(Q_WS_WIN) && defined(Q_WS_WINCE) + if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) + return QLatin1String("WindowsMobile"); + else + return QLatin1String("WindowsCE"); +#elif defined(Q_WS_WIN) + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsVista"); + else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsXP"); + else + return QLatin1String("Windows"); // default styles for Windows +#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) + return QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + return QLatin1String("S60"); // default style for Symbian with S60 +#elif defined(Q_OS_SYMBIAN) + return QLatin1String("Windows"); // default style for Symbian without S60 +#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) + return QLatin1String("SGI"); // default style for X11 on IRIX +#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) + return QLatin1String("Plastique"); // default style for X11 and small devices +#elif defined(Q_WS_MAC) + return QLatin1String("Macintosh"); // default style for all Mac's +#elif defined(Q_WS_X11) + QString stylename; + switch(X11->desktopEnvironment) { + case DE_KDE: + stylename = QKde::kdeStyle(); + break; + case DE_GNOME: { + QStringList availableStyles = QStyleFactory::keys(); + // Set QGtkStyle for GNOME if available + QString gtkStyleKey = QString::fromLatin1("GTK+"); + if (availableStyles.contains(gtkStyleKey)) { + stylename = gtkStyleKey; + break; + } + if (X11->use_xrender) + stylename = QLatin1String("cleanlooks"); + else + stylename = QLatin1String("windows"); + break; + } + case DE_CDE: + stylename = QLatin1String("cde"); + break; + default: + // Don't do anything + break; + } + return stylename; +#endif +} + +/* return an additional default palette (only work on X11) */ +QPalette QGuiPlatformPlugin::palette() +{ +#ifdef Q_WS_X11 + if (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE) + return QKde::kdePalette(); +#endif + + return QPalette(); +} + +/* the default icon theme name for QIcon::fromTheme. */ +QString QGuiPlatformPlugin::systemIconThemeName() +{ + QString result; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_GNOME) { + result = QString::fromLatin1("gnome"); +#ifndef QT_NO_STYLE_GTK + result = QGtkStylePrivate::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), result); +#endif + } else if (X11->desktopEnvironment == DE_KDE) { + result = X11->desktopVersion >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + settings.beginGroup(QLatin1String("Icons")); + result = settings.value(QLatin1String("Theme"), result).toString(); + } +#endif + return result; +} + + +QStringList QGuiPlatformPlugin::iconThemeSearchPaths() +{ + QStringList paths; +#if defined(Q_WS_X11) + QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); + if (xdgDirString.isEmpty()) + xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); + + QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); + + for (int i = 0 ; i < xdgDirs.size() ; ++i) { + QDir dir(xdgDirs[i]); + if (dir.exists()) + paths.append(dir.path() + QLatin1String("/icons")); + } + if (X11->desktopEnvironment == DE_KDE) { + paths << QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share/icons"); + QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); + for (int i = 0 ; i< kdeDirs.count() ; ++i) { + QDir dir(QLatin1Char(':') + kdeDirs.at(i) + QLatin1String("/share/icons")); + if (dir.exists()) + paths.append(dir.path()); + } + } + + // Add home directory first in search path + QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); + if (homeDir.exists()) + paths.prepend(homeDir.path()); +#endif + +#if defined(Q_WS_WIN) + paths.append(qApp->applicationDirPath() + QLatin1String("/icons")); +#elif defined(Q_WS_MAC) + paths.append(qApp->applicationDirPath() + QLatin1String("/../Resources/icons")); +#endif + return paths; +} + +/* backend for QFileIconProvider, null icon means default */ +QIcon QGuiPlatformPlugin::fileSystemIcon(const QFileInfo &) +{ + return QIcon(); +} + +/* Like QStyle::styleHint */ +int QGuiPlatformPlugin::platformHint(PlatformHint hint) +{ + int ret = 0; + switch(hint) + { + case PH_ToolButtonStyle: + ret = Qt::ToolButtonIconOnly; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolButtonStyle(); + } +#endif + break; + case PH_ToolBarIconSize: +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolBarIconSize(); + } +#endif + //by default keep ret = 0 so QCommonStyle will use the style default + break; + default: + break; + } + return ret; +} + + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qguiplatformplugin_p.h b/src/widgets/kernel/qguiplatformplugin_p.h new file mode 100644 index 0000000000..49e2d9294a --- /dev/null +++ b/src/widgets/kernel/qguiplatformplugin_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIPLATFORM_P_H +#define QGUIPLATFORM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStyle; +class QPalette; +class QIcon; +class QFileDialog; +class QColorDialog; +class QFileInfo; + +struct Q_GUI_EXPORT QGuiPlatformPluginInterface : public QFactoryInterface +{ +}; + +#define QGuiPlatformPluginInterface_iid "com.nokia.qt.QGuiPlatformPluginInterface" + +Q_DECLARE_INTERFACE(QGuiPlatformPluginInterface, QGuiPlatformPluginInterface_iid) + +class Q_GUI_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QGuiPlatformPluginInterface:QFactoryInterface) + public: + explicit QGuiPlatformPlugin(QObject *parent = 0); + ~QGuiPlatformPlugin(); + + virtual QStringList keys() const { return QStringList() << QLatin1String("default"); }; + + virtual QString styleName(); + virtual QPalette palette(); + virtual QString systemIconThemeName(); + virtual QStringList iconThemeSearchPaths(); + virtual QIcon fileSystemIcon(const QFileInfo &); + + enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; + virtual int platformHint(PlatformHint hint); + + + virtual void fileDialogDelete(QFileDialog *) {} + virtual bool fileDialogSetVisible(QFileDialog *, bool) { return false; } + virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *) { return QDialog::Rejected; } + virtual void fileDialogSetDirectory(QFileDialog *, const QString &) {} + virtual QString fileDialogDirectory(const QFileDialog *) const { return QString(); } + virtual void fileDialogSelectFile(QFileDialog *, const QString &) {} + virtual QStringList fileDialogSelectedFiles(const QFileDialog *) const { return QStringList(); } + virtual void fileDialogSetFilter(QFileDialog *) {} + virtual void fileDialogSetNameFilters(QFileDialog *, const QStringList &) {} + virtual void fileDialogSelectNameFilter(QFileDialog *, const QString &) {} + virtual QString fileDialogSelectedNameFilter(const QFileDialog *) const { return QString(); } + + virtual void colorDialogDelete(QColorDialog *) {} + virtual bool colorDialogSetVisible(QColorDialog *, bool) { return false; } + virtual void colorDialogSetCurrentColor(QColorDialog *, const QColor &) {} +}; + +//internal +QGuiPlatformPlugin *qt_guiPlatformPlugin(); + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGUIPLATFORMPLUGIN_H diff --git a/src/widgets/kernel/qicon.cpp b/src/widgets/kernel/qicon.cpp new file mode 100644 index 0000000000..59687c709d --- /dev/null +++ b/src/widgets/kernel/qicon.cpp @@ -0,0 +1,1165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qicon.h" +#include "qicon_p.h" +#include "qiconengine.h" +#include "qiconengineplugin.h" +#include "private/qfactoryloader_p.h" +#include "private/qiconloader_p.h" +#include "qstyleoption.h" +#include "qpainter.h" +#include "qfileinfo.h" +#include "qstyle.h" +#include "qpixmapcache.h" +#include "qvariant.h" +#include "qcache.h" +#include "qdebug.h" +#include "private/qguiplatformplugin_p.h" +#include "qguiapplication.h" + +#ifdef Q_WS_MAC +#include +#include +#endif + +#ifdef Q_WS_X11 +#include "private/qt_x11_p.h" +#include "private/qkde_p.h" +#endif + +#include "private/qhexstring_p.h" + +#ifndef QT_NO_ICON +QT_BEGIN_NAMESPACE + +/*! + \enum QIcon::Mode + + This enum type describes the mode for which a pixmap is intended + to be used. The currently defined modes are: + + \value Normal + Display the pixmap when the user is + not interacting with the icon, but the + functionality represented by the icon is available. + \value Disabled + Display the pixmap when the + functionality represented by the icon is not available. + \value Active + Display the pixmap when the + functionality represented by the icon is available and + the user is interacting with the icon, for example, moving the + mouse over it or clicking it. + \value Selected + Display the pixmap when the item represented by the icon is + selected. +*/ + +/*! + \enum QIcon::State + + This enum describes the state for which a pixmap is intended to be + used. The \e state can be: + + \value Off Display the pixmap when the widget is in an "off" state + \value On Display the pixmap when the widget is in an "on" state +*/ + +static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1); + +static void qt_cleanup_icon_cache(); +typedef QCache IconCache; +Q_GLOBAL_STATIC_WITH_INITIALIZER(IconCache, qtIconCache, qAddPostRoutine(qt_cleanup_icon_cache)) + +static void qt_cleanup_icon_cache() +{ + qtIconCache()->clear(); +} + +QIconPrivate::QIconPrivate() + : engine(0), ref(1), + serialNum(serialNumCounter.fetchAndAddRelaxed(1)), + detach_no(0), + engine_version(2), + v1RefCount(0) +{ +} + +QPixmapIconEngine::QPixmapIconEngine() +{ +} + +QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other) + : QIconEngineV2(other), pixmaps(other.pixmaps) +{ +} + +QPixmapIconEngine::~QPixmapIconEngine() +{ +} + +void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) +{ + QSize pixmapSize = rect.size(); +#if defined(Q_WS_MAC) + pixmapSize *= qt_mac_get_scalefactor(); +#endif + painter->drawPixmap(rect, pixmap(pixmapSize, mode, state)); +} + +static inline int area(const QSize &s) { return s.width() * s.height(); } + +// returns the smallest of the two that is still larger than or equal to size. +static QPixmapIconEngineEntry *bestSizeMatch( const QSize &size, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb) +{ + int s = area(size); + if (pa->size == QSize() && pa->pixmap.isNull()) { + pa->pixmap = QPixmap(pa->fileName); + pa->size = pa->pixmap.size(); + } + int a = area(pa->size); + if (pb->size == QSize() && pb->pixmap.isNull()) { + pb->pixmap = QPixmap(pb->fileName); + pb->size = pb->pixmap.size(); + } + int b = area(pb->size); + int res = a; + if (qMin(a,b) >= s) + res = qMin(a,b); + else + res = qMax(a,b); + if (res == a) + return pa; + return pb; +} + +QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + QPixmapIconEngineEntry *pe = 0; + for (int i = 0; i < pixmaps.count(); ++i) + if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) { + if (pe) + pe = bestSizeMatch(size, &pixmaps[i], pe); + else + pe = &pixmaps[i]; + } + return pe; +} + + +QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly) +{ + QPixmapIconEngineEntry *pe = tryMatch(size, mode, state); + while (!pe){ + QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On; + if (mode == QIcon::Disabled || mode == QIcon::Selected) { + QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled; + if ((pe = tryMatch(size, QIcon::Normal, state))) + break; + if ((pe = tryMatch(size, QIcon::Active, state))) + break; + if ((pe = tryMatch(size, mode, oppositeState))) + break; + if ((pe = tryMatch(size, QIcon::Normal, oppositeState))) + break; + if ((pe = tryMatch(size, QIcon::Active, oppositeState))) + break; + if ((pe = tryMatch(size, oppositeMode, state))) + break; + if ((pe = tryMatch(size, oppositeMode, oppositeState))) + break; + } else { + QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal; + if ((pe = tryMatch(size, oppositeMode, state))) + break; + if ((pe = tryMatch(size, mode, oppositeState))) + break; + if ((pe = tryMatch(size, oppositeMode, oppositeState))) + break; + if ((pe = tryMatch(size, QIcon::Disabled, state))) + break; + if ((pe = tryMatch(size, QIcon::Selected, state))) + break; + if ((pe = tryMatch(size, QIcon::Disabled, oppositeState))) + break; + if ((pe = tryMatch(size, QIcon::Selected, oppositeState))) + break; + } + + if (!pe) + return pe; + } + + if (sizeOnly ? (pe->size.isNull() || !pe->size.isValid()) : pe->pixmap.isNull()) { + pe->pixmap = QPixmap(pe->fileName); + if (!pe->pixmap.isNull()) + pe->size = pe->pixmap.size(); + } + + return pe; +} + +QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + QPixmap pm; + QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, false); + if (pe) + pm = pe->pixmap; + + if (pm.isNull()) { + int idx = pixmaps.count(); + while (--idx >= 0) { + if (pe == &pixmaps[idx]) { + pixmaps.remove(idx); + break; + } + } + if (pixmaps.isEmpty()) + return pm; + else + return pixmap(size, mode, state); + } + + QSize actualSize = pm.size(); + if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height())) + actualSize.scale(size, Qt::KeepAspectRatio); + + // #### Qt5 no idea what this really does, but we need to remove the QApp and style references +// QString key = QLatin1Literal("qt_") +// % HexString(pm.cacheKey()) +// % HexString(pe->mode) +// % HexString(QApplication::palette().cacheKey()) +// % HexString(actualSize.width()) +// % HexString(actualSize.height()); + +// if (mode == QIcon::Active) { +// if (QPixmapCache::find(key % HexString(mode), pm)) +// return pm; // horray +// if (QPixmapCache::find(key % HexString(QIcon::Normal), pm)) { +// QStyleOption opt(0); +// opt.palette = QApplication::palette(); +// QPixmap active = QApplication::style()->generatedIconPixmap(QIcon::Active, pm, &opt); +// if (pm.cacheKey() == active.cacheKey()) +// return pm; +// } +// } + +// if (!QPixmapCache::find(key % HexString(mode), pm)) { + if (pm.size() != actualSize) + pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); +// if (pe->mode != mode && mode != QIcon::Normal) { +// QStyleOption opt(0); +// opt.palette = QApplication::palette(); +// QPixmap generated = QApplication::style()->generatedIconPixmap(mode, pm, &opt); +// if (!generated.isNull()) +// pm = generated; +// } +// QPixmapCache::insert(key % HexString(mode), pm); +// } + return pm; +} + +QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + QSize actualSize; + if (QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, true)) + actualSize = pe->size; + + if (actualSize.isNull()) + return actualSize; + + if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height())) + actualSize.scale(size, Qt::KeepAspectRatio); + return actualSize; +} + +void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) +{ + if (!pixmap.isNull()) { + QPixmapIconEngineEntry *pe = tryMatch(pixmap.size(), mode, state); + if(pe && pe->size == pixmap.size()) { + pe->pixmap = pixmap; + pe->fileName.clear(); + } else { + pixmaps += QPixmapIconEngineEntry(pixmap, mode, state); + } + } +} + +void QPixmapIconEngine::addFile(const QString &fileName, const QSize &_size, QIcon::Mode mode, QIcon::State state) +{ + if (!fileName.isEmpty()) { + QSize size = _size; + QPixmap pixmap; + + QString abs = fileName; + if (fileName.at(0) != QLatin1Char(':')) + abs = QFileInfo(fileName).absoluteFilePath(); + + for (int i = 0; i < pixmaps.count(); ++i) { + if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) { + QPixmapIconEngineEntry *pe = &pixmaps[i]; + if(size == QSize()) { + pixmap = QPixmap(abs); + size = pixmap.size(); + } + if (pe->size == QSize() && pe->pixmap.isNull()) { + pe->pixmap = QPixmap(pe->fileName); + pe->size = pe->pixmap.size(); + } + if(pe->size == size) { + pe->pixmap = pixmap; + pe->fileName = abs; + return; + } + } + } + QPixmapIconEngineEntry e(abs, size, mode, state); + e.pixmap = pixmap; + pixmaps += e; + } +} + +QString QPixmapIconEngine::key() const +{ + return QLatin1String("QPixmapIconEngine"); +} + +QIconEngineV2 *QPixmapIconEngine::clone() const +{ + return new QPixmapIconEngine(*this); +} + +bool QPixmapIconEngine::read(QDataStream &in) +{ + int num_entries; + QPixmap pm; + QString fileName; + QSize sz; + uint mode; + uint state; + + in >> num_entries; + for (int i=0; i < num_entries; ++i) { + if (in.atEnd()) { + pixmaps.clear(); + return false; + } + in >> pm; + in >> fileName; + in >> sz; + in >> mode; + in >> state; + if (pm.isNull()) { + addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state)); + } else { + QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state)); + pe.pixmap = pm; + pixmaps += pe; + } + } + return true; +} + +bool QPixmapIconEngine::write(QDataStream &out) const +{ + int num_entries = pixmaps.size(); + out << num_entries; + for (int i=0; i < num_entries; ++i) { + if (pixmaps.at(i).pixmap.isNull()) + out << QPixmap(pixmaps.at(i).fileName); + else + out << pixmaps.at(i).pixmap; + out << pixmaps.at(i).fileName; + out << pixmaps.at(i).size; + out << (uint) pixmaps.at(i).mode; + out << (uint) pixmaps.at(i).state; + } + return true; +} + +void QPixmapIconEngine::virtual_hook(int id, void *data) +{ + switch (id) { + case QIconEngineV2::AvailableSizesHook: { + QIconEngineV2::AvailableSizesArgument &arg = + *reinterpret_cast(data); + arg.sizes.clear(); + for (int i = 0; i < pixmaps.size(); ++i) { + QPixmapIconEngineEntry &pe = pixmaps[i]; + if (pe.size == QSize() && pe.pixmap.isNull()) { + pe.pixmap = QPixmap(pe.fileName); + pe.size = pe.pixmap.size(); + } + if (pe.mode == arg.mode && pe.state == arg.state && !pe.size.isEmpty()) + arg.sizes.push_back(pe.size); + } + break; + } + default: + QIconEngineV2::virtual_hook(id, data); + } +} + +#ifndef QT_NO_LIBRARY +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive)) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loaderV2, + (QIconEngineFactoryInterfaceV2_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive)) +#endif + + + +/*! + \class QIcon + + \brief The QIcon class provides scalable icons in different modes + and states. + + \ingroup painting + \ingroup shared + + + A QIcon can generate smaller, larger, active, and disabled pixmaps + from the set of pixmaps it is given. Such pixmaps are used by Qt + widgets to show an icon representing a particular action. + + The simplest use of QIcon is to create one from a QPixmap file or + resource, and then use it, allowing Qt to work out all the required + icon styles and sizes. For example: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 0 + + To undo a QIcon, simply set a null icon in its place: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 1 + + Use the QImageReader::supportedImageFormats() and + QImageWriter::supportedImageFormats() functions to retrieve a + complete list of the supported file formats. + + When you retrieve a pixmap using pixmap(QSize, Mode, State), and no + pixmap for this given size, mode and state has been added with + addFile() or addPixmap(), then QIcon will generate one on the + fly. This pixmap generation happens in a QIconEngineV2. The default + engine scales pixmaps down if required, but never up, and it uses + the current style to calculate a disabled appearance. By using + custom icon engines, you can customize every aspect of generated + icons. With QIconEnginePluginV2 it is possible to register different + icon engines for different file suffixes, making it possible for + third parties to provide additional icon engines to those included + with Qt. + + \note Since Qt 4.2, an icon engine that supports SVG is included. + + \section1 Making Classes that Use QIcon + + If you write your own widgets that have an option to set a small + pixmap, consider allowing a QIcon to be set for that pixmap. The + Qt class QToolButton is an example of such a widget. + + Provide a method to set a QIcon, and when you draw the icon, choose + whichever pixmap is appropriate for the current state of your widget. + For example: + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 2 + + You might also make use of the \c Active mode, perhaps making your + widget \c Active when the mouse is over the widget (see \l + QWidget::enterEvent()), while the mouse is pressed pending the + release that will activate the function, or when it is the currently + selected item. If the widget can be toggled, the "On" mode might be + used to draw a different icon. + + \img icon.png QIcon + + \sa {fowler}{GUI Design Handbook: Iconic Label}, {Icons Example} +*/ + + +/*! + Constructs a null icon. +*/ +QIcon::QIcon() + : d(0) +{ +} + +/*! + Constructs an icon from a \a pixmap. + */ +QIcon::QIcon(const QPixmap &pixmap) + :d(0) +{ + addPixmap(pixmap); +} + +/*! + Constructs a copy of \a other. This is very fast. +*/ +QIcon::QIcon(const QIcon &other) + :d(other.d) +{ + if (d) + d->ref.ref(); +} + +/*! + Constructs an icon from the file with the given \a fileName. The + file will be loaded on demand. + + If \a fileName contains a relative path (e.g. the filename only) + the relevant file must be found relative to the runtime working + directory. + + The file name can be either refer to an actual file on disk or to + one of the application's embedded resources. See the + \l{resources.html}{Resource System} overview for details on how to + embed images and other resource files in the application's + executable. + + Use the QImageReader::supportedImageFormats() and + QImageWriter::supportedImageFormats() functions to retrieve a + complete list of the supported file formats. +*/ +QIcon::QIcon(const QString &fileName) + : d(0) +{ + addFile(fileName); +} + + +/*! + Creates an icon with a specific icon \a engine. The icon takes + ownership of the engine. +*/ +QIcon::QIcon(QIconEngine *engine) + :d(new QIconPrivate) +{ + d->engine_version = 1; + d->engine = engine; + d->v1RefCount = new QAtomicInt(1); +} + +/*! + Creates an icon with a specific icon \a engine. The icon takes + ownership of the engine. +*/ +QIcon::QIcon(QIconEngineV2 *engine) + :d(new QIconPrivate) +{ + d->engine_version = 2; + d->engine = engine; +} + +/*! + Destroys the icon. +*/ +QIcon::~QIcon() +{ + if (d && !d->ref.deref()) + delete d; +} + +/*! + Assigns the \a other icon to this icon and returns a reference to + this icon. +*/ +QIcon &QIcon::operator=(const QIcon &other) +{ + if (other.d) + other.d->ref.ref(); + if (d && !d->ref.deref()) + delete d; + d = other.d; + return *this; +} + +/*! + \fn void QIcon::swap(QIcon &other) + \since 4.8 + + Swaps icon \a other with this icon. This operation is very + fast and never fails. +*/ + +/*! + Returns the icon as a QVariant. +*/ +QIcon::operator QVariant() const +{ + return QVariant(QVariant::Icon, this); +} + +/*! \obsolete + + Returns a number that identifies the contents of this + QIcon object. Distinct QIcon objects can have + the same serial number if they refer to the same contents + (but they don't have to). Also, the serial number of + a QIcon object may change during its lifetime. + + Use cacheKey() instead. + + A null icon always has a serial number of 0. + + Serial numbers are mostly useful in conjunction with caching. + + \sa QPixmap::serialNumber() +*/ + +int QIcon::serialNumber() const +{ + return d ? d->serialNum : 0; +} + +/*! + Returns a number that identifies the contents of this QIcon + object. Distinct QIcon objects can have the same key if + they refer to the same contents. + \since 4.3 + + The cacheKey() will change when the icon is altered via + addPixmap() or addFile(). + + Cache keys are mostly useful in conjunction with caching. + + \sa QPixmap::cacheKey() +*/ +qint64 QIcon::cacheKey() const +{ + if (!d) + return 0; + return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no)); +} + +/*! + Returns a pixmap with the requested \a size, \a mode, and \a + state, generating one if necessary. The pixmap might be smaller than + requested, but never larger. + + \sa actualSize(), paint() +*/ +QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const +{ + if (!d) + return QPixmap(); + return d->engine->pixmap(size, mode, state); +} + +/*! + \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const + + \overload + + Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than + requested, but never larger. +*/ + +/*! + \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const + + \overload + + Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller + than requested, but never larger. +*/ + +/*! Returns the actual size of the icon for the requested \a size, \a + mode, and \a state. The result might be smaller than requested, but + never larger. + + \sa pixmap(), paint() +*/ +QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const +{ + if (!d) + return QSize(); + return d->engine->actualSize(size, mode, state); +} + + +/*! + Uses the \a painter to paint the icon with specified \a alignment, + required \a mode, and \a state into the rectangle \a rect. + + \sa actualSize(), pixmap() +*/ +void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const +{ + if (!d || !painter) + return; + QRect alignedRect = QStyle::alignedRect(painter->layoutDirection(), alignment, d->engine->actualSize(rect.size(), mode, state), rect); + d->engine->paint(painter, alignedRect, mode, state); +} + +/*! + \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment, + Mode mode, State state) const + + \overload + + Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h). +*/ + +/*! + Returns true if the icon is empty; otherwise returns false. + + An icon is empty if it has neither a pixmap nor a filename. + + Note: Even a non-null icon might not be able to create valid + pixmaps, eg. if the file does not exist or cannot be read. +*/ +bool QIcon::isNull() const +{ + return !d; +} + +/*!\internal + */ +bool QIcon::isDetached() const +{ + return !d || d->ref == 1; +} + +/*! \internal + */ +void QIcon::detach() +{ + if (d) { + if (d->ref != 1) { + QIconPrivate *x = new QIconPrivate; + if (d->engine_version > 1) { + QIconEngineV2 *engine = static_cast(d->engine); + x->engine = engine->clone(); + } else { + x->engine = d->engine; + x->v1RefCount = d->v1RefCount; + x->v1RefCount->ref(); + } + x->engine_version = d->engine_version; + if (!d->ref.deref()) + delete d; + d = x; + } + ++d->detach_no; + } +} + +/*! + Adds \a pixmap to the icon, as a specialization for \a mode and + \a state. + + Custom icon engines are free to ignore additionally added + pixmaps. + + \sa addFile() +*/ +void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state) +{ + if (pixmap.isNull()) + return; + if (!d) { + d = new QIconPrivate; + d->engine = new QPixmapIconEngine; + } else { + detach(); + } + d->engine->addPixmap(pixmap, mode, state); +} + + +/*! Adds an image from the file with the given \a fileName to the + icon, as a specialization for \a size, \a mode and \a state. The + file will be loaded on demand. Note: custom icon engines are free + to ignore additionally added pixmaps. + + If \a fileName contains a relative path (e.g. the filename only) + the relevant file must be found relative to the runtime working + directory. + + The file name can be either refer to an actual file on disk or to + one of the application's embedded resources. See the + \l{resources.html}{Resource System} overview for details on how to + embed images and other resource files in the application's + executable. + + Use the QImageReader::supportedImageFormats() and + QImageWriter::supportedImageFormats() functions to retrieve a + complete list of the supported file formats. + + Note: When you add a non-empty filename to a QIcon, the icon becomes + non-null, even if the file doesn't exist or points to a corrupt file. + + \sa addPixmap() + */ +void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state) +{ + if (fileName.isEmpty()) + return; + if (!d) { +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QFileInfo info(fileName); + QString suffix = info.suffix(); + if (!suffix.isEmpty()) { + // first try version 2 engines.. + if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast(loaderV2()->instance(suffix))) { + if (QIconEngine *engine = factory->create(fileName)) { + d = new QIconPrivate; + d->engine = engine; + } + } + // ..then fall back and try to load version 1 engines + if (!d) { + if (QIconEngineFactoryInterface *factory = qobject_cast(loader()->instance(suffix))) { + if (QIconEngine *engine = factory->create(fileName)) { + d = new QIconPrivate; + d->engine = engine; + d->engine_version = 1; + d->v1RefCount = new QAtomicInt(1); + } + } + } + } +#endif + // ...then fall back to the default engine + if (!d) { + d = new QIconPrivate; + d->engine = new QPixmapIconEngine; + } + } else { + detach(); + } + d->engine->addFile(fileName, size, mode, state); +} + +/*! + \since 4.5 + + Returns a list of available icon sizes for the specified \a mode and + \a state. +*/ +QList QIcon::availableSizes(Mode mode, State state) const +{ + if (!d || !d->engine || d->engine_version < 2) + return QList(); + QIconEngineV2 *engine = static_cast(d->engine); + return engine->availableSizes(mode, state); +} + +/*! + \since 4.7 + + Returns the name used to create the icon, if available. + + Depending on the way the icon was created, it may have an associated + name. This is the case for icons created with fromTheme() or icons + using a QIconEngine which supports the QIconEngineV2::IconNameHook. + + \sa fromTheme(), QIconEngine +*/ +QString QIcon::name() const +{ + if (!d || !d->engine || d->engine_version < 2) + return QString(); + QIconEngineV2 *engine = static_cast(d->engine); + return engine->iconName(); +} + +/*! + \since 4.6 + + Sets the search paths for icon themes to \a paths. + \sa themeSearchPaths(), fromTheme(), setThemeName() +*/ +void QIcon::setThemeSearchPaths(const QStringList &paths) +{ + QIconLoader::instance()->setThemeSearchPath(paths); +} + +/*! + \since 4.6 + + Returns the search paths for icon themes. + + The default value will depend on the platform: + + On X11, the search path will use the XDG_DATA_DIRS environment + variable if available. + + By default all platforms will have the resource directory + \c{:\icons} as a fallback. You can use "rcc -project" to generate a + resource file from your icon theme. + + \sa setThemeSearchPaths(), fromTheme(), setThemeName() +*/ +QStringList QIcon::themeSearchPaths() +{ + return QIconLoader::instance()->themeSearchPaths(); +} + +/*! + \since 4.6 + + Sets the current icon theme to \a name. + + The \a name should correspond to a directory name in the + themeSearchPath() containing an index.theme + file describing it's contents. + + \sa themeSearchPaths(), themeName() +*/ +void QIcon::setThemeName(const QString &name) +{ + QIconLoader::instance()->setThemeName(name); +} + +/*! + \since 4.6 + + Returns the name of the current icon theme. + + On X11, the current icon theme depends on your desktop + settings. On other platforms it is not set by default. + + \sa setThemeName(), themeSearchPaths(), fromTheme(), + hasThemeIcon() +*/ +QString QIcon::themeName() +{ + return QIconLoader::instance()->themeName(); +} + +/*! + \since 4.6 + + Returns the QIcon corresponding to \a name in the current + icon theme. If no such icon is found in the current theme + \a fallback is returned instead. + + The latest version of the freedesktop icon specification and naming + specification can be obtained here: + + \list + \o \l{http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html} + \o \l{http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html} + \endlist + + To fetch an icon from the current icon theme: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 3 + + Or if you want to provide a guaranteed fallback for platforms that + do not support theme icons, you can use the second argument: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 4 + + \note By default, only X11 will support themed icons. In order to + use themed icons on Mac and Windows, you will have to bundle a + compliant theme in one of your themeSearchPaths() and set the + appropriate themeName(). + + \sa themeName(), setThemeName(), themeSearchPaths() +*/ +QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) +{ + QIcon icon; + + if (qtIconCache()->contains(name)) { + icon = *qtIconCache()->object(name); + } else { + QIcon *cachedIcon = new QIcon(new QIconLoaderEngine(name)); + qtIconCache()->insert(name, cachedIcon); + icon = *cachedIcon; + } + + // Note the qapp check is to allow lazy loading of static icons + // Supporting fallbacks will not work for this case. + if (qApp && icon.availableSizes().isEmpty()) + return fallback; + + return icon; +} + +/*! + \since 4.6 + + Returns true if there is an icon available for \a name in the + current icon theme, otherwise returns false. + + \sa themeSearchPaths(), fromTheme(), setThemeName() +*/ +bool QIcon::hasThemeIcon(const QString &name) +{ + QIcon icon = fromTheme(name); + + return !icon.isNull(); +} + + +/***************************************************************************** + QIcon stream functions + *****************************************************************************/ +#if !defined(QT_NO_DATASTREAM) +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon) + \relates QIcon + \since 4.2 + + Writes the given \a icon to the given \a stream as a PNG + image. If the icon contains more than one image, all images will + be written to the stream. Note that writing the stream to a file + will not produce a valid image file. +*/ + +QDataStream &operator<<(QDataStream &s, const QIcon &icon) +{ + if (s.version() >= QDataStream::Qt_4_3) { + if (icon.isNull()) { + s << QString(); + } else { + if (icon.d->engine_version > 1) { + QIconEngineV2 *engine = static_cast(icon.d->engine); + s << engine->key(); + engine->write(s); + } else { + // not really supported + qWarning("QIcon: Cannot stream QIconEngine. Use QIconEngineV2 instead."); + } + } + } else if (s.version() == QDataStream::Qt_4_2) { + if (icon.isNull()) { + s << 0; + } else { + QPixmapIconEngine *engine = static_cast(icon.d->engine); + int num_entries = engine->pixmaps.size(); + s << num_entries; + for (int i=0; i < num_entries; ++i) { + s << engine->pixmaps.at(i).pixmap; + s << engine->pixmaps.at(i).fileName; + s << engine->pixmaps.at(i).size; + s << (uint) engine->pixmaps.at(i).mode; + s << (uint) engine->pixmaps.at(i).state; + } + } + } else { + s << QPixmap(icon.pixmap(22,22)); + } + return s; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon) + \relates QIcon + \since 4.2 + + Reads an image, or a set of images, from the given \a stream into + the given \a icon. +*/ + +QDataStream &operator>>(QDataStream &s, QIcon &icon) +{ + if (s.version() >= QDataStream::Qt_4_3) { + icon = QIcon(); + QString key; + s >> key; + if (key == QLatin1String("QPixmapIconEngine")) { + icon.d = new QIconPrivate; + QIconEngineV2 *engine = new QPixmapIconEngine; + icon.d->engine = engine; + engine->read(s); + } else if (key == QLatin1String("QIconLoaderEngine")) { + icon.d = new QIconPrivate; + QIconEngineV2 *engine = new QIconLoaderEngine(); + icon.d->engine = engine; + engine->read(s); +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + } else if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast(loaderV2()->instance(key))) { + if (QIconEngineV2 *engine= factory->create()) { + icon.d = new QIconPrivate; + icon.d->engine = engine; + engine->read(s); + } +#endif + } + } else if (s.version() == QDataStream::Qt_4_2) { + icon = QIcon(); + int num_entries; + QPixmap pm; + QString fileName; + QSize sz; + uint mode; + uint state; + + s >> num_entries; + for (int i=0; i < num_entries; ++i) { + s >> pm; + s >> fileName; + s >> sz; + s >> mode; + s >> state; + if (pm.isNull()) + icon.addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state)); + else + icon.addPixmap(pm, QIcon::Mode(mode), QIcon::State(state)); + } + } else { + QPixmap pm; + s >> pm; + icon.addPixmap(pm); + } + return s; +} + +#endif //QT_NO_DATASTREAM + +/*! + \fn DataPtr &QIcon::data_ptr() + \internal +*/ + +/*! + \typedef QIcon::DataPtr + \internal +*/ + +QT_END_NAMESPACE +#endif //QT_NO_ICON diff --git a/src/widgets/kernel/qicon.h b/src/widgets/kernel/qicon.h new file mode 100644 index 0000000000..4e3960925e --- /dev/null +++ b/src/widgets/kernel/qicon.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICON_H +#define QICON_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QIconPrivate; +class QIconEngine; +class QIconEngineV2; + +class Q_GUI_EXPORT QIcon +{ +public: + enum Mode { Normal, Disabled, Active, Selected }; + enum State { On, Off }; + + QIcon(); + QIcon(const QPixmap &pixmap); + QIcon(const QIcon &other); + explicit QIcon(const QString &fileName); // file or resource name + explicit QIcon(QIconEngine *engine); + explicit QIcon(QIconEngineV2 *engine); + ~QIcon(); + QIcon &operator=(const QIcon &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QIcon &operator=(QIcon &&other) + { qSwap(d, other.d); return *this; } +#endif + inline void swap(QIcon &other) { qSwap(d, other.d); } + + operator QVariant() const; + + QPixmap pixmap(const QSize &size, Mode mode = Normal, State state = Off) const; + inline QPixmap pixmap(int w, int h, Mode mode = Normal, State state = Off) const + { return pixmap(QSize(w, h), mode, state); } + inline QPixmap pixmap(int extent, Mode mode = Normal, State state = Off) const + { return pixmap(QSize(extent, extent), mode, state); } + + QSize actualSize(const QSize &size, Mode mode = Normal, State state = Off) const; + + QString name() const; + + void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment = Qt::AlignCenter, Mode mode = Normal, State state = Off) const; + inline void paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment = Qt::AlignCenter, Mode mode = Normal, State state = Off) const + { paint(painter, QRect(x, y, w, h), alignment, mode, state); } + + bool isNull() const; + bool isDetached() const; + void detach(); + + int serialNumber() const; + qint64 cacheKey() const; + + void addPixmap(const QPixmap &pixmap, Mode mode = Normal, State state = Off); + void addFile(const QString &fileName, const QSize &size = QSize(), Mode mode = Normal, State state = Off); + + QList availableSizes(Mode mode = Normal, State state = Off) const; + + static QIcon fromTheme(const QString &name, const QIcon &fallback = QIcon()); + static bool hasThemeIcon(const QString &name); + + static QStringList themeSearchPaths(); + static void setThemeSearchPaths(const QStringList &searchpath); + + static QString themeName(); + static void setThemeName(const QString &path); + + Q_DUMMY_COMPARISON_OPERATOR(QIcon) + +private: + QIconPrivate *d; +#if !defined(QT_NO_DATASTREAM) + friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QIcon &); + friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QIcon &); +#endif + +public: + typedef QIconPrivate * DataPtr; + inline DataPtr &data_ptr() { return d; } +}; + +Q_DECLARE_SHARED(QIcon) +Q_DECLARE_TYPEINFO(QIcon, Q_MOVABLE_TYPE); + +#if !defined(QT_NO_DATASTREAM) +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QIcon &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QIcon &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QICON_H diff --git a/src/widgets/kernel/qicon_p.h b/src/widgets/kernel/qicon_p.h new file mode 100644 index 0000000000..0bf7e65cc1 --- /dev/null +++ b/src/widgets/kernel/qicon_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICON_P_H +#define QICON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_ICON +QT_BEGIN_NAMESPACE + +class QIconPrivate +{ +public: + QIconPrivate(); + + ~QIconPrivate() { + if (engine_version == 1) { + if (!v1RefCount->deref()) { + delete engine; + delete v1RefCount; + } + } else if (engine_version == 2) { + delete engine; + } + } + + QIconEngine *engine; + + QAtomicInt ref; + int serialNum; + int detach_no; + int engine_version; + + QAtomicInt *v1RefCount; +}; + + +struct QPixmapIconEngineEntry +{ + QPixmapIconEngineEntry():mode(QIcon::Normal), state(QIcon::Off){} + QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) + :pixmap(pm), size(pm.size()), mode(m), state(s){} + QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) + :fileName(file), size(sz), mode(m), state(s){} + QPixmap pixmap; + QString fileName; + QSize size; + QIcon::Mode mode; + QIcon::State state; + bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); } +}; + + + +class QPixmapIconEngine : public QIconEngineV2 { +public: + QPixmapIconEngine(); + QPixmapIconEngine(const QPixmapIconEngine &); + ~QPixmapIconEngine(); + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly); + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); + void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state); + void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state); + + // v2 functions + QString key() const; + QIconEngineV2 *clone() const; + bool read(QDataStream &in); + bool write(QDataStream &out) const; + void virtual_hook(int id, void *data); + +private: + QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state); + QVector pixmaps; + + friend QDataStream &operator<<(QDataStream &s, const QIcon &icon); + friend class QIconThemeEngine; +}; + +QT_END_NAMESPACE +#endif //QT_NO_ICON +#endif // QICON_P_H diff --git a/src/widgets/kernel/qiconengine.cpp b/src/widgets/kernel/qiconengine.cpp new file mode 100644 index 0000000000..6168a83940 --- /dev/null +++ b/src/widgets/kernel/qiconengine.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiconengine.h" +#include "qpainter.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QIconEngine + + \brief The QIconEngine class provides an abstract base class for QIcon renderers. + + \ingroup painting + + \bold {Use QIconEngineV2 instead.} + + An icon engine provides the rendering functions for a QIcon. Each icon has a + corresponding icon engine that is responsible for drawing the icon with a + requested size, mode and state. + + The icon is rendered by the paint() function, and the icon can additionally be + obtained as a pixmap with the pixmap() function (the default implementation + simply uses paint() to achieve this). The addPixmap() function can be used to + add new pixmaps to the icon engine, and is used by QIcon to add specialized + custom pixmaps. + + The paint(), pixmap(), and addPixmap() functions are all virtual, and can + therefore be reimplemented in subclasses of QIconEngine. + + \sa QIconEngineV2, QIconEnginePlugin + +*/ + +/*! + \fn virtual void QIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0; + + Uses the given \a painter to paint the icon with the required \a mode and + \a state into the rectangle \a rect. +*/ + +/*! Returns the actual size of the icon the engine provides for the + requested \a size, \a mode and \a state. The default implementation + returns the given \a size. + */ +QSize QIconEngine::actualSize(const QSize &size, QIcon::Mode /*mode*/, QIcon::State /*state*/) +{ + return size; +} + + +/*! + Destroys the icon engine. + */ +QIconEngine::~QIconEngine() +{ +} + + +/*! + Returns the icon as a pixmap with the required \a size, \a mode, + and \a state. The default implementation creates a new pixmap and + calls paint() to fill it. +*/ +QPixmap QIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + QPixmap pm(size); + { + QPainter p(&pm); + paint(&p, QRect(QPoint(0,0),size), mode, state); + } + return pm; +} + +/*! + Called by QIcon::addPixmap(). Adds a specialized \a pixmap for the given + \a mode and \a state. The default pixmap-based engine stores any supplied + pixmaps, and it uses them instead of scaled pixmaps if the size of a pixmap + matches the size of icon requested. Custom icon engines that implement + scalable vector formats are free to ignores any extra pixmaps. + */ +void QIconEngine::addPixmap(const QPixmap &/*pixmap*/, QIcon::Mode /*mode*/, QIcon::State /*state*/) +{ +} + + +/*! Called by QIcon::addFile(). Adds a specialized pixmap from the + file with the given \a fileName, \a size, \a mode and \a state. The + default pixmap-based engine stores any supplied file names, and it + loads the pixmaps on demand instead of using scaled pixmaps if the + size of a pixmap matches the size of icon requested. Custom icon + engines that implement scalable vector formats are free to ignores + any extra files. + */ +void QIconEngine::addFile(const QString &/*fileName*/, const QSize &/*size*/, QIcon::Mode /*mode*/, QIcon::State /*state*/) +{ +} + + + +// version 2 functions + + +/*! + \class QIconEngineV2 + + \brief The QIconEngineV2 class provides an abstract base class for QIcon renderers. + + \ingroup painting + \since 4.3 + + An icon engine renders \l{QIcon}s. With icon engines, you can + customize icons. Qt provides a default engine that makes icons + adhere to the current style by scaling the icons and providing a + disabled appearance. + + An engine is installed on an icon either through a QIcon + constructor or through a QIconEnginePluginV2. The plugins are used + by Qt if a specific engine is not given when the icon is created. + See the QIconEngineV2 class description to learn how to create + icon engine plugins. + + An icon engine provides the rendering functions for a QIcon. Each + icon has a corresponding icon engine that is responsible for drawing + the icon with a requested size, mode and state. + + QIconEngineV2 extends the API of QIconEngine to allow streaming of + the icon engine contents, and should be used instead of QIconEngine + for implementing new icon engines. + + \sa QIconEnginePluginV2 + +*/ + +/*! + \enum QIconEngineV2::IconEngineHook + \since 4.5 + + These enum values are used for virtual_hook() to allow additional + queries to icon engine without breaking binary compatibility. + + \value AvailableSizesHook Allows to query the sizes of the + contained pixmaps for pixmap-based engines. The \a data argument + of the virtual_hook() function is a AvailableSizesArgument pointer + that should be filled with icon sizes. Engines that work in terms + of a scalable, vectorial format normally return an empty list. + + \value IconNameHook Allows to query the name used to create the + icon, for example when instantiating an icon using + QIcon::fromTheme(). + + \sa virtual_hook() + */ + +/*! + \class QIconEngineV2::AvailableSizesArgument + \since 4.5 + + This struct represents arguments to virtual_hook() function when + \a id parameter is QIconEngineV2::AvailableSizesHook. + + \sa virtual_hook(), QIconEngineV2::IconEngineHook + */ + +/*! + \variable QIconEngineV2::AvailableSizesArgument::mode + \brief the requested mode of an image. + + \sa QIcon::Mode +*/ + +/*! + \variable QIconEngineV2::AvailableSizesArgument::state + \brief the requested state of an image. + + \sa QIcon::State +*/ + +/*! + \variable QIconEngineV2::AvailableSizesArgument::sizes + + \brief image sizes that are available with specified \a mode and + \a state. This is an output parameter and is filled after call to + virtual_hook(). Engines that work in terms of a scalable, + vectorial format normally return an empty list. +*/ + + +/*! + Returns a key that identifies this icon engine. + */ +QString QIconEngineV2::key() const +{ + return QString(); +} + +/*! + Returns a clone of this icon engine. + */ +QIconEngineV2 *QIconEngineV2::clone() const +{ + return 0; +} + +/*! + Reads icon engine contents from the QDataStream \a in. Returns + true if the contents were read; otherwise returns false. + + QIconEngineV2's default implementation always return false. + */ +bool QIconEngineV2::read(QDataStream &) +{ + return false; +} + +/*! + Writes the contents of this engine to the QDataStream \a out. + Returns true if the contents were written; otherwise returns false. + + QIconEngineV2's default implementation always return false. + */ +bool QIconEngineV2::write(QDataStream &) const +{ + return false; +} + +/*! + \since 4.5 + + Additional method to allow extending QIconEngineV2 without + adding new virtual methods (and without breaking binary compatibility). + The actual action and format of \a data depends on \a id argument + which is in fact a constant from IconEngineHook enum. + + \sa IconEngineHook +*/ +void QIconEngineV2::virtual_hook(int id, void *data) +{ + switch (id) { + case QIconEngineV2::AvailableSizesHook: { + QIconEngineV2::AvailableSizesArgument &arg = + *reinterpret_cast(data); + arg.sizes.clear(); + break; + } + default: + break; + } +} + +/*! + \since 4.5 + + Returns sizes of all images that are contained in the engine for the + specific \a mode and \a state. + + \note This is a helper method and the actual work is done by + virtual_hook() method, hence this method depends on icon engine support + and may not work with all icon engines. + */ +QList QIconEngineV2::availableSizes(QIcon::Mode mode, QIcon::State state) +{ + AvailableSizesArgument arg; + arg.mode = mode; + arg.state = state; + virtual_hook(QIconEngineV2::AvailableSizesHook, reinterpret_cast(&arg)); + return arg.sizes; +} + +/*! + \since 4.7 + + Returns the name used to create the engine, if available. + + \note This is a helper method and the actual work is done by + virtual_hook() method, hence this method depends on icon engine support + and may not work with all icon engines. + */ +QString QIconEngineV2::iconName() +{ + QString name; + virtual_hook(QIconEngineV2::IconNameHook, reinterpret_cast(&name)); + return name; +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qiconengine.h b/src/widgets/kernel/qiconengine.h new file mode 100644 index 0000000000..12caea8a20 --- /dev/null +++ b/src/widgets/kernel/qiconengine.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICONENGINE_H +#define QICONENGINE_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class Q_GUI_EXPORT QIconEngine +{ +public: + virtual ~QIconEngine(); + virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0; + virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); + virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + + virtual void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state); + virtual void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state); + +#if 0 + virtual int frameCount(QIcon::Mode fromMode, QIcon::State fromState, QIcon::Mode toMode, QIcon::State toState); + virtual void paintFrame(QPainter *painter, const QRect &rect, int frameNumber, QIcon::Mode fromMode, QIcon::State fromState, QIcon::Mode toMode, QIcon::State toState); +#endif +}; + +// ### Qt 5: move the below into QIconEngine +class Q_GUI_EXPORT QIconEngineV2 : public QIconEngine +{ +public: + virtual QString key() const; + virtual QIconEngineV2 *clone() const; + virtual bool read(QDataStream &in); + virtual bool write(QDataStream &out) const; + virtual void virtual_hook(int id, void *data); + +public: + enum IconEngineHook { AvailableSizesHook = 1, IconNameHook }; + + struct AvailableSizesArgument + { + QIcon::Mode mode; + QIcon::State state; + QList sizes; + }; + + // ### Qt 5: make this function const and virtual. + QList availableSizes(QIcon::Mode mode = QIcon::Normal, + QIcon::State state = QIcon::Off); + + // ### Qt 5: make this function const and virtual. + QString iconName(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QICONENGINE_H diff --git a/src/widgets/kernel/qiconengineplugin.cpp b/src/widgets/kernel/qiconengineplugin.cpp new file mode 100644 index 0000000000..7c8c3a3c1a --- /dev/null +++ b/src/widgets/kernel/qiconengineplugin.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiconengineplugin.h" +#include "qiconengine.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QIconEnginePlugin + \brief The QIconEnginePlugin class provides an abstract base for custom QIconEngine plugins. + + \ingroup plugins + + \bold {Use QIconEnginePluginV2 instead.} + + The icon engine plugin is a simple plugin interface that makes it easy to + create custom icon engines that can be loaded dynamically into applications + through QIcon. QIcon uses the file or resource name's suffix to determine + what icon engine to use. + + Writing a icon engine plugin is achieved by subclassing this base class, + reimplementing the pure virtual functions keys() and create(), and + exporting the class with the Q_EXPORT_PLUGIN2() macro. + + \sa {How to Create Qt Plugins} +*/ + +/*! + \fn QStringList QIconEnginePlugin::keys() const + + Returns a list of icon engine keys that this plugin supports. The keys correspond + to the suffix of the file or resource name used when the plugin was created. + Keys are case insensitive. + + \sa create() +*/ + +/*! + \fn QIconEngine* QIconEnginePlugin::create(const QString& filename) + + Creates and returns a QIconEngine object for the icon with the given + \a filename. + + \sa keys() +*/ + +/*! + Constructs a icon engine plugin with the given \a parent. This is invoked + automatically by the Q_EXPORT_PLUGIN2() macro. +*/ +QIconEnginePlugin::QIconEnginePlugin(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the icon engine plugin. + + You never have to call this explicitly. Qt destroys a plugin + automatically when it is no longer used. +*/ +QIconEnginePlugin::~QIconEnginePlugin() +{ +} + +// version 2 + +/*! + \class QIconEnginePluginV2 + \brief The QIconEnginePluginV2 class provides an abstract base for custom QIconEngineV2 plugins. + + \ingroup plugins + \since 4.3 + + Icon engine plugins produces \l{QIconEngine}s for \l{QIcon}s; an + icon engine is used to render the icon. The keys that identifies + the engines the plugin can create are suffixes of + icon filenames; they are returned by keys(). The create() function + receives the icon filename to return an engine for; it should + return 0 if it cannot produce an engine for the file. + + Writing an icon engine plugin is achieved by inheriting + QIconEnginePluginV2, reimplementing keys() and create(), and + adding the Q_EXPORT_PLUGIN2() macro. + + You should ensure that you do not duplicate keys. Qt will query + the plugins for icon engines in the order in which the plugins are + found during plugin search (see the plugins \l{How to Create Qt + Plugins}{overview document}). + + \sa {How to Create Qt Plugins} +*/ + +/*! + \fn QStringList QIconEnginePluginV2::keys() const + + Returns a list of icon engine keys that this plugin supports. The keys correspond + to the suffix of the file or resource name used when the plugin was created. + Keys are case insensitive. + + \sa create() +*/ + +/*! + \fn QIconEngineV2* QIconEnginePluginV2::create(const QString& filename = QString()) + + Creates and returns a QIconEngine object for the icon with the given + \a filename. + + \sa keys() +*/ + +/*! + Constructs a icon engine plugin with the given \a parent. This is invoked + automatically by the Q_EXPORT_PLUGIN2() macro. +*/ +QIconEnginePluginV2::QIconEnginePluginV2(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the icon engine plugin. + + You never have to call this explicitly. Qt destroys a plugin + automatically when it is no longer used. +*/ +QIconEnginePluginV2::~QIconEnginePluginV2() +{ +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qiconengineplugin.h b/src/widgets/kernel/qiconengineplugin.h new file mode 100644 index 0000000000..e892a38f7b --- /dev/null +++ b/src/widgets/kernel/qiconengineplugin.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICONENGINEPLUGIN_H +#define QICONENGINEPLUGIN_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QIconEngine; +class QIconEngineV2; + +struct Q_GUI_EXPORT QIconEngineFactoryInterface : public QFactoryInterface +{ + virtual QIconEngine *create(const QString &filename) = 0; +}; + +#define QIconEngineFactoryInterface_iid \ + "com.trolltech.Qt.QIconEngineFactoryInterface" +Q_DECLARE_INTERFACE(QIconEngineFactoryInterface, QIconEngineFactoryInterface_iid) + +class Q_GUI_EXPORT QIconEnginePlugin : public QObject, public QIconEngineFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QIconEngineFactoryInterface:QFactoryInterface) +public: + QIconEnginePlugin(QObject *parent = 0); + ~QIconEnginePlugin(); + + virtual QStringList keys() const = 0; + virtual QIconEngine *create(const QString &filename) = 0; +}; + +// ### Qt 5: remove version 2 +struct Q_GUI_EXPORT QIconEngineFactoryInterfaceV2 : public QFactoryInterface +{ + virtual QIconEngineV2 *create(const QString &filename = QString()) = 0; +}; + +#define QIconEngineFactoryInterfaceV2_iid \ + "com.trolltech.Qt.QIconEngineFactoryInterfaceV2" +Q_DECLARE_INTERFACE(QIconEngineFactoryInterfaceV2, QIconEngineFactoryInterfaceV2_iid) + +class Q_GUI_EXPORT QIconEnginePluginV2 : public QObject, public QIconEngineFactoryInterfaceV2 +{ + Q_OBJECT + Q_INTERFACES(QIconEngineFactoryInterfaceV2:QFactoryInterface) +public: + QIconEnginePluginV2(QObject *parent = 0); + ~QIconEnginePluginV2(); + + virtual QStringList keys() const = 0; + virtual QIconEngineV2 *create(const QString &filename = QString()) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QICONENGINEPLUGIN_H diff --git a/src/widgets/kernel/qiconloader.cpp b/src/widgets/kernel/qiconloader.cpp new file mode 100644 index 0000000000..19be636e9c --- /dev/null +++ b/src/widgets/kernel/qiconloader.cpp @@ -0,0 +1,573 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QT_NO_ICON +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAC +#include +#endif + +#ifdef Q_WS_X11 +#include +#endif + +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance) + +/* Theme to use in last resort, if the theme does not have the icon, neither the parents */ +static QString fallbackTheme() +{ +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_GNOME) { + return QLatin1String("gnome"); + } else if (X11->desktopEnvironment == DE_KDE) { + return X11->desktopVersion >= 4 + ? QString::fromLatin1("oxygen") + : QString::fromLatin1("crystalsvg"); + } else { + return QLatin1String("hicolor"); + } +#endif + return QString(); +} + +QIconLoader::QIconLoader() : + m_themeKey(1), m_supportsSvg(false), m_initialized(false) +{ +} + +// We lazily initialize the loader to make static icons +// work. Though we do not officially support this. +void QIconLoader::ensureInitialized() +{ + if (!m_initialized) { + m_initialized = true; + + Q_ASSERT(qApp); + + m_systemTheme = qt_guiPlatformPlugin()->systemIconThemeName(); + if (m_systemTheme.isEmpty()) + m_systemTheme = fallbackTheme(); +#ifndef QT_NO_LIBRARY + QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterfaceV2_iid, + QLatin1String("/iconengines"), + Qt::CaseInsensitive); + if (iconFactoryLoader.keys().contains(QLatin1String("svg"))) + m_supportsSvg = true; +#endif //QT_NO_LIBRARY + } +} + +QIconLoader *QIconLoader::instance() +{ + return iconLoaderInstance(); +} + +// Queries the system theme and invalidates existing +// icons if the theme has changed. +void QIconLoader::updateSystemTheme() +{ + // Only change if this is not explicitly set by the user + if (m_userTheme.isEmpty()) { + QString theme = qt_guiPlatformPlugin()->systemIconThemeName(); + if (theme.isEmpty()) + theme = fallbackTheme(); + if (theme != m_systemTheme) { + m_systemTheme = theme; + invalidateKey(); + } + } +} + +void QIconLoader::setThemeName(const QString &themeName) +{ + m_userTheme = themeName; + invalidateKey(); +} + +void QIconLoader::setThemeSearchPath(const QStringList &searchPaths) +{ + m_iconDirs = searchPaths; + themeList.clear(); + invalidateKey(); +} + +QStringList QIconLoader::themeSearchPaths() const +{ + if (m_iconDirs.isEmpty()) { + m_iconDirs = qt_guiPlatformPlugin()->iconThemeSearchPaths(); + // Always add resource directory as search path + m_iconDirs.append(QLatin1String(":/icons")); + } + return m_iconDirs; +} + +QIconTheme::QIconTheme(const QString &themeName) + : m_valid(false) +{ + QFile themeIndex; + + QList keyList; + QStringList iconDirs = QIcon::themeSearchPaths(); + for ( int i = 0 ; i < iconDirs.size() ; ++i) { + QDir iconDir(iconDirs[i]); + QString themeDir = iconDir.path() + QLatin1Char('/') + themeName; + themeIndex.setFileName(themeDir + QLatin1String("/index.theme")); + if (themeIndex.exists()) { + m_contentDir = themeDir; + m_valid = true; + break; + } + } +#ifndef QT_NO_SETTINGS + if (themeIndex.exists()) { + const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat); + QStringListIterator keyIterator(indexReader.allKeys()); + while (keyIterator.hasNext()) { + + const QString key = keyIterator.next(); + if (key.endsWith(QLatin1String("/Size"))) { + // Note the QSettings ini-format does not accept + // slashes in key names, hence we have to cheat + if (int size = indexReader.value(key).toInt()) { + QString directoryKey = key.left(key.size() - 5); + QIconDirInfo dirInfo(directoryKey); + dirInfo.size = size; + QString type = indexReader.value(directoryKey + + QLatin1String("/Type") + ).toString(); + + if (type == QLatin1String("Fixed")) + dirInfo.type = QIconDirInfo::Fixed; + else if (type == QLatin1String("Scalable")) + dirInfo.type = QIconDirInfo::Scalable; + else + dirInfo.type = QIconDirInfo::Threshold; + + dirInfo.threshold = indexReader.value(directoryKey + + QLatin1String("/Threshold"), + 2).toInt(); + + dirInfo.minSize = indexReader.value(directoryKey + + QLatin1String("/MinSize"), + size).toInt(); + + dirInfo.maxSize = indexReader.value(directoryKey + + QLatin1String("/MaxSize"), + size).toInt(); + m_keyList.append(dirInfo); + } + } + } + + // Parent themes provide fallbacks for missing icons + m_parents = indexReader.value( + QLatin1String("Icon Theme/Inherits")).toStringList(); + + // Ensure a default platform fallback for all themes + if (m_parents.isEmpty()) + m_parents.append(fallbackTheme()); + + // Ensure that all themes fall back to hicolor + if (!m_parents.contains(QLatin1String("hicolor"))) + m_parents.append(QLatin1String("hicolor")); + } +#endif //QT_NO_SETTINGS +} + +QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const +{ + QThemeIconEntries entries; + Q_ASSERT(!themeName.isEmpty()); + + QPixmap pixmap; + + // Used to protect against potential recursions + visited << themeName; + + QIconTheme theme = themeList.value(themeName); + if (!theme.isValid()) { + theme = QIconTheme(themeName); + if (!theme.isValid()) + theme = QIconTheme(fallbackTheme()); + + themeList.insert(themeName, theme); + } + + QString contentDir = theme.contentDir() + QLatin1Char('/'); + QList subDirs = theme.keyList(); + + const QString svgext(QLatin1String(".svg")); + const QString pngext(QLatin1String(".png")); + + // Add all relevant files + for (int i = 0; i < subDirs.size() ; ++i) { + const QIconDirInfo &dirInfo = subDirs.at(i); + QString subdir = dirInfo.path; + QDir currentDir(contentDir + subdir); + if (currentDir.exists(iconName + pngext)) { + PixmapEntry *iconEntry = new PixmapEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(iconName + pngext); + // Notice we ensure that pixmap entries always come before + // scalable to preserve search order afterwards + entries.prepend(iconEntry); + } else if (m_supportsSvg && + currentDir.exists(iconName + svgext)) { + ScalableEntry *iconEntry = new ScalableEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(iconName + svgext); + entries.append(iconEntry); + } + } + + if (entries.isEmpty()) { + const QStringList parents = theme.parents(); + // Search recursively through inherited themes + for (int i = 0 ; i < parents.size() ; ++i) { + + const QString parentTheme = parents.at(i).trimmed(); + + if (!visited.contains(parentTheme)) // guard against recursion + entries = findIconHelper(parentTheme, iconName, visited); + + if (!entries.isEmpty()) // success + break; + } + } + return entries; +} + +QThemeIconEntries QIconLoader::loadIcon(const QString &name) const +{ + if (!themeName().isEmpty()) { + QStringList visited; + return findIconHelper(themeName(), name, visited); + } + + return QThemeIconEntries(); +} + + +// -------- Icon Loader Engine -------- // + + +QIconLoaderEngine::QIconLoaderEngine(const QString& iconName) + : m_iconName(iconName), m_key(0) +{ +} + +QIconLoaderEngine::~QIconLoaderEngine() +{ + while (!m_entries.isEmpty()) + delete m_entries.takeLast(); + Q_ASSERT(m_entries.size() == 0); +} + +QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other) + : QIconEngineV2(other), + m_iconName(other.m_iconName), + m_key(0) +{ +} + +QIconEngineV2 *QIconLoaderEngine::clone() const +{ + return new QIconLoaderEngine(*this); +} + +bool QIconLoaderEngine::read(QDataStream &in) { + in >> m_iconName; + return true; +} + +bool QIconLoaderEngine::write(QDataStream &out) const +{ + out << m_iconName; + return true; +} + +bool QIconLoaderEngine::hasIcon() const +{ + return !(m_entries.isEmpty()); +} + +// Lazily load the icon +void QIconLoaderEngine::ensureLoaded() +{ + + iconLoaderInstance()->ensureInitialized(); + + if (!(iconLoaderInstance()->themeKey() == m_key)) { + + while (!m_entries.isEmpty()) + delete m_entries.takeLast(); + + Q_ASSERT(m_entries.size() == 0); + m_entries = iconLoaderInstance()->loadIcon(m_iconName); + m_key = iconLoaderInstance()->themeKey(); + } +} + +void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect, + QIcon::Mode mode, QIcon::State state) +{ + QSize pixmapSize = rect.size(); +#if defined(Q_WS_MAC) + pixmapSize *= qt_mac_get_scalefactor(); +#endif + painter->drawPixmap(rect, pixmap(pixmapSize, mode, state)); +} + +/* + * This algorithm is defined by the freedesktop spec: + * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + */ +static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize) +{ + if (dir.type == QIconDirInfo::Fixed) { + return dir.size == iconsize; + + } else if (dir.type == QIconDirInfo::Scalable) { + return dir.size <= dir.maxSize && + iconsize >= dir.minSize; + + } else if (dir.type == QIconDirInfo::Threshold) { + return iconsize >= dir.size - dir.threshold && + iconsize <= dir.size + dir.threshold; + } + + Q_ASSERT(1); // Not a valid value + return false; +} + +/* + * This algorithm is defined by the freedesktop spec: + * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + */ +static int directorySizeDistance(const QIconDirInfo &dir, int iconsize) +{ + if (dir.type == QIconDirInfo::Fixed) { + return qAbs(dir.size - iconsize); + + } else if (dir.type == QIconDirInfo::Scalable) { + if (iconsize < dir.minSize) + return dir.minSize - iconsize; + else if (iconsize > dir.maxSize) + return iconsize - dir.maxSize; + else + return 0; + + } else if (dir.type == QIconDirInfo::Threshold) { + if (iconsize < dir.size - dir.threshold) + return dir.minSize - iconsize; + else if (iconsize > dir.size + dir.threshold) + return iconsize - dir.maxSize; + else return 0; + } + + Q_ASSERT(1); // Not a valid value + return INT_MAX; +} + +QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size) +{ + int iconsize = qMin(size.width(), size.height()); + + // Note that m_entries are sorted so that png-files + // come first + + // Search for exact matches first + for (int i = 0; i < m_entries.count(); ++i) { + QIconLoaderEngineEntry *entry = m_entries.at(i); + if (directoryMatchesSize(entry->dir, iconsize)) { + return entry; + } + } + + // Find the minimum distance icon + int minimalSize = INT_MAX; + QIconLoaderEngineEntry *closestMatch = 0; + for (int i = 0; i < m_entries.count(); ++i) { + QIconLoaderEngineEntry *entry = m_entries.at(i); + int distance = directorySizeDistance(entry->dir, iconsize); + if (distance < minimalSize) { + minimalSize = distance; + closestMatch = entry; + } + } + return closestMatch; +} + +/* + * Returns the actual icon size. For scalable svg's this is equivalent + * to the requested size. Otherwise the closest match is returned but + * we can never return a bigger size than the requested size. + * + */ +QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode, + QIcon::State state) +{ + ensureLoaded(); + + QIconLoaderEngineEntry *entry = entryForSize(size); + if (entry) { + const QIconDirInfo &dir = entry->dir; + if (dir.type == QIconDirInfo::Scalable) + return size; + else { + int result = qMin(dir.size, qMin(size.width(), size.height())); + return QSize(result, result); + } + } + return QIconEngineV2::actualSize(size, mode, state); +} + +QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + Q_UNUSED(state); + + // Ensure that basePixmap is lazily initialized before generating the + // key, otherwise the cache key is not unique + if (basePixmap.isNull()) + basePixmap.load(filename); + +#if 0 // ### Qt5 + int actualSize = qMin(size.width(), size.height()); + QString key = QLatin1Literal("$qt_theme_") + % HexString(basePixmap.cacheKey()) + % HexString(mode) + % HexString(qApp->palette().cacheKey()) + % HexString(actualSize); + + QPixmap cachedPixmap; + if (QPixmapCache::find(key, &cachedPixmap)) { + return cachedPixmap; + } else { + QStyleOption opt(0); + opt.palette = qApp->palette(); + cachedPixmap = qApp->style()->generatedIconPixmap(mode, basePixmap, &opt); + QPixmapCache::insert(key, cachedPixmap); + } + return cachedPixmap; +#else + return basePixmap; +#endif +} + +QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + if (svgIcon.isNull()) + svgIcon = QIcon(filename); + + // Simply reuse svg icon engine + return svgIcon.pixmap(size, mode, state); +} + +QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode, + QIcon::State state) +{ + ensureLoaded(); + + QIconLoaderEngineEntry *entry = entryForSize(size); + if (entry) + return entry->pixmap(size, mode, state); + + return QPixmap(); +} + +QString QIconLoaderEngine::key() const +{ + return QLatin1String("QIconLoaderEngine"); +} + +void QIconLoaderEngine::virtual_hook(int id, void *data) +{ + ensureLoaded(); + + switch (id) { + case QIconEngineV2::AvailableSizesHook: + { + QIconEngineV2::AvailableSizesArgument &arg + = *reinterpret_cast(data); + const QList directoryKey = iconLoaderInstance()->theme().keyList(); + arg.sizes.clear(); + + // Gets all sizes from the DirectoryInfo entries + for (int i = 0 ; i < m_entries.size() ; ++i) { + int size = m_entries.at(i)->dir.size; + arg.sizes.append(QSize(size, size)); + } + } + break; + case QIconEngineV2::IconNameHook: + { + QString &name = *reinterpret_cast(data); + name = m_iconName; + } + break; + default: + QIconEngineV2::virtual_hook(id, data); + } +} + +QT_END_NAMESPACE + +#endif //QT_NO_ICON diff --git a/src/widgets/kernel/qiconloader_p.h b/src/widgets/kernel/qiconloader_p.h new file mode 100644 index 0000000000..00a3976b40 --- /dev/null +++ b/src/widgets/kernel/qiconloader_p.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESKTOPICON_P_H +#define QDESKTOPICON_P_H + +#ifndef QT_NO_ICON +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QIconLoader; + +struct QIconDirInfo +{ + enum Type { Fixed, Scalable, Threshold }; + QIconDirInfo(const QString &_path = QString()) : + path(_path), + size(0), + maxSize(0), + minSize(0), + threshold(0), + type(Threshold) {} + QString path; + short size; + short maxSize; + short minSize; + short threshold; + Type type : 4; +}; + +class QIconLoaderEngineEntry + { +public: + virtual ~QIconLoaderEngineEntry() {} + virtual QPixmap pixmap(const QSize &size, + QIcon::Mode mode, + QIcon::State state) = 0; + QString filename; + QIconDirInfo dir; + static int count; +}; + +struct ScalableEntry : public QIconLoaderEngineEntry +{ + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QIcon svgIcon; +}; + +struct PixmapEntry : public QIconLoaderEngineEntry +{ + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QPixmap basePixmap; +}; + +typedef QList QThemeIconEntries; + +class QIconLoaderEngine : public QIconEngineV2 +{ +public: + QIconLoaderEngine(const QString& iconName = QString()); + ~QIconLoaderEngine(); + + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); + QIconEngineV2 *clone() const; + bool read(QDataStream &in); + bool write(QDataStream &out) const; + +private: + QString key() const; + bool hasIcon() const; + void ensureLoaded(); + void virtual_hook(int id, void *data); + QIconLoaderEngineEntry *entryForSize(const QSize &size); + QIconLoaderEngine(const QIconLoaderEngine &other); + QThemeIconEntries m_entries; + QString m_iconName; + uint m_key; + + friend class QIconLoader; +}; + +class QIconTheme +{ +public: + QIconTheme(const QString &name); + QIconTheme() : m_valid(false) {} + QStringList parents() { return m_parents; } + QList keyList() { return m_keyList; } + QString contentDir() { return m_contentDir; } + bool isValid() { return m_valid; } + +private: + QString m_contentDir; + QList m_keyList; + QStringList m_parents; + bool m_valid; +}; + +class QIconLoader : public QObject +{ +public: + QIconLoader(); + QThemeIconEntries loadIcon(const QString &iconName) const; + uint themeKey() const { return m_themeKey; } + + QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; } + void setThemeName(const QString &themeName); + QIconTheme theme() { return themeList.value(themeName()); } + void setThemeSearchPath(const QStringList &searchPaths); + QStringList themeSearchPaths() const; + QIconDirInfo dirInfo(int dirindex); + static QIconLoader *instance(); + void updateSystemTheme(); + void invalidateKey() { m_themeKey++; } + void ensureInitialized(); + +private: + QThemeIconEntries findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const; + uint m_themeKey; + bool m_supportsSvg; + bool m_initialized; + + mutable QString m_userTheme; + mutable QString m_systemTheme; + mutable QStringList m_iconDirs; + mutable QHash themeList; +}; + +QT_END_NAMESPACE + +#endif // QDESKTOPICON_P_H + +#endif //QT_NO_ICON diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp new file mode 100644 index 0000000000..e014ec855f --- /dev/null +++ b/src/widgets/kernel/qlayout.cpp @@ -0,0 +1,1632 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayout.h" + +#include "qapplication.h" +#include "qlayoutengine_p.h" +#include "qmenubar.h" +#include "qtoolbar.h" +#include "qsizegrip.h" +#include "qevent.h" +#include "qstyle.h" +#include "qvariant.h" +#include "qwidget_p.h" +#include "qlayout_p.h" +#include "qformlayout.h" + +QT_BEGIN_NAMESPACE + +static int menuBarHeightForWidth(QWidget *menubar, int w) +{ + if (menubar && !menubar->isHidden() && !menubar->isWindow()) { + int result = menubar->heightForWidth(qMax(w, menubar->minimumWidth())); + if (result != -1) + return result; + result = menubar->sizeHint() + .expandedTo(menubar->minimumSize()) + .expandedTo(menubar->minimumSizeHint()) + .boundedTo(menubar->maximumSize()).height(); + if (result != -1) + return result; + } + return 0; +} + +/*! + \class QLayout + \brief The QLayout class is the base class of geometry managers. + + \ingroup geomanagement + + This is an abstract base class inherited by the concrete classes + QBoxLayout, QGridLayout, QFormLayout, and QStackedLayout. + + For users of QLayout subclasses or of QMainWindow there is seldom + any need to use the basic functions provided by QLayout, such as + setSizeConstraint() or setMenuBar(). See \l{Layout Management} + for more information. + + To make your own layout manager, implement the functions + addItem(), sizeHint(), setGeometry(), itemAt() and takeAt(). You + should also implement minimumSize() to ensure your layout isn't + resized to zero size if there is too little space. To support + children whose heights depend on their widths, implement + hasHeightForWidth() and heightForWidth(). See the + \l{layouts/borderlayout}{Border Layout} and + \l{layouts/flowlayout}{Flow Layout} examples for + more information about implementing custom layout managers. + + Geometry management stops when the layout manager is deleted. + + \sa QLayoutItem, {Layout Management}, {Basic Layouts Example}, + {Border Layout Example}, {Flow Layout Example} +*/ + + +/*! + Constructs a new top-level QLayout, with parent \a parent. + \a parent may not be 0. + + There can be only one top-level layout for a widget. It is + returned by QWidget::layout(). +*/ +QLayout::QLayout(QWidget *parent) + : QObject(*new QLayoutPrivate, parent) +{ + if (!parent) + return; + parent->setLayout(this); +} + +/*! + Constructs a new child QLayout. + + This layout has to be inserted into another layout before geometry + management will work. +*/ +QLayout::QLayout() + : QObject(*new QLayoutPrivate, 0) +{ +} + + +/*! \internal + */ +QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w) + : QObject(dd, lay ? static_cast(lay) : static_cast(w)) +{ + Q_D(QLayout); + if (lay) { + lay->addItem(this); + } else if (w) { + if (w->layout()) { + qWarning("QLayout: Attempting to add QLayout \"%s\" to %s \"%s\", which" + " already has a layout", + qPrintable(QObject::objectName()), w->metaObject()->className(), + w->objectName().toLocal8Bit().data()); + setParent(0); + } else { + d->topLevel = true; + w->d_func()->layout = this; + QT_TRY { + invalidate(); + } QT_CATCH(...) { + w->d_func()->layout = 0; + QT_RETHROW; + } + } + } +} + +QLayoutPrivate::QLayoutPrivate() + : QObjectPrivate(), insideSpacing(-1), userLeftMargin(-1), userTopMargin(-1), userRightMargin(-1), + userBottomMargin(-1), topLevel(false), enabled(true), activated(true), autoNewChild(false), + constraint(QLayout::SetDefaultConstraint), menubar(0) +{ +} + +void QLayoutPrivate::getMargin(int *result, int userMargin, QStyle::PixelMetric pm) const +{ + if (!result) + return; + + Q_Q(const QLayout); + if (userMargin >= 0) { + *result = userMargin; + } else if (!topLevel) { + *result = 0; + } else if (QWidget *pw = q->parentWidget()) { + *result = pw->style()->pixelMetric(pm, 0, pw); + } else { + *result = 0; + } +} + +// Static item factory functions that allow for hooking things in Designer + +QLayoutPrivate::QWidgetItemFactoryMethod QLayoutPrivate::widgetItemFactoryMethod = 0; +QLayoutPrivate::QSpacerItemFactoryMethod QLayoutPrivate::spacerItemFactoryMethod = 0; + +QWidgetItem *QLayoutPrivate::createWidgetItem(const QLayout *layout, QWidget *widget) +{ + if (widgetItemFactoryMethod) + if (QWidgetItem *wi = (*widgetItemFactoryMethod)(layout, widget)) + return wi; + return new QWidgetItemV2(widget); +} + +QSpacerItem *QLayoutPrivate::createSpacerItem(const QLayout *layout, int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy) +{ + if (spacerItemFactoryMethod) + if (QSpacerItem *si = (*spacerItemFactoryMethod)(layout, w, h, hPolicy, vPolicy)) + return si; + return new QSpacerItem(w, h, hPolicy, vPolicy); +} + +#ifdef QT3_SUPPORT +/*! + Constructs a new top-level QLayout called \a name, with parent + widget \a parent. \a parent may not be 0. + + The \a margin is the number of pixels between the edge of the + widget and the managed children. The \a spacing sets the value of + spacing(), which gives the spacing between the managed widgets. If + \a spacing is -1 (the default), spacing is set to the value of \a + margin. + + There can be only one top-level layout for a widget. It is + returned by QWidget::layout() + + \sa QWidget::setLayout() +*/ +QLayout::QLayout(QWidget *parent, int margin, int spacing, const char *name) + : QObject(*new QLayoutPrivate,parent) +{ + Q_D(QLayout); + setObjectName(QString::fromAscii(name)); + setMargin(margin); + if (spacing < 0) + d->insideSpacing = margin; + else + d->insideSpacing = spacing; + if (parent) { + if (parent->layout()) { + qWarning("QLayout \"%s\" added to %s \"%s\", which already has a layout", + QObject::objectName().toLocal8Bit().data(), parent->metaObject()->className(), + parent->objectName().toLocal8Bit().data()); + parent->layout()->setParent(0); + } else { + d->topLevel = true; + parent->d_func()->layout = this; + QT_TRY { + invalidate(); + } QT_CATCH(...) { + parent->d_func()->layout = 0; + QT_RETHROW; + } + } + } +} + +/*! + Constructs a new child QLayout called \a name, and places it + inside \a parentLayout by using the default placement defined by + addItem(). + + If \a spacing is -1, this QLayout inherits \a parentLayout's + spacing(), otherwise the value of \a spacing is used. +*/ +QLayout::QLayout(QLayout *parentLayout, int spacing, const char *name) + : QObject(*new QLayoutPrivate,parentLayout) + +{ + Q_D(QLayout); + setObjectName(QString::fromAscii(name)); + d->insideSpacing = spacing; + parentLayout->addItem(this); +} + +/*! + Constructs a new child QLayout called \a name. If \a spacing is + -1, this QLayout inherits its parent's spacing(); otherwise the + value of \a spacing is used. + + This layout has to be inserted into another layout before geometry + management will work. +*/ +QLayout::QLayout(int spacing, const char *name) + : QObject(*new QLayoutPrivate, 0) +{ + Q_D(QLayout); + setObjectName(QString::fromAscii(name)); + d->insideSpacing = spacing; +} + +/*! + Automatically adding widgets is deprecated. Use addWidget() or + addLayout() instead. +*/ +void QLayout::setAutoAdd(bool a) { Q_D(QLayout); d->autoNewChild = a; } + +/*! + Automatically adding widgets is deprecated. Use addWidget() or + addLayout() instead. +*/ +bool QLayout::autoAdd() const { Q_D(const QLayout); return d->autoNewChild; } +#endif + + +/*! + \fn void QLayout::addItem(QLayoutItem *item) + + Implemented in subclasses to add an \a item. How it is added is + specific to each subclass. + + This function is not usually called in application code. To add a widget + to a layout, use the addWidget() function; to add a child layout, use the + addLayout() function provided by the relevant QLayout subclass. + + \bold{Note:} The ownership of \a item is transferred to the layout, and it's + the layout's responsibility to delete it. + + \sa addWidget(), QBoxLayout::addLayout(), QGridLayout::addLayout() +*/ + +/*! + Adds widget \a w to this layout in a manner specific to the + layout. This function uses addItem(). +*/ +void QLayout::addWidget(QWidget *w) +{ + addChildWidget(w); + addItem(QLayoutPrivate::createWidgetItem(this, w)); +} + + + +/*! + Sets the alignment for widget \a w to \a alignment and returns + true if \a w is found in this layout (not including child + layouts); otherwise returns false. +*/ +bool QLayout::setAlignment(QWidget *w, Qt::Alignment alignment) +{ + int i = 0; + QLayoutItem *item = itemAt(i); + while (item) { + if (item->widget() == w) { + item->setAlignment(alignment); + invalidate(); + return true; + } + ++i; + item = itemAt(i); + } + return false; +} + +/*! + \overload + + Sets the alignment for the layout \a l to \a alignment and + returns true if \a l is found in this layout (not including child + layouts); otherwise returns false. +*/ +bool QLayout::setAlignment(QLayout *l, Qt::Alignment alignment) +{ + int i = 0; + QLayoutItem *item = itemAt(i); + while (item) { + if (item->layout() == l) { + item->setAlignment(alignment); + invalidate(); + return true; + } + ++i; + item = itemAt(i); + } + return false; +} + +/*! + \fn void QLayout::setAlignment(Qt::Alignment alignment) + + Sets the alignment of this item to \a alignment. + + \sa QLayoutItem::setAlignment() +*/ + +/*! + \fn bool QLayout::isTopLevel() const + + Returns true if this layout is a top-level layout, i.e. not a + child of another layout; otherwise returns false. +*/ + +/*! + \property QLayout::margin + \brief the width of the outside border of the layout + \obsolete + + Use setContentsMargins() and getContentsMargins() instead. + + \sa contentsRect(), spacing +*/ + +/*! + \obsolete +*/ +int QLayout::margin() const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + if (left == top && top == right && right == bottom) { + return left; + } else { + return -1; + } +} + +/*! + \property QLayout::spacing + \brief the spacing between widgets inside the layout + + If no value is explicitly set, the layout's spacing is inherited + from the parent layout, or from the style settings for the parent + widget. + + For QGridLayout and QFormLayout, it is possible to set different horizontal and + vertical spacings using \l{QGridLayout::}{setHorizontalSpacing()} + and \l{QGridLayout::}{setVerticalSpacing()}. In that case, + spacing() returns -1. + + \sa contentsRect(), getContentsMargins(), QStyle::layoutSpacing(), + QStyle::pixelMetric() +*/ + +int QLayout::spacing() const +{ + if (const QBoxLayout* boxlayout = qobject_cast(this)) { + return boxlayout->spacing(); + } else if (const QGridLayout* gridlayout = qobject_cast(this)) { + return gridlayout->spacing(); + } else if (const QFormLayout* formlayout = qobject_cast(this)) { + return formlayout->spacing(); + } else { + Q_D(const QLayout); + if (d->insideSpacing >=0) { + return d->insideSpacing; + } else { + // arbitrarily prefer horizontal spacing to vertical spacing + return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing); + } + } +} + +/*! + \obsolete +*/ +void QLayout::setMargin(int margin) +{ + setContentsMargins(margin, margin, margin, margin); +} + +void QLayout::setSpacing(int spacing) +{ + if (QBoxLayout* boxlayout = qobject_cast(this)) { + boxlayout->setSpacing(spacing); + } else if (QGridLayout* gridlayout = qobject_cast(this)) { + gridlayout->setSpacing(spacing); + } else if (QFormLayout* formlayout = qobject_cast(this)) { + formlayout->setSpacing(spacing); + } else { + Q_D(QLayout); + d->insideSpacing = spacing; + invalidate(); + } +} + +/*! + \since 4.3 + + Sets the \a left, \a top, \a right, and \a bottom margins to use + around the layout. + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa getContentsMargins(), QStyle::pixelMetric(), + {QStyle::}{PM_LayoutLeftMargin}, + {QStyle::}{PM_LayoutTopMargin}, + {QStyle::}{PM_LayoutRightMargin}, + {QStyle::}{PM_LayoutBottomMargin} +*/ +void QLayout::setContentsMargins(int left, int top, int right, int bottom) +{ + Q_D(QLayout); + + if (d->userLeftMargin == left && d->userTopMargin == top && + d->userRightMargin == right && d->userBottomMargin == bottom) + return; + + d->userLeftMargin = left; + d->userTopMargin = top; + d->userRightMargin = right; + d->userBottomMargin = bottom; + invalidate(); +} + +/*! + \since 4.6 + + Sets the \a margins to use around the layout. + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa contentsMargins() +*/ +void QLayout::setContentsMargins(const QMargins &margins) +{ + setContentsMargins(margins.left(), margins.top(), margins.right(), margins.bottom()); +} + +/*! + \since 4.3 + + Extracts the left, top, right, and bottom margins used around the + layout, and assigns them to *\a left, *\a top, *\a right, and *\a + bottom (unless they are null pointers). + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa setContentsMargins(), QStyle::pixelMetric(), + {QStyle::}{PM_LayoutLeftMargin}, + {QStyle::}{PM_LayoutTopMargin}, + {QStyle::}{PM_LayoutRightMargin}, + {QStyle::}{PM_LayoutBottomMargin} +*/ +void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) const +{ + Q_D(const QLayout); + d->getMargin(left, d->userLeftMargin, QStyle::PM_LayoutLeftMargin); + d->getMargin(top, d->userTopMargin, QStyle::PM_LayoutTopMargin); + d->getMargin(right, d->userRightMargin, QStyle::PM_LayoutRightMargin); + d->getMargin(bottom, d->userBottomMargin, QStyle::PM_LayoutBottomMargin); +} + +/*! + \since 4.6 + + Returns the margins used around the layout. + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa setContentsMargins() +*/ +QMargins QLayout::contentsMargins() const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + return QMargins(left, top, right, bottom); +} + +/*! + \since 4.3 + + Returns the layout's geometry() rectangle, but taking into account the + contents margins. + + \sa setContentsMargins(), getContentsMargins() +*/ +QRect QLayout::contentsRect() const +{ + Q_D(const QLayout); + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + return d->rect.adjusted(+left, +top, -right, -bottom); +} + +#ifdef QT3_SUPPORT +bool QLayout::isTopLevel() const +{ + Q_D(const QLayout); + return d->topLevel; +} +#endif + +/*! + Returns the parent widget of this layout, or 0 if this layout is + not installed on any widget. + + If the layout is a sub-layout, this function returns the parent + widget of the parent layout. + + \sa parent() +*/ +QWidget *QLayout::parentWidget() const +{ + Q_D(const QLayout); + if (!d->topLevel) { + if (parent()) { + QLayout *parentLayout = qobject_cast(parent()); + if (!parentLayout) { + qWarning("QLayout::parentWidget: A layout can only have another layout as a parent."); + return 0; + } + return parentLayout->parentWidget(); + } else { + return 0; + } + } else { + Q_ASSERT(parent() && parent()->isWidgetType()); + return static_cast(parent()); + } +} + +/*! + \reimp +*/ +bool QLayout::isEmpty() const +{ + int i = 0; + QLayoutItem *item = itemAt(i); + while (item) { + if (!item->isEmpty()) + return false; + ++i; + item = itemAt(i); + } + return true; +} + +/*! + \reimp +*/ +void QLayout::setGeometry(const QRect &r) +{ + Q_D(QLayout); + d->rect = r; +} + +/*! + \reimp +*/ +QRect QLayout::geometry() const +{ + Q_D(const QLayout); + return d->rect; +} + +/*! + \reimp +*/ +void QLayout::invalidate() +{ + Q_D(QLayout); + d->rect = QRect(); + update(); +} + +static bool removeWidgetRecursively(QLayoutItem *li, QWidget *w) +{ + QLayout *lay = li->layout(); + if (!lay) + return false; + int i = 0; + QLayoutItem *child; + while ((child = lay->itemAt(i))) { + if (child->widget() == w) { + delete lay->takeAt(i); + lay->invalidate(); + return true; + } else if (removeWidgetRecursively(child, w)) { + return true; + } else { + ++i; + } + } + return false; +} + + +void QLayoutPrivate::doResize(const QSize &r) +{ + Q_Q(QLayout); + int mbh = menuBarHeightForWidth(menubar, r.width()); + QWidget *mw = q->parentWidget(); + QRect rect = mw->testAttribute(Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect(); + rect.setTop(rect.top() + mbh); + q->setGeometry(rect); +#ifndef QT_NO_MENUBAR + if (menubar) + menubar->setGeometry(0,0,r.width(), mbh); +#endif +} + + +/*! + \internal + Performs child widget layout when the parent widget is + resized. Also handles removal of widgets. \a e is the + event +*/ +void QLayout::widgetEvent(QEvent *e) +{ + Q_D(QLayout); + if (!d->enabled) + return; + + switch (e->type()) { + case QEvent::Resize: + if (d->activated) { + QResizeEvent *r = (QResizeEvent *)e; + d->doResize(r->size()); + } else { + activate(); + } + break; + case QEvent::ChildRemoved: + { + QChildEvent *c = (QChildEvent *)e; + if (c->child()->isWidgetType()) { + QWidget *w = (QWidget *)c->child(); +#ifndef QT_NO_MENUBAR + if (w == d->menubar) + d->menubar = 0; +#endif + removeWidgetRecursively(this, w); + } + } + break; +#ifdef QT3_SUPPORT + case QEvent::ChildInserted: + if (d->topLevel && d->autoNewChild) { + QChildEvent *c = (QChildEvent *)e; + if (c->child()->isWidgetType()) { + QWidget *w = (QWidget *)c->child(); + if (!w->isWindow()) { +#if !defined(QT_NO_MENUBAR) && !defined(QT_NO_TOOLBAR) + if (qobject_cast(w) && !qobject_cast(w->parentWidget())) { + d->menubar = (QMenuBar *)w; + invalidate(); + } else +#endif +#ifndef QT_NO_SIZEGRIP + if (qobject_cast(w) ) { + //SizeGrip is handled by the dialog itself. + } else +#endif + addItem(QLayoutPrivate::createWidgetItem(this, w)); + } + } + } + break; + case QEvent::LayoutHint: + d->activated = false; + // fall through +#endif + case QEvent::LayoutRequest: + if (static_cast(parent())->isVisible()) + activate(); + break; + default: + break; + } +} + +/*! + \reimp +*/ +void QLayout::childEvent(QChildEvent *e) +{ + Q_D(QLayout); + if (!d->enabled) + return; + + if (e->type() == QEvent::ChildRemoved) { + QChildEvent *c = (QChildEvent*)e; + int i = 0; + + QLayoutItem *item; + while ((item = itemAt(i))) { + if (item == static_cast(c->child())) { + takeAt(i); + invalidate(); + break; + } else { + ++i; + } + } + } +} + +/*! + \internal + Also takes contentsMargins and menu bar into account. +*/ +int QLayout::totalHeightForWidth(int w) const +{ + Q_D(const QLayout); + int side=0, top=0; + if (d->topLevel) { + QWidget *parent = parentWidget(); + parent->ensurePolished(); + QWidgetPrivate *wd = parent->d_func(); + side += wd->leftmargin + wd->rightmargin; + top += wd->topmargin + wd->bottommargin; + } + int h = heightForWidth(w - side) + top; +#ifndef QT_NO_MENUBAR + h += menuBarHeightForWidth(d->menubar, w); +#endif + return h; +} + +/*! + \internal + Also takes contentsMargins and menu bar into account. +*/ +QSize QLayout::totalMinimumSize() const +{ + Q_D(const QLayout); + int side=0, top=0; + if (d->topLevel) { + QWidget *pw = parentWidget(); + pw->ensurePolished(); + QWidgetPrivate *wd = pw->d_func(); + side += wd->leftmargin + wd->rightmargin; + top += wd->topmargin + wd->bottommargin; + } + + QSize s = minimumSize(); +#ifndef QT_NO_MENUBAR + top += menuBarHeightForWidth(d->menubar, s.width() + side); +#endif + return s + QSize(side, top); +} + +/*! + \internal + Also takes contentsMargins and menu bar into account. +*/ +QSize QLayout::totalSizeHint() const +{ + Q_D(const QLayout); + int side=0, top=0; + if (d->topLevel) { + QWidget *pw = parentWidget(); + pw->ensurePolished(); + QWidgetPrivate *wd = pw->d_func(); + side += wd->leftmargin + wd->rightmargin; + top += wd->topmargin + wd->bottommargin; + } + + QSize s = sizeHint(); + if (hasHeightForWidth()) + s.setHeight(heightForWidth(s.width() + side)); +#ifndef QT_NO_MENUBAR + top += menuBarHeightForWidth(d->menubar, s.width()); +#endif + return s + QSize(side, top); +} + +/*! + \internal + Also takes contentsMargins and menu bar into account. +*/ +QSize QLayout::totalMaximumSize() const +{ + Q_D(const QLayout); + int side=0, top=0; + if (d->topLevel) { + QWidget *pw = parentWidget(); + pw->ensurePolished(); + QWidgetPrivate *wd = pw->d_func(); + side += wd->leftmargin + wd->rightmargin; + top += wd->topmargin + wd->bottommargin; + } + + QSize s = maximumSize(); +#ifndef QT_NO_MENUBAR + top += menuBarHeightForWidth(d->menubar, s.width()); +#endif + + if (d->topLevel) + s = QSize(qMin(s.width() + side, QLAYOUTSIZE_MAX), + qMin(s.height() + top, QLAYOUTSIZE_MAX)); + return s; +} + +/*! + \internal + Destroys the layout, deleting all child layouts. + Geometry management stops when a top-level layout is deleted. + + The layout classes will probably be fatally confused if you delete + a sublayout. +*/ +QLayout::~QLayout() +{ + Q_D(QLayout); + /* + This function may be called during the QObject destructor, + when the parent no longer is a QWidget. + */ + if (d->topLevel && parent() && parent()->isWidgetType() && + ((QWidget*)parent())->layout() == this) + ((QWidget*)parent())->d_func()->layout = 0; +} + +#ifdef QT3_SUPPORT +/*! + Removes and deletes all items in this layout. +*/ +void QLayout::deleteAllItems() +{ + QLayoutItem *l; + while ((l = takeAt(0))) + delete l; +} +#endif + +/*! + This function is called from \c addLayout() or \c insertLayout() functions in + subclasses to add layout \a l as a sub-layout. + + The only scenario in which you need to call it directly is if you + implement a custom layout that supports nested layouts. + + \sa QBoxLayout::addLayout(), QBoxLayout::insertLayout(), QGridLayout::addLayout() +*/ +void QLayout::addChildLayout(QLayout *l) +{ + if (l->parent()) { + qWarning("QLayout::addChildLayout: layout \"%s\" already has a parent", + l->objectName().toLocal8Bit().data()); + return; + } + l->setParent(this); + + if (QWidget *mw = parentWidget()) { + l->d_func()->reparentChildWidgets(mw); + } + +} + +#ifdef QT_DEBUG +static bool layoutDebug() +{ + static int checked_env = -1; + if(checked_env == -1) + checked_env = !!qgetenv("QT_LAYOUT_DEBUG").toInt(); + + return checked_env; +} +#endif + +void QLayoutPrivate::reparentChildWidgets(QWidget *mw) +{ + Q_Q(QLayout); + int n = q->count(); + +#ifndef QT_NO_MENUBAR + if (menubar && menubar->parentWidget() != mw) { + menubar->setParent(mw); + } +#endif + bool mwVisible = mw && mw->isVisible(); + for (int i = 0; i < n; ++i) { + QLayoutItem *item = q->itemAt(i); + if (QWidget *w = item->widget()) { + QWidget *pw = w->parentWidget(); +#ifdef QT_DEBUG + if (pw && pw != mw && layoutDebug()) { + qWarning("QLayout::addChildLayout: widget %s \"%s\" in wrong parent; moved to correct parent", + w->metaObject()->className(), w->objectName().toLocal8Bit().data()); + } +#endif + bool needShow = mwVisible && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide)); + if (pw != mw) + w->setParent(mw); + if (needShow) + QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later + } else if (QLayout *l = item->layout()) { + l->d_func()->reparentChildWidgets(mw); + } + } +} + +/*! + This function is called from \c addWidget() functions in + subclasses to add \a w as a managed widget of a layout. + + If \a w is already managed by a layout, this function will give a warning + and remove \a w from that layout. This function must therefore be + called before adding \a w to the layout's data structure. +*/ +void QLayout::addChildWidget(QWidget *w) +{ + QWidget *mw = parentWidget(); + QWidget *pw = w->parentWidget(); + + //Qt::WA_LaidOut is never reset. It only means that the widget at some point has + //been in a layout. + if (pw && w->testAttribute(Qt::WA_LaidOut)) { + QLayout *l = pw->layout(); + if (l && removeWidgetRecursively(l, w)) { +#ifdef QT_DEBUG + if (layoutDebug()) + qWarning("QLayout::addChildWidget: %s \"%s\" is already in a layout; moved to new layout", + w->metaObject()->className(), w->objectName().toLocal8Bit().data()); +#endif + } + } + if (pw && mw && pw != mw) { +#ifdef QT_DEBUG + if (layoutDebug()) + qWarning("QLayout::addChildWidget: %s \"%s\" in wrong parent; moved to correct parent", + w->metaObject()->className(), w->objectName().toLocal8Bit().data()); +#endif + pw = 0; + } + bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide)); + if (!pw && mw) + w->setParent(mw); + w->setAttribute(Qt::WA_LaidOut); + if (needShow) + QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later +} + +#ifdef QT3_SUPPORT +/*! + \compat + + Sets this layout's parent widget to a fixed size with width \a w + and height \a h, stopping the user from resizing it, and also + prevents the layout from resizing it, even if the layout's size + hint should change. Does nothing if this is not a top-level + layout (i.e., if parent()->isWidgetType()). + + As a special case, if both \a w and \a h are 0, then the layout's + current sizeHint() is used. + + Use \c setResizeMode(Fixed) to stop the widget from being resized + by the user, while still allowing the layout to resize it when + the sizeHint() changes. + + Use \c setResizeMode(FreeResize) to allow the user to resize the + widget, while preventing the layout from resizing it. + +*/ +void QLayout::freeze(int w, int h) +{ + Q_D(QLayout); + if (!d->topLevel) + return; + if (w <= 0 || h <= 0) { + QSize s = totalSizeHint(); + w = s.width(); + h = s.height(); + } + setSizeConstraint(SetNoConstraint); // layout will not change min/max size + QWidget *parent = parentWidget(); + if (parent) + parent->setFixedSize(w, h); +} + +#endif + + + + + + + +/*! + Tells the geometry manager to place the menu bar \a widget at the + top of parentWidget(), outside QWidget::contentsMargins(). All + child widgets are placed below the bottom edge of the menu bar. +*/ +void QLayout::setMenuBar(QWidget *widget) +{ + Q_D(QLayout); + +#ifdef Q_OS_WINCE_WM + if (widget && widget->size().height() > 0) +#else + if (widget) +#endif + addChildWidget(widget); + d->menubar = widget; +} + +/*! + Returns the menu bar set for this layout, or 0 if no menu bar is + set. +*/ + +QWidget *QLayout::menuBar() const +{ + Q_D(const QLayout); + return d->menubar; +} + + +/*! + Returns the minimum size of this layout. This is the smallest + size that the layout can have while still respecting the + specifications. + + The returned value doesn't include the space required by + QWidget::setContentsMargins() or menuBar(). + + The default implementation allows unlimited resizing. +*/ +QSize QLayout::minimumSize() const +{ + return QSize(0, 0); +} + +/*! + Returns the maximum size of this layout. This is the largest size + that the layout can have while still respecting the + specifications. + + The returned value doesn't include the space required by + QWidget::setContentsMargins() or menuBar(). + + The default implementation allows unlimited resizing. +*/ +QSize QLayout::maximumSize() const +{ + return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX); +} + +/*! + Returns whether this layout can make use of more space than + sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that + it wants to grow in only one dimension, whereas Qt::Vertical | + Qt::Horizontal means that it wants to grow in both dimensions. + + The default implementation returns Qt::Horizontal | Qt::Vertical. + Subclasses reimplement it to return a meaningful value based on + their child widgets's \l{QSizePolicy}{size policies}. + + \sa sizeHint() +*/ +Qt::Orientations QLayout::expandingDirections() const +{ + return Qt::Horizontal | Qt::Vertical; +} + +void QLayout::activateRecursiveHelper(QLayoutItem *item) +{ + item->invalidate(); + QLayout *layout = item->layout(); + if (layout) { + QLayoutItem *child; + int i=0; + while ((child = layout->itemAt(i++))) + activateRecursiveHelper(child); + layout->d_func()->activated = true; + } +} + +/*! + Updates the layout for parentWidget(). + + You should generally not need to call this because it is + automatically called at the most appropriate times. + + \sa activate(), invalidate() +*/ + +void QLayout::update() +{ + QLayout *layout = this; + while (layout && layout->d_func()->activated) { + layout->d_func()->activated = false; + if (layout->d_func()->topLevel) { + Q_ASSERT(layout->parent()->isWidgetType()); + QWidget *mw = static_cast(layout->parent()); + QApplication::postEvent(mw, new QEvent(QEvent::LayoutRequest)); + break; + } + layout = static_cast(layout->parent()); + } +} + +/*! + Redoes the layout for parentWidget() if necessary. + + You should generally not need to call this because it is + automatically called at the most appropriate times. It returns + true if the layout was redone. + + \sa update(), QWidget::updateGeometry() +*/ +bool QLayout::activate() +{ + Q_D(QLayout); + if (!d->enabled || !parent()) + return false; + if (!d->topLevel) + return static_cast(parent())->activate(); + if (d->activated) + return false; + QWidget *mw = static_cast(parent()); + if (mw == 0) { + qWarning("QLayout::activate: %s \"%s\" does not have a main widget", + QObject::metaObject()->className(), QObject::objectName().toLocal8Bit().data()); + return false; + } + activateRecursiveHelper(this); + + QWidgetPrivate *md = mw->d_func(); + uint explMin = md->extra ? md->extra->explicitMinSize : 0; + uint explMax = md->extra ? md->extra->explicitMaxSize : 0; + + switch (d->constraint) { + case SetFixedSize: + // will trigger resize + mw->setFixedSize(totalSizeHint()); + break; + case SetMinimumSize: + mw->setMinimumSize(totalMinimumSize()); + break; + case SetMaximumSize: + mw->setMaximumSize(totalMaximumSize()); + break; + case SetMinAndMaxSize: + mw->setMinimumSize(totalMinimumSize()); + mw->setMaximumSize(totalMaximumSize()); + break; + case SetDefaultConstraint: { + bool widthSet = explMin & Qt::Horizontal; + bool heightSet = explMin & Qt::Vertical; + if (mw->isWindow()) { + QSize ms = totalMinimumSize(); + if (widthSet) + ms.setWidth(mw->minimumSize().width()); + if (heightSet) + ms.setHeight(mw->minimumSize().height()); + if ((!heightSet || !widthSet) && hasHeightForWidth()) { + int h = minimumHeightForWidth(ms.width()); + if (h > ms.height()) { + if (!heightSet) + ms.setHeight(0); + if (!widthSet) + ms.setWidth(0); + } + } + mw->setMinimumSize(ms); + } else if (!widthSet || !heightSet) { + QSize ms = mw->minimumSize(); + if (!widthSet) + ms.setWidth(0); + if (!heightSet) + ms.setHeight(0); + mw->setMinimumSize(ms); + } + break; + } + case SetNoConstraint: + break; + } + + d->doResize(mw->size()); + + if (md->extra) { + md->extra->explicitMinSize = explMin; + md->extra->explicitMaxSize = explMax; + } + // ideally only if sizeHint() or sizePolicy() has changed + mw->updateGeometry(); + return true; +} + +/*! + \fn QLayoutItem *QLayout::itemAt(int index) const + + Must be implemented in subclasses to return the layout item at \a + index. If there is no such item, the function must return 0. + Items are numbered consecutively from 0. If an item is deleted, other items will be renumbered. + + This function can be used to iterate over a layout. The following + code will draw a rectangle for each layout item in the layout structure of the widget. + + \snippet doc/src/snippets/code/src_gui_kernel_qlayout.cpp 0 + + \sa count(), takeAt() +*/ + +/*! + \fn QLayoutItem *QLayout::takeAt(int index) + + Must be implemented in subclasses to remove the layout item at \a + index from the layout, and return the item. If there is no such + item, the function must do nothing and return 0. Items are numbered + consecutively from 0. If an item is removed, other items will be + renumbered. + + The following code fragment shows a safe way to remove all items + from a layout: + + \snippet doc/src/snippets/code/src_gui_kernel_qlayout.cpp 1 + + \sa itemAt(), count() +*/ + +/*! + \fn int *QLayout::count() const + + Must be implemented in subclasses to return the number of items + in the layout. + + \sa itemAt() +*/ + +/*! + Searches for widget \a widget in this layout (not including child + layouts). + + Returns the index of \a widget, or -1 if \a widget is not found. + + The default implementation iterates over all items using itemAt() +*/ +int QLayout::indexOf(QWidget *widget) const +{ + int i = 0; + QLayoutItem *item = itemAt(i); + while (item) { + if (item->widget() == widget) + return i; + ++i; + item = itemAt(i); + } + return -1; +} + +/*! + \enum QLayout::SizeConstraint + + The possible values are: + + \value SetDefaultConstraint The main widget's minimum size is set + to minimumSize(), unless the widget already has + a minimum size. + + \value SetFixedSize The main widget's size is set to sizeHint(); it + cannot be resized at all. + \value SetMinimumSize The main widget's minimum size is set to + minimumSize(); it cannot be smaller. + + \value SetMaximumSize The main widget's maximum size is set to + maximumSize(); it cannot be larger. + + \value SetMinAndMaxSize The main widget's minimum size is set to + minimumSize() and its maximum size is set to + maximumSize(). + + \value SetNoConstraint The widget is not constrained. + + \omitvalue Auto + \omitvalue FreeResize + \omitvalue Minimum + \omitvalue Fixed + + \sa setSizeConstraint() +*/ + +/*! + \property QLayout::sizeConstraint + \brief the resize mode of the layout + + The default mode is \l {QLayout::SetDefaultConstraint} + {SetDefaultConstraint}. +*/ +void QLayout::setSizeConstraint(SizeConstraint constraint) +{ + Q_D(QLayout); + if (constraint == d->constraint) + return; + + d->constraint = constraint; + invalidate(); +} + +QLayout::SizeConstraint QLayout::sizeConstraint() const +{ + Q_D(const QLayout); + return d->constraint; +} + +/*! + Returns the rectangle that should be covered when the geometry of + this layout is set to \a r, provided that this layout supports + setAlignment(). + + The result is derived from sizeHint() and expanding(). It is never + larger than \a r. +*/ +QRect QLayout::alignmentRect(const QRect &r) const +{ + QSize s = sizeHint(); + Qt::Alignment a = alignment(); + + /* + This is a hack to obtain the real maximum size, not + QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX), the value consistently + returned by QLayoutItems that have an alignment. + */ + QLayout *that = const_cast(this); + that->setAlignment(0); + QSize ms = that->maximumSize(); + that->setAlignment(a); + + if ((expandingDirections() & Qt::Horizontal) || + !(a & Qt::AlignHorizontal_Mask)) { + s.setWidth(qMin(r.width(), ms.width())); + } + if ((expandingDirections() & Qt::Vertical) || + !(a & Qt::AlignVertical_Mask)) { + s.setHeight(qMin(r.height(), ms.height())); + } else if (hasHeightForWidth()) { + int hfw = heightForWidth(s.width()); + if (hfw < s.height()) + s.setHeight(qMin(hfw, ms.height())); + } + + s = s.boundedTo(r.size()); + int x = r.x(); + int y = r.y(); + + if (a & Qt::AlignBottom) + y += (r.height() - s.height()); + else if (!(a & Qt::AlignTop)) + y += (r.height() - s.height()) / 2; + + QWidget *parent = parentWidget(); + a = QStyle::visualAlignment(parent ? parent->layoutDirection() : QApplication::layoutDirection(), a); + if (a & Qt::AlignRight) + x += (r.width() - s.width()); + else if (!(a & Qt::AlignLeft)) + x += (r.width() - s.width()) / 2; + + return QRect(x, y, s.width(), s.height()); +} + +/*! + Removes the widget \a widget from the layout. After this call, it + is the caller's responsibility to give the widget a reasonable + geometry or to put the widget back into a layout. + + \bold{Note:} The ownership of \a widget remains the same as + when it was added. + + \sa removeItem(), QWidget::setGeometry(), addWidget() +*/ +void QLayout::removeWidget(QWidget *widget) +{ + int i = 0; + QLayoutItem *child; + while ((child = itemAt(i))) { + if (child->widget() == widget) { + delete takeAt(i); + invalidate(); + } else { + ++i; + } + } +} + +/*! + Removes the layout item \a item from the layout. It is the + caller's responsibility to delete the item. + + Notice that \a item can be a layout (since QLayout inherits + QLayoutItem). + + \sa removeWidget(), addItem() +*/ +void QLayout::removeItem(QLayoutItem *item) +{ + int i = 0; + QLayoutItem *child; + while ((child = itemAt(i))) { + if (child == item) { + takeAt(i); + invalidate(); + } else { + ++i; + } + } +} + +/*! + Enables this layout if \a enable is true, otherwise disables it. + + An enabled layout adjusts dynamically to changes; a disabled + layout acts as if it did not exist. + + By default all layouts are enabled. + + \sa isEnabled() +*/ +void QLayout::setEnabled(bool enable) +{ + Q_D(QLayout); + d->enabled = enable; +} + +/*! + Returns true if the layout is enabled; otherwise returns false. + + \sa setEnabled() +*/ +bool QLayout::isEnabled() const +{ + Q_D(const QLayout); + return d->enabled; +} + +/*! + Returns a size that satisfies all size constraints on \a widget, + including heightForWidth() and that is as close as possible to \a + size. +*/ + +QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size) +{ + QSize result = size.boundedTo(qSmartMaxSize(widget)); + result = result.expandedTo(qSmartMinSize(widget)); + QLayout *l = widget->layout(); + if (l && l->hasHeightForWidth() && result.height() < l->minimumHeightForWidth(result.width()) ) { + QSize current = widget->size(); + int currentHfw = l->minimumHeightForWidth(current.width()); + int newHfw = l->minimumHeightForWidth(result.width()); + if (current.height() < currentHfw || currentHfw == newHfw) { + //handle the constant hfw case and the vertical-only case, as well as the + // current-size-is-not-correct case + result.setHeight(newHfw); + } else { + // binary search; assume hfw is decreasing ### + + int maxw = qMax(widget->width(),result.width()); + int maxh = qMax(widget->height(), result.height()); + int minw = qMin(widget->width(),result.width()); + int minh = qMin(widget->height(), result.height()); + + int minhfw = l->minimumHeightForWidth(minw); + int maxhfw = l->minimumHeightForWidth(maxw); + while (minw < maxw) { + if (minhfw > maxh) { //assume decreasing + minw = maxw - (maxw-minw)/2; + minhfw = l->minimumHeightForWidth(minw); + } else if (maxhfw < minh ) { //assume decreasing + maxw = minw + (maxw-minw)/2; + maxhfw = l->minimumHeightForWidth(maxw); + } else { + break; + } + } + result = result.expandedTo(QSize(minw, minhfw)); + } + } + return result; +} + +/*! + \fn void QLayout::setResizeMode(SizeConstraint constraint) + + Use setSizeConstraint(\a constraint) instead. +*/ + +/*! + \fn QLayout::SizeConstraint QLayout::resizeMode() const + + Use sizeConstraint() instead. +*/ + +void QSizePolicy::setControlType(ControlType type) +{ + /* + The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10, + etc. In memory, we pack it onto the available bits (CTSize) in + setControlType(), and unpack it here. + + Example: + + 0x00000001 maps to 0x00000000 + 0x00000002 maps to 0x00000200 + 0x00000004 maps to 0x00000400 + 0x00000008 maps to 0x00000600 + etc. + */ + + int i = 0; + while (true) { + if (type & (0x1 << i)) { + data = (data & ~CTMask) | (i << CTShift); + return; + } + ++i; + } +} + +QSizePolicy::ControlType QSizePolicy::controlType() const +{ + return QSizePolicy::ControlType(0x1 << ((data & CTMask) >> CTShift)); +} + +#ifndef QT_NO_DATASTREAM +/*! + \relates QSizePolicy + \since 4.2 + + Writes the size \a policy to the data stream \a stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ +QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy) +{ + return stream << policy.data; +} + +/*! + \relates QSizePolicy + \since 4.2 + + Reads the size \a policy from the data stream \a stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ +QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy) +{ + return stream >> policy.data; +} +#endif // QT_NO_DATASTREAM + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qlayout.h b/src/widgets/kernel/qlayout.h new file mode 100644 index 0000000000..5333150072 --- /dev/null +++ b/src/widgets/kernel/qlayout.h @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUT_H +#define QLAYOUT_H + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QLayout; +class QSize; + +#ifdef QT3_SUPPORT +class Q_GUI_EXPORT QLayoutIterator +{ +public: + inline QT3_SUPPORT_CONSTRUCTOR QLayoutIterator(QLayout *i) : layout(i), index(0) {} + inline QLayoutIterator(const QLayoutIterator &i) + : layout(i.layout), index(i.index) {} + inline QLayoutIterator &operator=(const QLayoutIterator &i) { + layout = i.layout; + index = i.index; + return *this; + } + inline QT3_SUPPORT QLayoutItem *operator++(); + inline QT3_SUPPORT QLayoutItem *current(); + inline QT3_SUPPORT QLayoutItem *takeCurrent(); + inline QT3_SUPPORT void deleteCurrent(); + +private: + // hack to avoid deprecated warning + friend class QLayout; + inline QLayoutIterator(QLayout *i, bool) : layout(i), index(0) {} + QLayout *layout; + int index; +}; +#endif + +class QLayoutPrivate; + +class Q_GUI_EXPORT QLayout : public QObject, public QLayoutItem +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QLayout) + + Q_ENUMS(SizeConstraint) + Q_PROPERTY(int margin READ margin WRITE setMargin) + Q_PROPERTY(int spacing READ spacing WRITE setSpacing) + Q_PROPERTY(SizeConstraint sizeConstraint READ sizeConstraint WRITE setSizeConstraint) +public: + enum SizeConstraint { + SetDefaultConstraint, + SetNoConstraint, + SetMinimumSize, + SetFixedSize, + SetMaximumSize, + SetMinAndMaxSize +#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN) + , Auto = SetDefaultConstraint, + FreeResize = SetNoConstraint, + Minimum = SetMinimumSize, + Fixed = SetFixedSize +#endif + }; + + QLayout(QWidget *parent); + QLayout(); + ~QLayout(); + + int margin() const; + int spacing() const; + + void setMargin(int); + void setSpacing(int); + + void setContentsMargins(int left, int top, int right, int bottom); + void setContentsMargins(const QMargins &margins); + void getContentsMargins(int *left, int *top, int *right, int *bottom) const; + QMargins contentsMargins() const; + QRect contentsRect() const; + + bool setAlignment(QWidget *w, Qt::Alignment alignment); + bool setAlignment(QLayout *l, Qt::Alignment alignment); +#ifdef Q_NO_USING_KEYWORD + inline void setAlignment(Qt::Alignment alignment) { QLayoutItem::setAlignment(alignment); } +#else + using QLayoutItem::setAlignment; +#endif + + void setSizeConstraint(SizeConstraint); + SizeConstraint sizeConstraint() const; +#ifdef QT3_SUPPORT + inline QT3_SUPPORT void setResizeMode(SizeConstraint s) {setSizeConstraint(s);} + inline QT3_SUPPORT SizeConstraint resizeMode() const {return sizeConstraint();} +#endif + void setMenuBar(QWidget *w); + QWidget *menuBar() const; + + QWidget *parentWidget() const; + + void invalidate(); + QRect geometry() const; + bool activate(); + void update(); + + void addWidget(QWidget *w); + virtual void addItem(QLayoutItem *) = 0; + + void removeWidget(QWidget *w); + void removeItem(QLayoutItem *); + + Qt::Orientations expandingDirections() const; + QSize minimumSize() const; + QSize maximumSize() const; + virtual void setGeometry(const QRect&); + virtual QLayoutItem *itemAt(int index) const = 0; + virtual QLayoutItem *takeAt(int index) = 0; + virtual int indexOf(QWidget *) const; + virtual int count() const = 0; + bool isEmpty() const; + + int totalHeightForWidth(int w) const; + QSize totalMinimumSize() const; + QSize totalMaximumSize() const; + QSize totalSizeHint() const; + QLayout *layout(); + + void setEnabled(bool); + bool isEnabled() const; + +#ifdef QT3_SUPPORT + QT3_SUPPORT void freeze(int w=0, int h=0); + QT3_SUPPORT bool isTopLevel() const; +#endif + + static QSize closestAcceptableSize(const QWidget *w, const QSize &s); + +protected: + void widgetEvent(QEvent *); + void childEvent(QChildEvent *e); + void addChildLayout(QLayout *l); + void addChildWidget(QWidget *w); +#ifdef QT3_SUPPORT + QT3_SUPPORT void deleteAllItems(); +#endif + + QRect alignmentRect(const QRect&) const; +protected: + QLayout(QLayoutPrivate &d, QLayout*, QWidget*); + +private: + Q_DISABLE_COPY(QLayout) + + static void activateRecursiveHelper(QLayoutItem *item); + + friend class QApplicationPrivate; + friend class QWidget; + +#ifdef QT3_SUPPORT +public: + QT3_SUPPORT_CONSTRUCTOR QLayout(QWidget *parent, int margin, int spacing = -1, + const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QLayout(QLayout *parentLayout, int spacing = -1, const char *name = 0); + QT3_SUPPORT_CONSTRUCTOR QLayout(int spacing, const char *name = 0); + inline QT3_SUPPORT QWidget *mainWidget() const { return parentWidget(); } + inline QT3_SUPPORT void remove(QWidget *w) { removeWidget(w); } + inline QT3_SUPPORT void add(QWidget *w) { addWidget(w); } + + QT3_SUPPORT void setAutoAdd(bool a); + QT3_SUPPORT bool autoAdd() const; + inline QT3_SUPPORT QLayoutIterator iterator() { return QLayoutIterator(this,true); } + + inline QT3_SUPPORT int defaultBorder() const { return spacing(); } +#endif +}; + +#ifdef QT3_SUPPORT +inline QLayoutItem *QLayoutIterator::operator++() { return layout->itemAt(++index); } +inline QLayoutItem *QLayoutIterator::current() { return layout->itemAt(index); } +inline QLayoutItem *QLayoutIterator::takeCurrent() { return layout->takeAt(index); } +inline void QLayoutIterator::deleteCurrent() { delete layout->takeAt(index); } +#endif + +//### support old includes +#if 1 //def QT3_SUPPORT +QT_BEGIN_INCLUDE_NAMESPACE +#include +#include +QT_END_INCLUDE_NAMESPACE +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QLAYOUT_H diff --git a/src/widgets/kernel/qlayout_p.h b/src/widgets/kernel/qlayout_p.h new file mode 100644 index 0000000000..342333954c --- /dev/null +++ b/src/widgets/kernel/qlayout_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUT_P_H +#define QLAYOUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qlayout*.cpp, and qabstractlayout.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qobject_p.h" +#include "qstyle.h" +#include "qsizepolicy.h" + +QT_BEGIN_NAMESPACE + +class QWidgetItem; +class QSpacerItem; + +class Q_GUI_EXPORT QLayoutPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QLayout) + +public: + typedef QWidgetItem * (*QWidgetItemFactoryMethod)(const QLayout *layout, QWidget *widget); + typedef QSpacerItem * (*QSpacerItemFactoryMethod)(const QLayout *layout, int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy); + + QLayoutPrivate(); + + void getMargin(int *result, int userMargin, QStyle::PixelMetric pm) const; + void doResize(const QSize &); + void reparentChildWidgets(QWidget *mw); + + static QWidgetItem *createWidgetItem(const QLayout *layout, QWidget *widget); + static QSpacerItem *createSpacerItem(const QLayout *layout, int w, int h, QSizePolicy::Policy hPolicy = QSizePolicy::Minimum, QSizePolicy::Policy vPolicy = QSizePolicy::Minimum); + + static QWidgetItemFactoryMethod widgetItemFactoryMethod; + static QSpacerItemFactoryMethod spacerItemFactoryMethod; + + int insideSpacing; + int userLeftMargin; + int userTopMargin; + int userRightMargin; + int userBottomMargin; + uint topLevel : 1; + uint enabled : 1; + uint activated : 1; + uint autoNewChild : 1; + QLayout::SizeConstraint constraint; + QRect rect; + QWidget *menubar; +}; + +QT_END_NAMESPACE + +#endif // QLAYOUT_P_H diff --git a/src/widgets/kernel/qlayoutengine.cpp b/src/widgets/kernel/qlayoutengine.cpp new file mode 100644 index 0000000000..fdabd8ae1f --- /dev/null +++ b/src/widgets/kernel/qlayoutengine.cpp @@ -0,0 +1,436 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayout.h" +#include "private/qlayoutengine_p.h" + +#include "qvector.h" +#include "qwidget.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +//#define QLAYOUT_EXTRA_DEBUG + +typedef qint64 Fixed64; +static inline Fixed64 toFixed(int i) { return (Fixed64)i * 256; } +static inline int fRound(Fixed64 i) { + return (i % 256 < 128) ? i / 256 : 1 + i / 256; +} + +/* + This is the main workhorse of the QGridLayout. It portions out + available space to the chain's children. + + The calculation is done in fixed point: "fixed" variables are + scaled by a factor of 256. + + If the layout runs "backwards" (i.e. RightToLeft or Up) the layout + is computed mirror-reversed, and it's the caller's responsibility + do reverse the values before use. + + chain contains input and output parameters describing the geometry. + count is the count of items in the chain; pos and space give the + interval (relative to parentWidget topLeft). +*/ +void qGeomCalc(QVector &chain, int start, int count, + int pos, int space, int spacer) +{ + int cHint = 0; + int cMin = 0; + int cMax = 0; + int sumStretch = 0; + int sumSpacing = 0; + + bool wannaGrow = false; // anyone who really wants to grow? + // bool canShrink = false; // anyone who could be persuaded to shrink? + + bool allEmptyNonstretch = true; + int pendingSpacing = -1; + int spacerCount = 0; + int i; + + for (i = start; i < start + count; i++) { + QLayoutStruct *data = &chain[i]; + + data->done = false; + cHint += data->smartSizeHint(); + cMin += data->minimumSize; + cMax += data->maximumSize; + sumStretch += data->stretch; + if (!data->empty) { + /* + Using pendingSpacing, we ensure that the spacing for the last + (non-empty) item is ignored. + */ + if (pendingSpacing >= 0) { + sumSpacing += pendingSpacing; + ++spacerCount; + } + pendingSpacing = data->effectiveSpacer(spacer); + } + wannaGrow = wannaGrow || data->expansive || data->stretch > 0; + allEmptyNonstretch = allEmptyNonstretch && !wannaGrow && data->empty; + } + + int extraspace = 0; + + if (space < cMin + sumSpacing) { + /* + Less space than minimumSize; take from the biggest first + */ + + int minSize = cMin + sumSpacing; + + // shrink the spacers proportionally + if (spacer >= 0) { + spacer = minSize > 0 ? spacer * space / minSize : 0; + sumSpacing = spacer * spacerCount; + } + + QList list; + + for (i = start; i < start + count; i++) + list << chain.at(i).minimumSize; + + qSort(list); + + int space_left = space - sumSpacing; + + int sum = 0; + int idx = 0; + int space_used=0; + int current = 0; + while (idx < count && space_used < space_left) { + current = list.at(idx); + space_used = sum + current * (count - idx); + sum += current; + ++idx; + } + --idx; + int deficit = space_used - space_left; + + int items = count - idx; + /* + * If we truncate all items to "current", we would get "deficit" too many pixels. Therefore, we have to remove + * deficit/items from each item bigger than maxval. The actual value to remove is deficitPerItem + remainder/items + * "rest" is the accumulated error from using integer arithmetic. + */ + int deficitPerItem = deficit/items; + int remainder = deficit % items; + int maxval = current - deficitPerItem; + + int rest = 0; + for (i = start; i < start + count; i++) { + int maxv = maxval; + rest += remainder; + if (rest >= items) { + maxv--; + rest-=items; + } + QLayoutStruct *data = &chain[i]; + data->size = qMin(data->minimumSize, maxv); + data->done = true; + } + } else if (space < cHint + sumSpacing) { + /* + Less space than smartSizeHint(), but more than minimumSize. + Currently take space equally from each, as in Qt 2.x. + Commented-out lines will give more space to stretchier + items. + */ + int n = count; + int space_left = space - sumSpacing; + int overdraft = cHint - space_left; + + // first give to the fixed ones: + for (i = start; i < start + count; i++) { + QLayoutStruct *data = &chain[i]; + if (!data->done + && data->minimumSize >= data->smartSizeHint()) { + data->size = data->smartSizeHint(); + data->done = true; + space_left -= data->smartSizeHint(); + // sumStretch -= data->stretch; + n--; + } + } + bool finished = n == 0; + while (!finished) { + finished = true; + Fixed64 fp_over = toFixed(overdraft); + Fixed64 fp_w = 0; + + for (i = start; i < start+count; i++) { + QLayoutStruct *data = &chain[i]; + if (data->done) + continue; + // if (sumStretch <= 0) + fp_w += fp_over / n; + // else + // fp_w += (fp_over * data->stretch) / sumStretch; + int w = fRound(fp_w); + data->size = data->smartSizeHint() - w; + fp_w -= toFixed(w); // give the difference to the next + if (data->size < data->minimumSize) { + data->done = true; + data->size = data->minimumSize; + finished = false; + overdraft -= data->smartSizeHint() - data->minimumSize; + // sumStretch -= data->stretch; + n--; + break; + } + } + } + } else { // extra space + int n = count; + int space_left = space - sumSpacing; + // first give to the fixed ones, and handle non-expansiveness + for (i = start; i < start + count; i++) { + QLayoutStruct *data = &chain[i]; + if (!data->done + && (data->maximumSize <= data->smartSizeHint() + || (wannaGrow && !data->expansive && data->stretch == 0) + || (!allEmptyNonstretch && data->empty && + !data->expansive && data->stretch == 0))) { + data->size = data->smartSizeHint(); + data->done = true; + space_left -= data->size; + sumStretch -= data->stretch; + n--; + } + } + extraspace = space_left; + + /* + Do a trial distribution and calculate how much it is off. + If there are more deficit pixels than surplus pixels, give + the minimum size items what they need, and repeat. + Otherwise give to the maximum size items, and repeat. + + Paul Olav Tvete has a wonderful mathematical proof of the + correctness of this principle, but unfortunately this + comment is too small to contain it. + */ + int surplus, deficit; + do { + surplus = deficit = 0; + Fixed64 fp_space = toFixed(space_left); + Fixed64 fp_w = 0; + for (i = start; i < start + count; i++) { + QLayoutStruct *data = &chain[i]; + if (data->done) + continue; + extraspace = 0; + if (sumStretch <= 0) + fp_w += fp_space / n; + else + fp_w += (fp_space * data->stretch) / sumStretch; + int w = fRound(fp_w); + data->size = w; + fp_w -= toFixed(w); // give the difference to the next + if (w < data->smartSizeHint()) { + deficit += data->smartSizeHint() - w; + } else if (w > data->maximumSize) { + surplus += w - data->maximumSize; + } + } + if (deficit > 0 && surplus <= deficit) { + // give to the ones that have too little + for (i = start; i < start+count; i++) { + QLayoutStruct *data = &chain[i]; + if (!data->done && data->size < data->smartSizeHint()) { + data->size = data->smartSizeHint(); + data->done = true; + space_left -= data->smartSizeHint(); + sumStretch -= data->stretch; + n--; + } + } + } + if (surplus > 0 && surplus >= deficit) { + // take from the ones that have too much + for (i = start; i < start + count; i++) { + QLayoutStruct *data = &chain[i]; + if (!data->done && data->size > data->maximumSize) { + data->size = data->maximumSize; + data->done = true; + space_left -= data->maximumSize; + sumStretch -= data->stretch; + n--; + } + } + } + } while (n > 0 && surplus != deficit); + if (n == 0) + extraspace = space_left; + } + + /* + As a last resort, we distribute the unwanted space equally + among the spacers (counting the start and end of the chain). We + could, but don't, attempt a sub-pixel allocation of the extra + space. + */ + int extra = extraspace / (spacerCount + 2); + int p = pos + extra; + for (i = start; i < start+count; i++) { + QLayoutStruct *data = &chain[i]; + data->pos = p; + p += data->size; + if (!data->empty) + p += data->effectiveSpacer(spacer) + extra; + } + +#ifdef QLAYOUT_EXTRA_DEBUG + qDebug() << "qGeomCalc" << "start" << start << "count" << count << "pos" << pos + << "space" << space << "spacer" << spacer; + for (i = start; i < start + count; ++i) { + qDebug() << i << ':' << chain[i].minimumSize << chain[i].smartSizeHint() + << chain[i].maximumSize << "stretch" << chain[i].stretch + << "empty" << chain[i].empty << "expansive" << chain[i].expansive + << "spacing" << chain[i].spacing; + qDebug() << "result pos" << chain[i].pos << "size" << chain[i].size; + } +#endif +} + +Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint, + const QSize &minSize, const QSize &maxSize, + const QSizePolicy &sizePolicy) +{ + QSize s(0, 0); + + if (sizePolicy.horizontalPolicy() != QSizePolicy::Ignored) { + if (sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag) + s.setWidth(minSizeHint.width()); + else + s.setWidth(qMax(sizeHint.width(), minSizeHint.width())); + } + + if (sizePolicy.verticalPolicy() != QSizePolicy::Ignored) { + if (sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag) { + s.setHeight(minSizeHint.height()); + } else { + s.setHeight(qMax(sizeHint.height(), minSizeHint.height())); + } + } + + s = s.boundedTo(maxSize); + if (minSize.width() > 0) + s.setWidth(minSize.width()); + if (minSize.height() > 0) + s.setHeight(minSize.height()); + + return s.expandedTo(QSize(0,0)); +} + +Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i) +{ + QWidget *w = ((QWidgetItem *)i)->widget(); + return qSmartMinSize(w->sizeHint(), w->minimumSizeHint(), + w->minimumSize(), w->maximumSize(), + w->sizePolicy()); +} + +Q_GUI_EXPORT QSize qSmartMinSize(const QWidget *w) +{ + return qSmartMinSize(w->sizeHint(), w->minimumSizeHint(), + w->minimumSize(), w->maximumSize(), + w->sizePolicy()); +} + +Q_GUI_EXPORT QSize qSmartMaxSize(const QSize &sizeHint, + const QSize &minSize, const QSize &maxSize, + const QSizePolicy &sizePolicy, Qt::Alignment align) +{ + if (align & Qt::AlignHorizontal_Mask && align & Qt::AlignVertical_Mask) + return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX); + QSize s = maxSize; + QSize hint = sizeHint.expandedTo(minSize); + if (s.width() == QWIDGETSIZE_MAX && !(align & Qt::AlignHorizontal_Mask)) + if (!(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag)) + s.setWidth(hint.width()); + + if (s.height() == QWIDGETSIZE_MAX && !(align & Qt::AlignVertical_Mask)) + if (!(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag)) + s.setHeight(hint.height()); + + if (align & Qt::AlignHorizontal_Mask) + s.setWidth(QLAYOUTSIZE_MAX); + if (align & Qt::AlignVertical_Mask) + s.setHeight(QLAYOUTSIZE_MAX); + return s; +} + +Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align) +{ + QWidget *w = ((QWidgetItem*)i)->widget(); + + return qSmartMaxSize(w->sizeHint().expandedTo(w->minimumSizeHint()), w->minimumSize(), w->maximumSize(), + w->sizePolicy(), align); +} + +Q_GUI_EXPORT QSize qSmartMaxSize(const QWidget *w, Qt::Alignment align) +{ + return qSmartMaxSize(w->sizeHint().expandedTo(w->minimumSizeHint()), w->minimumSize(), w->maximumSize(), + w->sizePolicy(), align); +} + +Q_GUI_EXPORT int qSmartSpacing(const QLayout *layout, QStyle::PixelMetric pm) +{ + QObject *parent = layout->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + QWidget *pw = static_cast(parent); + return pw->style()->pixelMetric(pm, 0, pw); + } else { + return static_cast(parent)->spacing(); + } +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qlayoutengine_p.h b/src/widgets/kernel/qlayoutengine_p.h new file mode 100644 index 0000000000..da07f3bab1 --- /dev/null +++ b/src/widgets/kernel/qlayoutengine_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUTENGINE_P_H +#define QLAYOUTENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qlayoutitem.h" +#include "QtGui/qstyle.h" + +QT_BEGIN_NAMESPACE + +template class QVector; + +struct QLayoutStruct +{ + inline void init(int stretchFactor = 0, int minSize = 0) { + stretch = stretchFactor; + minimumSize = sizeHint = minSize; + maximumSize = QLAYOUTSIZE_MAX; + expansive = false; + empty = true; + spacing = 0; + } + + int smartSizeHint() { + return (stretch > 0) ? minimumSize : sizeHint; + } + int effectiveSpacer(int uniformSpacer) const { + Q_ASSERT(uniformSpacer >= 0 || spacing >= 0); + return (uniformSpacer >= 0) ? uniformSpacer : spacing; + } + + // parameters + int stretch; + int sizeHint; + int maximumSize; + int minimumSize; + bool expansive; + bool empty; + int spacing; + + // temporary storage + bool done; + + // result + int pos; + int size; +}; + + +Q_GUI_EXPORT void qGeomCalc(QVector &chain, int start, int count, + int pos, int space, int spacer = -1); +Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint, + const QSize &minSize, const QSize &maxSize, + const QSizePolicy &sizePolicy); +Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i); +Q_GUI_EXPORT QSize qSmartMinSize(const QWidget *w); +Q_GUI_EXPORT QSize qSmartMaxSize(const QSize &sizeHint, + const QSize &minSize, const QSize &maxSize, + const QSizePolicy &sizePolicy, Qt::Alignment align = 0); +Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align = 0); +Q_GUI_EXPORT QSize qSmartMaxSize(const QWidget *w, Qt::Alignment align = 0); + +Q_GUI_EXPORT int qSmartSpacing(const QLayout *layout, QStyle::PixelMetric pm); + +/* + Modify total maximum (max), total expansion (exp), and total empty + when adding boxmax/boxexp. + + Expansive boxes win over non-expansive boxes. + Non-empty boxes win over empty boxes. +*/ +static inline void qMaxExpCalc(int & max, bool &exp, bool &empty, + int boxmax, bool boxexp, bool boxempty) +{ + if (exp) { + if (boxexp) + max = qMax(max, boxmax); + } else { + if (boxexp || (empty && (!boxempty || max == 0))) + max = boxmax; + else if (empty == boxempty) + max = qMin(max, boxmax); + } + exp = exp || boxexp; + empty = empty && boxempty; +} + +QT_END_NAMESPACE + +#endif // QLAYOUTENGINE_P_H diff --git a/src/widgets/kernel/qlayoutitem.cpp b/src/widgets/kernel/qlayoutitem.cpp new file mode 100644 index 0000000000..aeb96e9ef5 --- /dev/null +++ b/src/widgets/kernel/qlayoutitem.cpp @@ -0,0 +1,834 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayout.h" + +#include "qapplication.h" +#include "qlayoutengine_p.h" +#include "qmenubar.h" +#include "qtoolbar.h" +#include "qevent.h" +#include "qstyle.h" +#include "qvariant.h" +#include "qwidget_p.h" + +QT_BEGIN_NAMESPACE + +inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) +{ + return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin, + -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin); +} + +inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) +{ + return fromLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size(); +} + +inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) +{ + return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin, + priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin); +} + +inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) +{ + return toLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size(); +} + +/*! + Returns a QVariant storing this QSizePolicy. +*/ +QSizePolicy::operator QVariant() const +{ + return QVariant(QVariant::SizePolicy, this); +} + +/*! + \class QLayoutItem + \brief The QLayoutItem class provides an abstract item that a + QLayout manipulates. + + \ingroup geomanagement + + This is used by custom layouts. + + Pure virtual functions are provided to return information about + the layout, including, sizeHint(), minimumSize(), maximumSize() + and expanding(). + + The layout's geometry can be set and retrieved with setGeometry() + and geometry(), and its alignment with setAlignment() and + alignment(). + + isEmpty() returns whether the layout item is empty. If the + concrete item is a QWidget, it can be retrieved using widget(). + Similarly for layout() and spacerItem(). + + Some layouts have width and height interdependencies. These can + be expressed using hasHeightForWidth(), heightForWidth(), and + minimumHeightForWidth(). For more explanation see the \e{Qt + Quarterly} article + \l{http://qt.nokia.com/doc/qq/qq04-height-for-width.html}{Trading + Height for Width}. + + \sa QLayout +*/ + +/*! + \class QSpacerItem + \ingroup geomanagement + \brief The QSpacerItem class provides blank space in a layout. + + Normally, you don't need to use this class directly. Qt's + built-in layout managers provide the following functions for + manipulating empty space in layouts: + + \table + \header \o Class + \o Functions + \row \o QHBoxLayout + \o \l{QBoxLayout::addSpacing()}{addSpacing()}, + \l{QBoxLayout::addStretch()}{addStretch()}, + \l{QBoxLayout::insertSpacing()}{insertSpacing()}, + \l{QBoxLayout::insertStretch()}{insertStretch()} + \row \o QGridLayout + \o \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()}, + \l{QGridLayout::setRowStretch()}{setRowStretch()}, + \l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()}, + \l{QGridLayout::setColumnStretch()}{setColumnStretch()} + \endtable + + \sa QLayout, QWidgetItem, QLayoutItem::spacerItem() +*/ + +/*! + \class QWidgetItem + \ingroup geomanagement + \brief The QWidgetItem class is a layout item that represents a widget. + + Normally, you don't need to use this class directly. Qt's + built-in layout managers provide the following functions for + manipulating widgets in layouts: + + \table + \header \o Class + \o Functions + \row \o QBoxLayout + \o \l{QBoxLayout::addWidget()}{addWidget()}, + \l{QBoxLayout::insertWidget()}{insertWidget()}, + \l{QBoxLayout::setStretchFactor()}{setStretchFactor()} + \row \o QGridLayout + \o \l{QGridLayout::addWidget()}{addWidget()} + \row \o QStackedLayout + \o \l{QStackedLayout::addWidget()}{addWidget()}, + \l{QStackedLayout::insertWidget()}{insertWidget()}, + \l{QStackedLayout::currentWidget()}{currentWidget()}, + \l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()}, + \l{QStackedLayout::widget()}{widget()} + \endtable + + \sa QLayout, QSpacerItem, QLayoutItem::widget() +*/ + +/*! + \fn QLayoutItem::QLayoutItem(Qt::Alignment alignment) + + Constructs a layout item with an \a alignment. + Not all subclasses support alignment. +*/ + +/*! + \fn Qt::Alignment QLayoutItem::alignment() const + + Returns the alignment of this item. +*/ + +/*! + Sets the alignment of this item to \a alignment. + + \bold{Note:} Item alignment is only supported by QLayoutItem subclasses + where it would have a visual effect. Except for QSpacerItem, which provides + blank space for layouts, all public Qt classes that inherit QLayoutItem + support item alignment. +*/ +void QLayoutItem::setAlignment(Qt::Alignment alignment) +{ + align = alignment; +} + +/*! + \fn QSize QLayoutItem::maximumSize() const + + Implemented in subclasses to return the maximum size of this item. +*/ + +/*! + \fn QSize QLayoutItem::minimumSize() const + + Implemented in subclasses to return the minimum size of this item. +*/ + +/*! + \fn QSize QLayoutItem::sizeHint() const + + Implemented in subclasses to return the preferred size of this item. +*/ + +/*! + \fn Qt::Orientations QLayoutItem::expandingDirections() const + + Returns whether this layout item can make use of more space than + sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that + it wants to grow in only one dimension, whereas Qt::Vertical | + Qt::Horizontal means that it wants to grow in both dimensions. +*/ + +/*! + \fn void QLayoutItem::setGeometry(const QRect &r) + + Implemented in subclasses to set this item's geometry to \a r. + + \sa geometry() +*/ + +/*! + \fn QRect QLayoutItem::geometry() const + + Returns the rectangle covered by this layout item. + + \sa setGeometry() +*/ + +/*! + \fn virtual bool QLayoutItem::isEmpty() const + + Implemented in subclasses to return whether this item is empty, + i.e. whether it contains any widgets. +*/ + +/*! + \fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy) + + Constructs a spacer item with preferred width \a w, preferred + height \a h, horizontal size policy \a hPolicy and vertical size + policy \a vPolicy. + + The default values provide a gap that is able to stretch if + nothing else wants the space. +*/ + +/*! + Changes this spacer item to have preferred width \a w, preferred + height \a h, horizontal size policy \a hPolicy and vertical size + policy \a vPolicy. + + The default values provide a gap that is able to stretch if + nothing else wants the space. + + Note that if changeSize() is called after the spacer item has been added + to a layout, it is necessary to invalidate the layout in order for the + spacer item's new size to take effect. + + \sa QSpacerItem::invalidate() +*/ +void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy, + QSizePolicy::Policy vPolicy) +{ + width = w; + height = h; + sizeP = QSizePolicy(hPolicy, vPolicy); +} + +/*! + \fn QWidgetItem::QWidgetItem(QWidget *widget) + + Creates an item containing the given \a widget. +*/ + +/*! + Destroys the QLayoutItem. +*/ +QLayoutItem::~QLayoutItem() +{ +} + +/*! + Invalidates any cached information in this layout item. +*/ +void QLayoutItem::invalidate() +{ +} + +/*! + If this item is a QLayout, it is returned as a QLayout; otherwise + 0 is returned. This function provides type-safe casting. +*/ +QLayout * QLayoutItem::layout() +{ + return 0; +} + +/*! + If this item is a QSpacerItem, it is returned as a QSpacerItem; + otherwise 0 is returned. This function provides type-safe casting. +*/ +QSpacerItem * QLayoutItem::spacerItem() +{ + return 0; +} + +/*! + \reimp +*/ +QLayout * QLayout::layout() +{ + return this; +} + +/*! + Returns a pointer to this object. +*/ +QSpacerItem * QSpacerItem::spacerItem() +{ + return this; +} + +/*! + If this item is a QWidget, it is returned as a QWidget; otherwise + 0 is returned. This function provides type-safe casting. +*/ +QWidget * QLayoutItem::widget() +{ + return 0; +} + +/*! + Returns the widget managed by this item. +*/ +QWidget *QWidgetItem::widget() +{ + return wid; +} + +/*! + Returns true if this layout's preferred height depends on its + width; otherwise returns false. The default implementation returns + false. + + Reimplement this function in layout managers that support height + for width. + + \sa heightForWidth(), QWidget::heightForWidth() +*/ +bool QLayoutItem::hasHeightForWidth() const +{ + return false; +} + +/*! + Returns the minimum height this widget needs for the given width, + \a w. The default implementation simply returns heightForWidth(\a + w). +*/ +int QLayoutItem::minimumHeightForWidth(int w) const +{ + return heightForWidth(w); +} + + +/*! + Returns the preferred height for this layout item, given the width + \a w. + + The default implementation returns -1, indicating that the + preferred height is independent of the width of the item. Using + the function hasHeightForWidth() will typically be much faster + than calling this function and testing for -1. + + Reimplement this function in layout managers that support height + for width. A typical implementation will look like this: + \snippet doc/src/snippets/code/src_gui_kernel_qlayoutitem.cpp 0 + + Caching is strongly recommended; without it layout will take + exponential time. + + \sa hasHeightForWidth() +*/ +int QLayoutItem::heightForWidth(int /* w */) const +{ + return -1; +} + +/*! + Returns the control type(s) for the layout item. For a + QWidgetItem, the control type comes from the widget's size + policy; for a QLayoutItem, the control types is derived from the + layout's contents. + + \sa QSizePolicy::controlType() +*/ +QSizePolicy::ControlTypes QLayoutItem::controlTypes() const +{ + // ### Qt 5: This function should probably be virtual instead + if (const QWidget *widget = const_cast(this)->widget()) { + return widget->sizePolicy().controlType(); + } else if (const QLayout *layout = const_cast(this)->layout()) { + if (layout->count() == 0) + return QSizePolicy::DefaultType; + QSizePolicy::ControlTypes types; + for (int i = layout->count() - 1; i >= 0; --i) + types |= layout->itemAt(i)->controlTypes(); + return types; + } + return QSizePolicy::DefaultType; +} + +/*! + \reimp +*/ +void QSpacerItem::setGeometry(const QRect &r) +{ + rect = r; +} + +/*! + \reimp +*/ +void QWidgetItem::setGeometry(const QRect &rect) +{ + if (isEmpty()) + return; + + QRect r = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? fromLayoutItemRect(wid->d_func(), rect) + : rect; + const QSize widgetRectSurplus = r.size() - rect.size(); + + /* + For historical reasons, this code is done using widget rect + coordinates, not layout item rect coordinates. However, + QWidgetItem's sizeHint(), maximumSize(), and heightForWidth() + all work in terms of layout item rect coordinates, so we have to + add or subtract widgetRectSurplus here and there. The code could + be much simpler if we did everything using layout item rect + coordinates and did the conversion right before the call to + QWidget::setGeometry(). + */ + + QSize s = r.size().boundedTo(maximumSize() + widgetRectSurplus); + int x = r.x(); + int y = r.y(); + if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) { + QSize pref(sizeHint()); + QSizePolicy sp = wid->sizePolicy(); + if (sp.horizontalPolicy() == QSizePolicy::Ignored) + pref.setWidth(wid->sizeHint().expandedTo(wid->minimumSize()).width()); + if (sp.verticalPolicy() == QSizePolicy::Ignored) + pref.setHeight(wid->sizeHint().expandedTo(wid->minimumSize()).height()); + pref += widgetRectSurplus; + if (align & Qt::AlignHorizontal_Mask) + s.setWidth(qMin(s.width(), pref.width())); + if (align & Qt::AlignVertical_Mask) { + if (hasHeightForWidth()) + s.setHeight(qMin(s.height(), + heightForWidth(s.width() - widgetRectSurplus.width()) + + widgetRectSurplus.height())); + else + s.setHeight(qMin(s.height(), pref.height())); + } + } + Qt::Alignment alignHoriz = QStyle::visualAlignment(wid->layoutDirection(), align); + if (alignHoriz & Qt::AlignRight) + x = x + (r.width() - s.width()); + else if (!(alignHoriz & Qt::AlignLeft)) + x = x + (r.width() - s.width()) / 2; + + if (align & Qt::AlignBottom) + y = y + (r.height() - s.height()); + else if (!(align & Qt::AlignTop)) + y = y + (r.height() - s.height()) / 2; + + wid->setGeometry(x, y, s.width(), s.height()); +} + +/*! + \reimp +*/ +QRect QSpacerItem::geometry() const +{ + return rect; +} + +/*! + \reimp +*/ +QRect QWidgetItem::geometry() const +{ + return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? toLayoutItemRect(wid->d_func(), wid->geometry()) + : wid->geometry(); +} + + +/*! + \reimp +*/ +bool QWidgetItem::hasHeightForWidth() const +{ + if (isEmpty()) + return false; + return wid->d_func()->hasHeightForWidth(); +} + +/*! + \reimp +*/ +int QWidgetItem::heightForWidth(int w) const +{ + if (isEmpty()) + return -1; + + w = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? fromLayoutItemSize(wid->d_func(), QSize(w, 0)).width() + : w; + + int hfw; + if (wid->layout()) + hfw = wid->layout()->totalHeightForWidth(w); + else + hfw = wid->heightForWidth(w); + + if (hfw > wid->maximumHeight()) + hfw = wid->maximumHeight(); + if (hfw < wid->minimumHeight()) + hfw = wid->minimumHeight(); + + hfw = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? toLayoutItemSize(wid->d_func(), QSize(0, hfw)).height() + : hfw; + + if (hfw < 0) + hfw = 0; + return hfw; +} + +/*! + \reimp +*/ +Qt::Orientations QSpacerItem::expandingDirections() const +{ + return sizeP.expandingDirections(); +} + +/*! + \reimp +*/ +Qt::Orientations QWidgetItem::expandingDirections() const +{ + if (isEmpty()) + return Qt::Orientations(0); + + Qt::Orientations e = wid->sizePolicy().expandingDirections(); + /* + ### Qt 4.0: + If the layout is expanding, we make the widget expanding, even if + its own size policy isn't expanding. This behavior should be + reconsidered. + */ + if (wid->layout()) { + if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag + && (wid->layout()->expandingDirections() & Qt::Horizontal)) + e |= Qt::Horizontal; + if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag + && (wid->layout()->expandingDirections() & Qt::Vertical)) + e |= Qt::Vertical; + } + + if (align & Qt::AlignHorizontal_Mask) + e &= ~Qt::Horizontal; + if (align & Qt::AlignVertical_Mask) + e &= ~Qt::Vertical; + return e; +} + +/*! + \reimp +*/ +QSize QSpacerItem::minimumSize() const +{ + return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width, + sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height); +} + +/*! + \reimp +*/ +QSize QWidgetItem::minimumSize() const +{ + if (isEmpty()) + return QSize(0, 0); + return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? toLayoutItemSize(wid->d_func(), qSmartMinSize(this)) + : qSmartMinSize(this); +} + +/*! + \reimp +*/ +QSize QSpacerItem::maximumSize() const +{ + return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width, + sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height); +} + +/*! + \reimp +*/ +QSize QWidgetItem::maximumSize() const +{ + if (isEmpty()) { + return QSize(0, 0); + } else { + return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? toLayoutItemSize(wid->d_func(), qSmartMaxSize(this, align)) + : qSmartMaxSize(this, align); + } +} + +/*! + \reimp +*/ +QSize QSpacerItem::sizeHint() const +{ + return QSize(width, height); +} + +/*! + \reimp +*/ +QSize QWidgetItem::sizeHint() const +{ + QSize s(0, 0); + if (!isEmpty()) { + s = wid->sizeHint().expandedTo(wid->minimumSizeHint()); + s = s.boundedTo(wid->maximumSize()) + .expandedTo(wid->minimumSize()); + s = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) + ? toLayoutItemSize(wid->d_func(), s) + : s; + + if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) + s.setWidth(0); + if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) + s.setHeight(0); + } + return s; +} + +/*! + Returns true. +*/ +bool QSpacerItem::isEmpty() const +{ + return true; +} + +/*! + Returns true if the widget is hidden; otherwise returns false. + + \sa QWidget::isHidden() +*/ +bool QWidgetItem::isEmpty() const +{ + return wid->isHidden() || wid->isWindow(); +} + +/*! + \class QWidgetItemV2 + \internal +*/ + +inline bool QWidgetItemV2::useSizeCache() const +{ + return wid->d_func()->widgetItem == this; +} + +void QWidgetItemV2::updateCacheIfNecessary() const +{ + if (q_cachedMinimumSize.width() != Dirty) + return; + + const QSize sizeHint(wid->sizeHint()); + const QSize minimumSizeHint(wid->minimumSizeHint()); + const QSize minimumSize(wid->minimumSize()); + const QSize maximumSize(wid->maximumSize()); + const QSizePolicy sizePolicy(wid->sizePolicy()); + const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint)); + + const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy)); + const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align)); + + const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect); + + q_cachedMinimumSize = useLayoutItemRect + ? toLayoutItemSize(wid->d_func(), smartMinSize) + : smartMinSize; + + q_cachedSizeHint = expandedSizeHint; + q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize) + .expandedTo(minimumSize); + q_cachedSizeHint = useLayoutItemRect + ? toLayoutItemSize(wid->d_func(), q_cachedSizeHint) + : q_cachedSizeHint; + + if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) + q_cachedSizeHint.setWidth(0); + if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) + q_cachedSizeHint.setHeight(0); + + q_cachedMaximumSize = useLayoutItemRect + ? toLayoutItemSize(wid->d_func(), smartMaxSize) + : smartMaxSize; +} + +QWidgetItemV2::QWidgetItemV2(QWidget *widget) + : QWidgetItem(widget), + q_cachedMinimumSize(Dirty, Dirty), + q_cachedSizeHint(Dirty, Dirty), + q_cachedMaximumSize(Dirty, Dirty), + q_firstCachedHfw(0), + q_hfwCacheSize(0), + d(0) +{ + QWidgetPrivate *wd = wid->d_func(); + if (!wd->widgetItem) + wd->widgetItem = this; +} + +QWidgetItemV2::~QWidgetItemV2() +{ + if (wid) { + QWidgetPrivate *wd = wid->d_func(); + if (wd->widgetItem == this) + wd->widgetItem = 0; + } +} + +QSize QWidgetItemV2::sizeHint() const +{ + if (isEmpty()) + return QSize(0, 0); + + if (useSizeCache()) { + updateCacheIfNecessary(); + return q_cachedSizeHint; + } else { + return QWidgetItem::sizeHint(); + } +} + +QSize QWidgetItemV2::minimumSize() const +{ + if (isEmpty()) + return QSize(0, 0); + + if (useSizeCache()) { + updateCacheIfNecessary(); + return q_cachedMinimumSize; + } else { + return QWidgetItem::minimumSize(); + } +} + +QSize QWidgetItemV2::maximumSize() const +{ + if (isEmpty()) + return QSize(0, 0); + + if (useSizeCache()) { + updateCacheIfNecessary(); + return q_cachedMaximumSize; + } else { + return QWidgetItem::maximumSize(); + } +} + +/* + The height-for-width cache is organized as a circular buffer. The entries + + q_hfwCachedHfws[q_firstCachedHfw], + ..., + q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize] + + contain the last cached values. When the cache is full, the first entry to + be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When + values are looked up, we try to move q_firstCachedHfw to point to that new + entry (unless the cache is not full, in which case it would leave the cache + in a broken state), so that the most recently used entry is also the last + to be erased. +*/ + +int QWidgetItemV2::heightForWidth(int width) const +{ + if (isEmpty()) + return -1; + + for (int i = 0; i < q_hfwCacheSize; ++i) { + int offset = q_firstCachedHfw + i; + const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize]; + if (size.width() == width) { + if (q_hfwCacheSize == HfwCacheMaxSize) + q_firstCachedHfw = offset; + return size.height(); + } + } + + if (q_hfwCacheSize < HfwCacheMaxSize) + ++q_hfwCacheSize; + q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize; + + int height = QWidgetItem::heightForWidth(width); + q_cachedHfws[q_firstCachedHfw] = QSize(width, height); + return height; +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qlayoutitem.h b/src/widgets/kernel/qlayoutitem.h new file mode 100644 index 0000000000..a75011f3ff --- /dev/null +++ b/src/widgets/kernel/qlayoutitem.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUTITEM_H +#define QLAYOUTITEM_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +static const int QLAYOUTSIZE_MAX = INT_MAX/256/16; + +class QLayout; +class QLayoutItem; +class QSpacerItem; +class QWidget; +class QSize; + +class Q_GUI_EXPORT QLayoutItem +{ +public: + inline explicit QLayoutItem(Qt::Alignment alignment = 0); + virtual ~QLayoutItem(); + virtual QSize sizeHint() const = 0; + virtual QSize minimumSize() const = 0; + virtual QSize maximumSize() const = 0; + virtual Qt::Orientations expandingDirections() const = 0; + virtual void setGeometry(const QRect&) = 0; + virtual QRect geometry() const = 0; + virtual bool isEmpty() const = 0; + virtual bool hasHeightForWidth() const; + virtual int heightForWidth(int) const; + virtual int minimumHeightForWidth(int) const; + virtual void invalidate(); + + virtual QWidget *widget(); + virtual QLayout *layout(); + virtual QSpacerItem *spacerItem(); + + Qt::Alignment alignment() const { return align; } + void setAlignment(Qt::Alignment a); + QSizePolicy::ControlTypes controlTypes() const; + +protected: + Qt::Alignment align; +}; + +inline QLayoutItem::QLayoutItem(Qt::Alignment aalignment) + : align(aalignment) { } + +class Q_GUI_EXPORT QSpacerItem : public QLayoutItem +{ +public: + QSpacerItem(int w, int h, + QSizePolicy::Policy hData = QSizePolicy::Minimum, + QSizePolicy::Policy vData = QSizePolicy::Minimum) + : width(w), height(h), sizeP(hData, vData) { } + void changeSize(int w, int h, + QSizePolicy::Policy hData = QSizePolicy::Minimum, + QSizePolicy::Policy vData = QSizePolicy::Minimum); + QSize sizeHint() const; + QSize minimumSize() const; + QSize maximumSize() const; + Qt::Orientations expandingDirections() const; + bool isEmpty() const; + void setGeometry(const QRect&); + QRect geometry() const; + QSpacerItem *spacerItem(); + +private: + int width; + int height; + QSizePolicy sizeP; + QRect rect; +}; + +class Q_GUI_EXPORT QWidgetItem : public QLayoutItem +{ + Q_DISABLE_COPY(QWidgetItem) + +public: + explicit QWidgetItem(QWidget *w) : wid(w) { } + QSize sizeHint() const; + QSize minimumSize() const; + QSize maximumSize() const; + Qt::Orientations expandingDirections() const; + bool isEmpty() const; + void setGeometry(const QRect&); + QRect geometry() const; + virtual QWidget *widget(); + + bool hasHeightForWidth() const; + int heightForWidth(int) const; + +protected: + QWidget *wid; +}; + +class Q_GUI_EXPORT QWidgetItemV2 : public QWidgetItem +{ +public: + explicit QWidgetItemV2(QWidget *widget); + ~QWidgetItemV2(); + + QSize sizeHint() const; + QSize minimumSize() const; + QSize maximumSize() const; + int heightForWidth(int width) const; + +private: + enum { Dirty = -123, HfwCacheMaxSize = 3 }; + + inline bool useSizeCache() const; + void updateCacheIfNecessary() const; + inline void invalidateSizeCache() { + q_cachedMinimumSize.setWidth(Dirty); + q_hfwCacheSize = 0; + } + + mutable QSize q_cachedMinimumSize; + mutable QSize q_cachedSizeHint; + mutable QSize q_cachedMaximumSize; + mutable QSize q_cachedHfws[HfwCacheMaxSize]; + mutable short q_firstCachedHfw; + mutable short q_hfwCacheSize; + void *d; + + friend class QWidgetPrivate; + + Q_DISABLE_COPY(QWidgetItemV2) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QLAYOUTITEM_H diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h new file mode 100644 index 0000000000..c0a8cc1f18 --- /dev/null +++ b/src/widgets/kernel/qsizepolicy.h @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIZEPOLICY_H +#define QSIZEPOLICY_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QVariant; + +class Q_GUI_EXPORT QSizePolicy +{ + Q_GADGET + Q_ENUMS(Policy) + +private: + enum SizePolicyMasks { + HSize = 4, + HMask = 0x0f, + VMask = HMask << HSize, + CTShift = 9, + CTSize = 5, + CTMask = ((0x1 << CTSize) - 1) << CTShift, + WFHShift = CTShift + CTSize, + UnusedShift = WFHShift + 1, + UnusedSize = 1 + }; + +public: + enum PolicyFlag { + GrowFlag = 1, + ExpandFlag = 2, + ShrinkFlag = 4, + IgnoreFlag = 8 + }; + + enum Policy { + Fixed = 0, + Minimum = GrowFlag, + Maximum = ShrinkFlag, + Preferred = GrowFlag | ShrinkFlag, + MinimumExpanding = GrowFlag | ExpandFlag, + Expanding = GrowFlag | ShrinkFlag | ExpandFlag, + Ignored = ShrinkFlag | GrowFlag | IgnoreFlag + }; + + enum ControlType { + DefaultType = 0x00000001, + ButtonBox = 0x00000002, + CheckBox = 0x00000004, + ComboBox = 0x00000008, + Frame = 0x00000010, + GroupBox = 0x00000020, + Label = 0x00000040, + Line = 0x00000080, + LineEdit = 0x00000100, + PushButton = 0x00000200, + RadioButton = 0x00000400, + Slider = 0x00000800, + SpinBox = 0x00001000, + TabWidget = 0x00002000, + ToolButton = 0x00004000 + }; + Q_DECLARE_FLAGS(ControlTypes, ControlType) + + QSizePolicy() : data(0) { } + + // ### Qt 5: merge these two constructors (with type == DefaultType) + QSizePolicy(Policy horizontal, Policy vertical) + : data(horizontal | (vertical << HSize)) { } + QSizePolicy(Policy horizontal, Policy vertical, ControlType type) + : data(horizontal | (vertical << HSize)) { setControlType(type); } + + Policy horizontalPolicy() const { return static_cast(data & HMask); } + Policy verticalPolicy() const { return static_cast((data & VMask) >> HSize); } + ControlType controlType() const; + + void setHorizontalPolicy(Policy d) { data = (data & ~HMask) | d; } + void setVerticalPolicy(Policy d) { data = (data & ~(HMask << HSize)) | (d << HSize); } + void setControlType(ControlType type); + + Qt::Orientations expandingDirections() const { + Qt::Orientations result; + if (verticalPolicy() & ExpandFlag) + result |= Qt::Vertical; + if (horizontalPolicy() & ExpandFlag) + result |= Qt::Horizontal; + return result; + } + + void setHeightForWidth(bool b) { data = b ? (data | (1 << 2*HSize)) : (data & ~(1 << 2*HSize)); } + bool hasHeightForWidth() const { return data & (1 << 2*HSize); } + void setWidthForHeight(bool b) { data = b ? (data | (1 << (WFHShift))) : (data & ~(1 << (WFHShift))); } + bool hasWidthForHeight() const { return data & (1 << (WFHShift)); } + + bool operator==(const QSizePolicy& s) const { return data == s.data; } + bool operator!=(const QSizePolicy& s) const { return data != s.data; } + operator QVariant() const; // implemented in qabstractlayout.cpp + + int horizontalStretch() const { return data >> 24; } + int verticalStretch() const { return (data >> 16) & 0xff; } + void setHorizontalStretch(uchar stretchFactor) { data = (data&0x00ffffff) | (uint(stretchFactor)<<24); } + void setVerticalStretch(uchar stretchFactor) { data = (data&0xff00ffff) | (uint(stretchFactor)<<16); } + + void transpose(); + +#ifdef QT3_SUPPORT + typedef Policy SizeType; +#ifndef qdoc + typedef Qt::Orientations ExpandData; + enum { + NoDirection = 0, + Horizontally = 1, + Vertically = 2, + BothDirections = Horizontally | Vertically + }; +#else + enum ExpandData { + NoDirection = 0x0, + Horizontally = 0x1, + Vertically = 0x2, + BothDirections = 0x3 + }; +#endif // qdoc + + inline QT3_SUPPORT bool mayShrinkHorizontally() const + { return horizontalPolicy() & ShrinkFlag; } + inline QT3_SUPPORT bool mayShrinkVertically() const { return verticalPolicy() & ShrinkFlag; } + inline QT3_SUPPORT bool mayGrowHorizontally() const { return horizontalPolicy() & GrowFlag; } + inline QT3_SUPPORT bool mayGrowVertically() const { return verticalPolicy() & GrowFlag; } + inline QT3_SUPPORT Qt::Orientations expanding() const { return expandingDirections(); } + + QT3_SUPPORT_CONSTRUCTOR QSizePolicy(Policy hor, Policy ver, bool hfw) + : data(hor | (ver<(data & HMask); } + inline QT3_SUPPORT Policy verData() const { return static_cast((data & VMask) >> HSize); } + inline QT3_SUPPORT void setHorData(Policy d) { setHorizontalPolicy(d); } + inline QT3_SUPPORT void setVerData(Policy d) { setVerticalPolicy(d); } + + inline QT3_SUPPORT uint horStretch() const { return horizontalStretch(); } + inline QT3_SUPPORT uint verStretch() const { return verticalStretch(); } + inline QT3_SUPPORT void setHorStretch(uchar sf) { setHorizontalStretch(sf); } + inline QT3_SUPPORT void setVerStretch(uchar sf) { setVerticalStretch(sf); } +#endif + +private: +#ifndef QT_NO_DATASTREAM + friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &); + friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &); +#endif + QSizePolicy(int i) : data(i) { } + + quint32 data; +/* Qt5: Use bit flags instead, keep it here for improved readability for now. + We can maybe change it for Qt4, but we'd have to be careful, since the behaviour + is implementation defined. It usually varies between little- and big-endian compilers, but + it might also not vary. + quint32 horzPolicy : 4; + quint32 vertPolicy : 4; + quint32 hfw : 1; + quint32 ctype : 5; + quint32 wfh : 1; + quint32 padding : 1; // we cannot use the highest bit + quint32 verStretch : 8; + quint32 horStretch : 8; +*/ + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes) + +#ifndef QT_NO_DATASTREAM +// implemented in qlayout.cpp +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &); +#endif + +inline void QSizePolicy::transpose() { + Policy hData = horizontalPolicy(); + Policy vData = verticalPolicy(); + uchar hStretch = uchar(horizontalStretch()); + uchar vStretch = uchar(verticalStretch()); + setHorizontalPolicy(vData); + setVerticalPolicy(hData); + setHorizontalStretch(vStretch); + setVerticalStretch(hStretch); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSIZEPOLICY_H diff --git a/src/widgets/kernel/qsizepolicy.qdoc b/src/widgets/kernel/qsizepolicy.qdoc new file mode 100644 index 0000000000..80e9f20f74 --- /dev/null +++ b/src/widgets/kernel/qsizepolicy.qdoc @@ -0,0 +1,529 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QSizePolicy + \brief The QSizePolicy class is a layout attribute describing horizontal + and vertical resizing policy. + + \ingroup geomanagement + + The size policy of a widget is an expression of its willingness to + be resized in various ways, and affects how the widget is treated + by the \l{Layout Management}{layout engine}. Each widget returns a + QSizePolicy that describes the horizontal and vertical resizing + policy it prefers when being laid out. You can change this for + a specific widget by changing its QWidget::sizePolicy property. + + QSizePolicy contains two independent QSizePolicy::Policy values + and two stretch factors; one describes the widgets's horizontal + size policy, and the other describes its vertical size policy. It + also contains a flag to indicate whether the height and width of + its preferred size are related. + + The horizontal and vertical policies can be set in the + constructor, and altered using the setHorizontalPolicy() and + setVerticalPolicy() functions. The stretch factors can be set + using the setHorizontalStretch() and setVerticalStretch() + functions. The flag indicating whether the widget's + \l{QWidget::sizeHint()}{sizeHint()} is width-dependent (such as a + menu bar or a word-wrapping label) can be set using the + setHeightForWidth() function. + + The current size policies and stretch factors be retrieved using + the horizontalPolicy(), verticalPolicy(), horizontalStretch() and + verticalStretch() functions. Alternatively, use the transpose() + function to swap the horizontal and vertical policies and + stretches. The hasHeightForWidth() function returns the current + status of the flag indicating the size hint dependencies. + + Use the expandingDirections() function to determine whether the + associated widget can make use of more space than its + \l{QWidget::sizeHint()}{sizeHint()} function indicates, as well as + find out in which directions it can expand. + + Finally, the QSizePolicy class provides operators comparing this + size policy to a given policy, as well as a QVariant operator + storing this QSizePolicy as a QVariant object. + + \sa QSize, QWidget::sizeHint(), QWidget::sizePolicy, + QLayoutItem::sizeHint() +*/ + +/*! + \enum QSizePolicy::PolicyFlag + + These flags are combined together to form the various \l{Policy} + values: + + \value GrowFlag The widget can grow beyond its size hint if necessary. + \value ExpandFlag The widget should get as much space as possible. + \value ShrinkFlag The widget can shrink below its size hint if necessary. + \value IgnoreFlag The widget's size hint is ignored. The widget will get + as much space as possible. + + \sa Policy +*/ + +/*! + \enum QSizePolicy::Policy + + This enum describes the various per-dimension sizing types used + when constructing a QSizePolicy. + + \value Fixed The QWidget::sizeHint() is the only acceptable + alternative, so the widget can never grow or shrink (e.g. the + vertical direction of a push button). + + \value Minimum The sizeHint() is minimal, and sufficient. The + widget can be expanded, but there is no advantage to it being + larger (e.g. the horizontal direction of a push button). + It cannot be smaller than the size provided by sizeHint(). + + \value Maximum The sizeHint() is a maximum. The widget can be + shrunk any amount without detriment if other widgets need the + space (e.g. a separator line). + It cannot be larger than the size provided by sizeHint(). + + \value Preferred The sizeHint() is best, but the widget can be + shrunk and still be useful. The widget can be expanded, but there + is no advantage to it being larger than sizeHint() (the default + QWidget policy). + + \value Expanding The sizeHint() is a sensible size, but the + widget can be shrunk and still be useful. The widget can make use + of extra space, so it should get as much space as possible (e.g. + the horizontal direction of a horizontal slider). + + \value MinimumExpanding The sizeHint() is minimal, and sufficient. + The widget can make use of extra space, so it should get as much + space as possible (e.g. the horizontal direction of a horizontal + slider). + + \value Ignored The sizeHint() is ignored. The widget will get as + much space as possible. + + \sa PolicyFlag, setHorizontalPolicy(), setVerticalPolicy() +*/ + +/*! + \fn QSizePolicy::QSizePolicy() + + Constructs a QSizePolicy object with \l Fixed as its horizontal + and vertical policies. + + The policies can be altered using the setHorizontalPolicy() and + setVerticalPolicy() functions. Use the setHeightForWidth() + function if the preferred height of the widget is dependent on the + width of the widget (for example, a QLabel with line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch() +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical) + + Constructs a QSizePolicy object with the given \a horizontal and + \a vertical policies, and DefaultType as the control type. + + Use setHeightForWidth() if the preferred height of the widget is + dependent on the width of the widget (for example, a QLabel with + line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch() +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, ControlType type) + \since 4.3 + + Constructs a QSizePolicy object with the given \a horizontal and + \a vertical policies, and the specified control \a type. + + Use setHeightForWidth() if the preferred height of the widget is + dependent on the width of the widget (for example, a QLabel with + line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch(), controlType() +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::horizontalPolicy() const + + Returns the horizontal component of the size policy. + + \sa setHorizontalPolicy(), verticalPolicy(), horizontalStretch() +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::verticalPolicy() const + + Returns the vertical component of the size policy. + + \sa setVerticalPolicy(), horizontalPolicy(), verticalStretch() +*/ + +/*! + \fn void QSizePolicy::setHorizontalPolicy(Policy policy) + + Sets the horizontal component to the given \a policy. + + \sa horizontalPolicy(), setVerticalPolicy(), setHorizontalStretch() +*/ + +/*! + \fn void QSizePolicy::setVerticalPolicy(Policy policy) + + Sets the vertical component to the given \a policy. + + \sa verticalPolicy(), setHorizontalPolicy(), setVerticalStretch() +*/ + +/*! + \fn Qt::Orientations QSizePolicy::expandingDirections() const + + Returns whether a widget can make use of more space than the + QWidget::sizeHint() function indicates. + + A value of Qt::Horizontal or Qt::Vertical means that the widget + can grow horizontally or vertically (i.e., the horizontal or + vertical policy is \l Expanding or \l MinimumExpanding), whereas + Qt::Horizontal | Qt::Vertical means that it can grow in both + dimensions. + + \sa horizontalPolicy(), verticalPolicy() +*/ + +/*! + \fn ControlType QSizePolicy::controlType() const + \since 4.3 + + Returns the control type associated with the widget for which + this size policy applies. +*/ + +/*! + \fn void QSizePolicy::setControlType(ControlType type) + \since 4.3 + + Sets the control type associated with the widget for which this + size policy applies to \a type. + + The control type specifies the type of the widget for which this + size policy applies. It is used by some styles, notably + QMacStyle, to insert proper spacing between widgets. For example, + the Mac OS X Aqua guidelines specify that push buttons should be + separated by 12 pixels, whereas vertically stacked radio buttons + only require 6 pixels. + + \sa QStyle::layoutSpacing() +*/ + +/*! + \fn void QSizePolicy::setHeightForWidth(bool dependent) + + Sets the flag determining whether the widget's preferred height + depends on its width, to \a dependent. + + \sa hasHeightForWidth(), setWidthForHeight() +*/ + +/*! + \fn bool QSizePolicy::hasHeightForWidth() const + + Returns true if the widget's preferred height depends on its + width; otherwise returns false. + + \sa setHeightForWidth() +*/ + +/*! + \fn void QSizePolicy::setWidthForHeight(bool dependent) + + Sets the flag determining whether the widget's width + depends on its height, to \a dependent. + + This is only supported for QGraphicsLayout's subclasses. + It is not possible to have a layout with both height-for-width + and width-for-height constraints at the same time. + + \sa hasWidthForHeight(), setHeightForWidth() +*/ + +/*! + \fn bool QSizePolicy::hasWidthForHeight() const + + Returns true if the widget's width depends on its + height; otherwise returns false. + + \sa setWidthForHeight() +*/ + +/*! + \fn bool QSizePolicy::operator==(const QSizePolicy &other) const + + Returns true if this policy is equal to \a other; otherwise + returns false. + + \sa operator!=() +*/ + +/*! + \fn bool QSizePolicy::operator!=(const QSizePolicy &other) const + + Returns true if this policy is different from \a other; otherwise + returns false. + + \sa operator==() +*/ + +/*! + \fn int QSizePolicy::horizontalStretch() const + + Returns the horizontal stretch factor of the size policy. + + \sa setHorizontalStretch(), verticalStretch(), horizontalPolicy() +*/ + +/*! + \fn int QSizePolicy::verticalStretch() const + + Returns the vertical stretch factor of the size policy. + + \sa setVerticalStretch(), horizontalStretch(), verticalPolicy() +*/ + +/*! + \fn void QSizePolicy::setHorizontalStretch(uchar stretchFactor) + + Sets the horizontal stretch factor of the size policy to the given \a + stretchFactor. + + \sa horizontalStretch(), setVerticalStretch(), setHorizontalPolicy() +*/ + +/*! + \fn void QSizePolicy::setVerticalStretch(uchar stretchFactor) + + Sets the vertical stretch factor of the size policy to the given + \a stretchFactor. + + \sa verticalStretch(), setHorizontalStretch(), setVerticalPolicy() +*/ + +/*! + \fn void QSizePolicy::transpose() + + Swaps the horizontal and vertical policies and stretches. +*/ + +/*! + \enum QSizePolicy::ControlType + \since 4.3 + + This enum specifies the different types of widgets in terms of + layout interaction: + + \value DefaultType The default type, when none is specified. + \value ButtonBox A QDialogButtonBox instance. + \value CheckBox A QCheckBox instance. + \value ComboBox A QComboBox instance. + \value Frame A QFrame instance. + \value GroupBox A QGroupBox instance. + \value Label A QLabel instance. + \value Line A QFrame instance with QFrame::HLine or QFrame::VLine. + \value LineEdit A QLineEdit instance. + \value PushButton A QPushButton instance. + \value RadioButton A QRadioButton instance. + \value Slider A QAbstractSlider instance. + \value SpinBox A QAbstractSpinBox instance. + \value TabWidget A QTabWidget instance. + \value ToolButton A QToolButton instance. + + \sa setControlType(), controlType() +*/ + +#ifdef QT3_SUPPORT +/*! + \typedef QSizePolicy::SizeType + \compat + + Use the QSizePolicy::Policy enum instead. +*/ + +/*! + \enum QSizePolicy::ExpandData + \compat + + Use the Qt::Orientations enum instead. + + \value NoDirection Use 0 instead. + \value Horizontally Use Qt::Horizontal instead. + \value Vertically Use Qt::Vertical instead. + \value BothDirections Use Qt::Horizontal | Qt::Vertical instead. +*/ + +/*! + \fn bool QSizePolicy::mayShrinkHorizontally() const + + Use the horizontalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayShrinkHorizontally(); + \newcode + bool policy = horizontalPolicy() & QSizePolicy::ShrinkFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayShrinkVertically() const + + Use the verticalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayShrinkVertically(); + \newcode + bool policy = verticalPolicy() & QSizePolicy::ShrinkFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayGrowHorizontally() const + + Use the horizontalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayGrowHorizontally(); + \newcode + bool policy = horizontalPolicy() & QSizePolicy::GrowFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayGrowVertically() const + + Use the verticalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayGrowVertically(); + \newcode + bool policy = verticalPolicy() & QSizePolicy::GrowFlag; + \endcode +*/ + +/*! + \fn Qt::QSizePolicy::Orientations QSizePolicy::expanding() const + + Use expandingDirections() instead. +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, bool dependent) + + Use the QSizePolicy() constructor and the setHeightForWidth() + function instead. + + \oldcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical, dependent); + \newcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical); + policy->setHeightForWidth(dependent); + \endcode +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, uchar horizontalStretch, + uchar verticalStretch, bool dependent) + + Use the QSizePolicy() constructor and call the + setHorizontalStretch(), setVerticalStretch(), and + setHeightForWidth() functions instead. + + \oldcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical, + horizontalStretch, verticalStretch, + dependent); + \newcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical); + policy->setHorizontalStretch(horizontalStretch); + policy->setVerticalStretch(verticalStretch); + policy->setHeightForWidth(dependent); + \endcode +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::horData() const + + Use horizontalPolicy() instead. +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::verData() const + + Use verticalPolicy() instead. +*/ + +/*! + \fn void QSizePolicy::setHorData(Policy policy) + + Use setHorizontalPolicy() instead. +*/ + +/*! + \fn void QSizePolicy::setVerData(Policy policy) + + Use setVerticalPolicy() instead. +*/ + +/*! + \fn uint QSizePolicy::horStretch() const + + Use horizontalStretch() instead. +*/ + +/*! + \fn uint QSizePolicy::verStretch() const + + Use verticalStretch() instead. +*/ + +/*! + \fn void QSizePolicy::setHorStretch(uchar stretch) + + Use setHorizontalStretch() instead. +*/ + +/*! + \fn void QSizePolicy::setVerStretch(uchar stretch) + + Use setVerticalStretch() instead. +*/ +#endif diff --git a/src/widgets/kernel/qsoftkeymanager.cpp b/src/widgets/kernel/qsoftkeymanager.cpp new file mode 100644 index 0000000000..204efe9ee9 --- /dev/null +++ b/src/widgets/kernel/qsoftkeymanager.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qevent.h" +#include "qbitmap.h" +#include "private/qsoftkeymanager_p.h" +#include "private/qaction_p.h" +#include "private/qsoftkeymanager_common_p.h" + +#ifdef Q_WS_S60 +#include "private/qsoftkeymanager_s60_p.h" +#endif + +#ifdef SYMBIAN_VERSION_SYMBIAN3 +#include "private/qt_s60_p.h" +#endif + +#ifndef QT_NO_SOFTKEYMANAGER +QT_BEGIN_NAMESPACE + +QSoftKeyManager *QSoftKeyManagerPrivate::self = 0; + +QString QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) +{ + QString softKeyText; + switch (standardKey) { + case OkSoftKey: + softKeyText = QSoftKeyManager::tr("Ok"); + break; + case SelectSoftKey: + softKeyText = QSoftKeyManager::tr("Select"); + break; + case DoneSoftKey: + softKeyText = QSoftKeyManager::tr("Done"); + break; + case MenuSoftKey: + softKeyText = QSoftKeyManager::tr("Options"); + break; + case CancelSoftKey: + softKeyText = QSoftKeyManager::tr("Cancel"); + break; + default: + break; + }; + + return softKeyText; +} + +QSoftKeyManager *QSoftKeyManager::instance() +{ + if (!QSoftKeyManagerPrivate::self) + QSoftKeyManagerPrivate::self = new QSoftKeyManager; + + return QSoftKeyManagerPrivate::self; +} + +QSoftKeyManager::QSoftKeyManager() : +#ifdef Q_WS_S60 + QObject(*(new QSoftKeyManagerPrivateS60), 0) +#else + QObject(*(new QSoftKeyManagerPrivate), 0) +#endif +{ +} + +QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) +{ + QAction *action = new QAction(standardSoftKeyText(standardKey), actionWidget); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + int key = 0; + switch (standardKey) { + case OkSoftKey: + key = EAknSoftkeyOk; + break; + case SelectSoftKey: + key = EAknSoftkeySelect; + break; + case DoneSoftKey: + key = EAknSoftkeyDone; + break; + case MenuSoftKey: + key = EAknSoftkeyOptions; + break; + case CancelSoftKey: + key = EAknSoftkeyCancel; + break; + default: + break; + }; + if (key != 0) + QSoftKeyManager::instance()->d_func()->softKeyCommandActions.insert(action, key); +#endif + QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; + switch (standardKey) { + case MenuSoftKey: // FALL-THROUGH + QActionPrivate::get(action)->menuActionSoftkeys = true; + case OkSoftKey: + case SelectSoftKey: + case DoneSoftKey: + softKeyRole = QAction::PositiveSoftKey; + break; + case CancelSoftKey: + softKeyRole = QAction::NegativeSoftKey; + break; + } + action->setSoftKeyRole(softKeyRole); + action->setVisible(false); + setForceEnabledInSoftkeys(action); + return action; +} + +/*! \internal + + Creates a QAction and registers the 'triggered' signal to send the given key event to + \a actionWidget as a convenience. + +*/ +QAction *QSoftKeyManager::createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget) +{ +#ifndef QT_NO_ACTION + QScopedPointer action(createAction(standardKey, actionWidget)); + + connect(action.data(), SIGNAL(triggered()), QSoftKeyManager::instance(), SLOT(sendKeyEvent())); + connect(action.data(), SIGNAL(destroyed(QObject*)), QSoftKeyManager::instance(), SLOT(cleanupHash(QObject*))); + QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key); + return action.take(); +#endif //QT_NO_ACTION +} + +void QSoftKeyManager::cleanupHash(QObject *obj) +{ + Q_D(QSoftKeyManager); + QAction *action = qobject_cast(obj); + d->keyedActions.remove(action); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + d->softKeyCommandActions.remove(action); +#endif +} + +void QSoftKeyManager::sendKeyEvent() +{ + Q_D(QSoftKeyManager); + QAction *action = qobject_cast(sender()); + + if (!action) + return; + + Qt::Key keyToSend = d->keyedActions.value(action, Qt::Key_unknown); + + if (keyToSend != Qt::Key_unknown) + QApplication::postEvent(action->parentWidget(), + new QKeyEvent(QEvent::KeyPress, keyToSend, Qt::NoModifier)); +} + +void QSoftKeyManager::updateSoftKeys() +{ + QSoftKeyManager::instance()->d_func()->pendingUpdate = true; + QEvent *event = new QEvent(QEvent::UpdateSoftKeys); + QApplication::postEvent(QSoftKeyManager::instance(), event); +} + +bool QSoftKeyManager::appendSoftkeys(const QWidget &source, int level) +{ + Q_D(QSoftKeyManager); + bool ret = false; + foreach(QAction *action, source.actions()) { + if (action->softKeyRole() != QAction::NoSoftKey + && (action->isVisible() || isForceEnabledInSofkeys(action))) { + d->requestedSoftKeyActions.insert(level, action); + ret = true; + } + } + return ret; +} + + +static bool isChildOf(const QWidget *c, const QWidget *p) +{ + while (c) { + if (c == p) + return true; + c = c->parentWidget(); + } + return false; +} + +QWidget *QSoftKeyManager::softkeySource(QWidget *previousSource, bool& recursiveMerging) +{ + Q_D(QSoftKeyManager); + QWidget *source = NULL; + if (!previousSource) { + // Initial source is primarily focuswidget and secondarily activeWindow + QWidget *focus = QApplication::focusWidget(); + QWidget *popup = QApplication::activePopupWidget(); + if (popup) { + if (isChildOf(focus, popup)) + source = focus; + else + source = popup; + } + if (!source) { + QWidget *modal = QApplication::activeModalWidget(); + if (modal) { + if (isChildOf(focus, modal)) + source = focus; + else + source = modal; + } + } + if (!source) { + source = focus; + if (!source) + source = QApplication::activeWindow(); + } + } else { + // Softkey merging is based on four criterias + // 1. Implicit merging is used whenever focus widget does not specify any softkeys + bool implicitMerging = d->requestedSoftKeyActions.isEmpty(); + // 2. Explicit merging with parent is used whenever WA_MergeSoftkeys widget attribute is set + bool explicitMerging = previousSource->testAttribute(Qt::WA_MergeSoftkeys); + // 3. Explicit merging with all parents + recursiveMerging |= previousSource->testAttribute(Qt::WA_MergeSoftkeysRecursively); + // 4. Implicit and explicit merging always stops at window boundary + bool merging = (implicitMerging || explicitMerging || recursiveMerging) && !previousSource->isWindow(); + + source = merging ? previousSource->parentWidget() : NULL; + } + return source; +} + +bool QSoftKeyManager::handleUpdateSoftKeys() +{ + Q_D(QSoftKeyManager); + int level = 0; + d->requestedSoftKeyActions.clear(); + bool recursiveMerging = false; + QWidget *source = softkeySource(NULL, recursiveMerging); + d->initialSoftKeySource = source; + while (source) { + if (appendSoftkeys(*source, level)) + ++level; + source = softkeySource(source, recursiveMerging); + } + + d->updateSoftKeys_sys(); + d->pendingUpdate = false; + return true; +} + +void QSoftKeyManager::setForceEnabledInSoftkeys(QAction *action) +{ + QActionPrivate::get(action)->forceEnabledInSoftkeys = true; +} + +bool QSoftKeyManager::isForceEnabledInSofkeys(QAction *action) +{ + return QActionPrivate::get(action)->forceEnabledInSoftkeys; +} + +bool QSoftKeyManager::event(QEvent *e) +{ +#ifndef QT_NO_ACTION + if (e->type() == QEvent::UpdateSoftKeys) + return handleUpdateSoftKeys(); +#endif //QT_NO_ACTION + return false; +} + +#ifdef Q_WS_S60 +bool QSoftKeyManager::handleCommand(int command) +{ + if (QSoftKeyManager::instance()->d_func()->pendingUpdate) + (void)QSoftKeyManager::instance()->handleUpdateSoftKeys(); + + return static_cast(QSoftKeyManager::instance()->d_func())->handleCommand(command); +} +#endif + +QT_END_NAMESPACE +#endif //QT_NO_SOFTKEYMANAGER diff --git a/src/widgets/kernel/qsoftkeymanager_common_p.h b/src/widgets/kernel/qsoftkeymanager_common_p.h new file mode 100644 index 0000000000..02ae697eef --- /dev/null +++ b/src/widgets/kernel/qsoftkeymanager_common_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOFTKEYMANAGER_COMMON_P_H +#define QSOFTKEYMANAGER_COMMON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +#ifndef QT_NO_SOFTKEYMANAGER + +QT_BEGIN_NAMESPACE + +class QSoftKeyManagerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSoftKeyManager) + +public: + virtual void updateSoftKeys_sys() {}; + +protected: + static QSoftKeyManager *self; + QHash keyedActions; + QMultiHash requestedSoftKeyActions; + QWidget *initialSoftKeySource; + bool pendingUpdate; +#ifdef SYMBIAN_VERSION_SYMBIAN3 + QHash softKeyCommandActions; +#endif +}; + +QT_END_NAMESPACE + +#endif //QT_NO_SOFTKEYMANAGER + +QT_END_HEADER + +#endif // QSOFTKEYMANAGER_COMMON_P_H diff --git a/src/widgets/kernel/qsoftkeymanager_p.h b/src/widgets/kernel/qsoftkeymanager_p.h new file mode 100644 index 0000000000..78999a97bd --- /dev/null +++ b/src/widgets/kernel/qsoftkeymanager_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOFTKEYMANAGER_P_H +#define QSOFTKEYMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "QtGui/qaction.h" + +QT_BEGIN_HEADER + +#ifndef QT_NO_SOFTKEYMANAGER +QT_BEGIN_NAMESPACE + +class QSoftKeyManagerPrivate; + +class Q_AUTOTEST_EXPORT QSoftKeyManager : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSoftKeyManager) + +public: + + enum StandardSoftKey { + OkSoftKey, + SelectSoftKey, + DoneSoftKey, + MenuSoftKey, + CancelSoftKey + }; + + static void updateSoftKeys(); +#ifdef Q_WS_S60 + static bool handleCommand(int); +#endif + + static QAction *createAction(StandardSoftKey standardKey, QWidget *actionWidget); + static QAction *createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget); + static QString standardSoftKeyText(StandardSoftKey standardKey); + static void setForceEnabledInSoftkeys(QAction *action); + static bool isForceEnabledInSofkeys(QAction *action); + +protected: + bool event(QEvent *e); + +private: + QSoftKeyManager(); + static QSoftKeyManager *instance(); + bool appendSoftkeys(const QWidget &source, int level); + QWidget *softkeySource(QWidget *previousSource, bool& recursiveMerging); + bool handleUpdateSoftKeys(); + +private Q_SLOTS: + void cleanupHash(QObject* obj); + void sendKeyEvent(); + +private: + Q_DISABLE_COPY(QSoftKeyManager) +}; + +QT_END_NAMESPACE +#endif //QT_NO_SOFTKEYMANAGER + +QT_END_HEADER + +#endif //QSOFTKEYMANAGER_P_H diff --git a/src/widgets/kernel/qsound.cpp b/src/widgets/kernel/qsound.cpp new file mode 100644 index 0000000000..55a98758c3 --- /dev/null +++ b/src/widgets/kernel/qsound.cpp @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsound.h" + +#ifndef QT_NO_SOUND + +#include "qlist.h" +#include +#include "qsound_p.h" + +QT_BEGIN_NAMESPACE + +static QList *servers=0; + +QAuServer::QAuServer(QObject* parent) + : QObject(parent) +{ + if (!servers) + servers = new QList; + servers->prepend(this); +} + +QAuServer::~QAuServer() +{ + servers->removeAll(this); + if (servers->count() == 0) { + delete servers; + servers = 0; + } +} + +void QAuServer::play(const QString& filename) +{ + QSound s(filename); + play(&s); +} + +extern QAuServer* qt_new_audio_server(); + +static QAuServer& server() +{ + if (!servers) qt_new_audio_server(); + return *servers->first(); +} + +class QSoundPrivate : public QObjectPrivate +{ +public: + QSoundPrivate(const QString& fname) + : filename(fname), bucket(0), looprem(0), looptotal(1) + { + } + + ~QSoundPrivate() + { + delete bucket; + } + + QString filename; + QAuBucket* bucket; + int looprem; + int looptotal; +}; + +/*! + \class QSound + \brief The QSound class provides access to the platform audio facilities. + + \ingroup multimedia + + + Qt provides the most commonly required audio operation in GUI + applications: asynchronously playing a sound file. This is most + easily accomplished using the static play() function: + + \snippet doc/src/snippets/code/src_gui_kernel_qsound.cpp 0 + + Alternatively, create a QSound object from the sound file first + and then call the play() slot: + + \snippet doc/src/snippets/code/src_gui_kernel_qsound.cpp 1 + + Once created a QSound object can be queried for its fileName() and + total number of loops() (i.e. the number of times the sound will + play). The number of repetitions can be altered using the + setLoops() function. While playing the sound, the loopsRemaining() + function returns the remaining number of repetitions. Use the + isFinished() function to determine whether the sound has finished + playing. + + Sounds played using a QSound object may use more memory than the + static play() function, but it may also play more immediately + (depending on the underlying platform audio facilities). Use the + static isAvailable() function to determine whether sound + facilities exist on the platform. Which facilities that are + actually used varies: + + \table + \header \o Platform \o Audio Facility + \row + \o Microsoft Windows + \o The underlying multimedia system is used; only WAVE format sound files + are supported. + \row + \o X11 + \o The \l{ftp://ftp.x.org/contrib/audio/nas/}{Network Audio System} + is used if available, otherwise all operations work silently. NAS + supports WAVE and AU files. + \row + \o Mac OS X + \o NSSound is used. All formats that NSSound supports, including QuickTime formats, + are supported by Qt for Mac OS X. + \row + \o Qt for Embedded Linux + \o A built-in mixing sound server is used, accessing \c /dev/dsp + directly. Only the WAVE format is supported. + \row + \o Symbian + \o CMdaAudioPlayerUtility is used. All formats that Symbian OS or devices support + are supported also by Qt. + \endtable + + Note that QSound does not support \l{resources.html}{resources}. + This might be fixed in a future Qt version. +*/ + +/*! + Plays the sound stored in the file specified by the given \a filename. + + \sa stop(), loopsRemaining(), isFinished() +*/ +void QSound::play(const QString& filename) +{ + server().play(filename); +} + +/*! + Constructs a QSound object from the file specified by the given \a + filename and with the given \a parent. + + This may use more memory than the static play() function, but it + may also play more immediately (depending on the underlying + platform audio facilities). + + \sa play() +*/ +QSound::QSound(const QString& filename, QObject* parent) + : QObject(*new QSoundPrivate(filename), parent) +{ + server().init(this); +} + +/*! + Destroys this sound object. If the sound is not finished playing, + the stop() function is called before the sound object is + destructed. + + \sa stop(), isFinished() +*/ +QSound::~QSound() +{ + if (!isFinished()) + stop(); +} + +/*! + Returns true if the sound has finished playing; otherwise returns false. + + \warning On Windows this function always returns true for unlooped sounds. +*/ +bool QSound::isFinished() const +{ + Q_D(const QSound); + return d->looprem == 0; +} + +/*! + \overload + + Starts playing the sound specified by this QSound object. + + The function returns immediately. Depending on the platform audio + facilities, other sounds may stop or be mixed with the new + sound. The sound can be played again at any time, possibly mixing + or replacing previous plays of the sound. + + \sa fileName() +*/ +void QSound::play() +{ + Q_D(QSound); + d->looprem = d->looptotal; + server().play(this); +} + +/*! + Returns the number of times the sound will play. + + \sa loopsRemaining(), setLoops() +*/ +int QSound::loops() const +{ + Q_D(const QSound); + return d->looptotal; +} + +/*! + Returns the remaining number of times the sound will loop (this + value decreases each time the sound is played). + + \sa loops(), isFinished() +*/ +int QSound::loopsRemaining() const +{ + Q_D(const QSound); + return d->looprem; +} + +/*! + \fn void QSound::setLoops(int number) + + Sets the sound to repeat the given \a number of times when it is + played. + + Note that passing the value -1 will cause the sound to loop + indefinitely. + + \sa loops() +*/ +void QSound::setLoops(int n) +{ + Q_D(QSound); + d->looptotal = n; +} + +/*! + Returns the filename associated with this QSound object. + + \sa QSound() +*/ +QString QSound::fileName() const +{ + Q_D(const QSound); + return d->filename; +} + +/*! + Stops the sound playing. + + Note that on Windows the current loop will finish if a sound is + played in a loop. + + \sa play() +*/ +void QSound::stop() +{ + Q_D(QSound); + server().stop(this); + d->looprem = 0; +} + + +/*! + Returns true if sound facilities exist on the platform; otherwise + returns false. + + If no sound is available, all QSound operations work silently and + quickly. An application may choose either to notify the user if + sound is crucial to the application or to operate silently without + bothering the user. + + Note: On Windows this always returns true because some sound card + drivers do not implement a way to find out whether it is available + or not. +*/ +bool QSound::isAvailable() +{ + return server().okay(); +} + +/*! + Sets the internal bucket record of sound \a s to \a b, deleting + any previous setting. +*/ +void QAuServer::setBucket(QSound* s, QAuBucket* b) +{ + delete s->d_func()->bucket; + s->d_func()->bucket = b; +} + +/*! + Returns the internal bucket record of sound \a s. +*/ +QAuBucket* QAuServer::bucket(QSound* s) +{ + return s->d_func()->bucket; +} + +/*! + Decrements the QSound::loopRemaining() value for sound \a s, + returning the result. +*/ +int QAuServer::decLoop(QSound* s) +{ + if (s->d_func()->looprem > 0) + --s->d_func()->looprem; + return s->d_func()->looprem; +} + +/*! + Initializes the sound. The default implementation does nothing. +*/ +void QAuServer::init(QSound*) +{ +} + +QAuBucket::~QAuBucket() +{ +} +/*! + \fn bool QSound::available() + + Use the isAvailable() function instead. +*/ + +QT_END_NAMESPACE + +#endif // QT_NO_SOUND diff --git a/src/widgets/kernel/qsound.h b/src/widgets/kernel/qsound.h new file mode 100644 index 0000000000..a0d058011a --- /dev/null +++ b/src/widgets/kernel/qsound.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUND_H +#define QSOUND_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_SOUND + +class QSoundPrivate; + +class Q_GUI_EXPORT QSound : public QObject +{ + Q_OBJECT + +public: + static bool isAvailable(); + static void play(const QString& filename); + + explicit QSound(const QString& filename, QObject* parent = 0); + ~QSound(); + + int loops() const; + int loopsRemaining() const; + void setLoops(int); + QString fileName() const; + + bool isFinished() const; + +public Q_SLOTS: + void play(); + void stop(); + +private: + Q_DECLARE_PRIVATE(QSound) + friend class QAuServer; +}; + +#endif // QT_NO_SOUND + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUND_H diff --git a/src/widgets/kernel/qsound_p.h b/src/widgets/kernel/qsound_p.h new file mode 100644 index 0000000000..dfdbfff063 --- /dev/null +++ b/src/widgets/kernel/qsound_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUND_P_H +#define QSOUND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SOUND + +class QSound; +/* + QAuServer is an INTERNAL class. If you wish to provide support for + additional audio servers, you can make a subclass of QAuServer to do + so, HOWEVER, your class may need to be re-engineered to some degree + with each new Qt release, including minor releases. + + QAuBucket is whatever you want. +*/ + +class QAuBucket { +public: + virtual ~QAuBucket(); +}; + +class QAuServer : public QObject { + Q_OBJECT + +public: + explicit QAuServer(QObject* parent); + ~QAuServer(); + + virtual void init(QSound*); + virtual void play(const QString& filename); + virtual void play(QSound*)=0; + virtual void stop(QSound*)=0; + virtual bool okay()=0; + +protected: + void setBucket(QSound*, QAuBucket*); + QAuBucket* bucket(QSound*); + int decLoop(QSound*); +}; + +#endif // QT_NO_SOUND + +QT_END_NAMESPACE + +#endif // QSOUND_P_H diff --git a/src/widgets/kernel/qstackedlayout.cpp b/src/widgets/kernel/qstackedlayout.cpp new file mode 100644 index 0000000000..c5ce238958 --- /dev/null +++ b/src/widgets/kernel/qstackedlayout.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstackedlayout.h" +#include "qlayout_p.h" + +#include +#include +#include "private/qlayoutengine_p.h" + +QT_BEGIN_NAMESPACE + +class QStackedLayoutPrivate : public QLayoutPrivate +{ + Q_DECLARE_PUBLIC(QStackedLayout) +public: + QStackedLayoutPrivate() : index(-1), stackingMode(QStackedLayout::StackOne) {} + QList list; + int index; + QStackedLayout::StackingMode stackingMode; +}; + +/*! + \class QStackedLayout + + \brief The QStackedLayout class provides a stack of widgets where + only one widget is visible at a time. + + \ingroup geomanagement + + QStackedLayout can be used to create a user interface similar to + the one provided by QTabWidget. There is also a convenience + QStackedWidget class built on top of QStackedLayout. + + A QStackedLayout can be populated with a number of child widgets + ("pages"). For example: + + \snippet doc/src/snippets/qstackedlayout/main.cpp 0 + \codeline + \snippet doc/src/snippets/qstackedlayout/main.cpp 2 + \snippet doc/src/snippets/qstackedlayout/main.cpp 3 + + QStackedLayout provides no intrinsic means for the user to switch + page. This is typically done through a QComboBox or a QListWidget + that stores the titles of the QStackedLayout's pages. For + example: + + \snippet doc/src/snippets/qstackedlayout/main.cpp 1 + + When populating a layout, the widgets are added to an internal + list. The indexOf() function returns the index of a widget in that + list. The widgets can either be added to the end of the list using + the addWidget() function, or inserted at a given index using the + insertWidget() function. The removeWidget() function removes the + widget at the given index from the layout. The number of widgets + contained in the layout, can be obtained using the count() + function. + + The widget() function returns the widget at a given index + position. The index of the widget that is shown on screen is given + by currentIndex() and can be changed using setCurrentIndex(). In a + similar manner, the currently shown widget can be retrieved using + the currentWidget() function, and altered using the + setCurrentWidget() function. + + Whenever the current widget in the layout changes or a widget is + removed from the layout, the currentChanged() and widgetRemoved() + signals are emitted respectively. + + \sa QStackedWidget, QTabWidget +*/ + +/*! + \fn void QStackedLayout::currentChanged(int index) + + This signal is emitted whenever the current widget in the layout + changes. The \a index specifies the index of the new current + widget, or -1 if there isn't a new one (for example, if there + are no widgets in the QStackedLayout) + + \sa currentWidget(), setCurrentWidget() +*/ + +/*! + \fn void QStackedLayout::widgetRemoved(int index) + + This signal is emitted whenever a widget is removed from the + layout. The widget's \a index is passed as parameter. + + \sa removeWidget() +*/ + +/*! + \fn QWidget *QStackedLayout::widget() + \internal +*/ + +/*! + Constructs a QStackedLayout with no parent. + + This QStackedLayout must be installed on a widget later on to + become effective. + + \sa addWidget(), insertWidget() +*/ +QStackedLayout::QStackedLayout() + : QLayout(*new QStackedLayoutPrivate, 0, 0) +{ +} + +/*! + Constructs a new QStackedLayout with the given \a parent. + + This layout will install itself on the \a parent widget and + manage the geometry of its children. +*/ +QStackedLayout::QStackedLayout(QWidget *parent) + : QLayout(*new QStackedLayoutPrivate, 0, parent) +{ +} + +/*! + Constructs a new QStackedLayout and inserts it into + the given \a parentLayout. +*/ +QStackedLayout::QStackedLayout(QLayout *parentLayout) + : QLayout(*new QStackedLayoutPrivate, parentLayout, 0) +{ +} + +/*! + Destroys this QStackedLayout. Note that the layout's widgets are + \e not destroyed. +*/ +QStackedLayout::~QStackedLayout() +{ + Q_D(QStackedLayout); + qDeleteAll(d->list); +} + +/*! + Adds the given \a widget to the end of this layout and returns the + index position of the \a widget. + + If the QStackedLayout is empty before this function is called, + the given \a widget becomes the current widget. + + \sa insertWidget(), removeWidget(), setCurrentWidget() +*/ +int QStackedLayout::addWidget(QWidget *widget) +{ + Q_D(QStackedLayout); + return insertWidget(d->list.count(), widget); +} + +/*! + Inserts the given \a widget at the given \a index in this + QStackedLayout. If \a index is out of range, the widget is + appended (in which case it is the actual index of the \a widget + that is returned). + + If the QStackedLayout is empty before this function is called, the + given \a widget becomes the current widget. + + Inserting a new widget at an index less than or equal to the current index + will increment the current index, but keep the current widget. + + \sa addWidget(), removeWidget(), setCurrentWidget() +*/ +int QStackedLayout::insertWidget(int index, QWidget *widget) +{ + Q_D(QStackedLayout); + addChildWidget(widget); + index = qMin(index, d->list.count()); + if (index < 0) + index = d->list.count(); + QWidgetItem *wi = QLayoutPrivate::createWidgetItem(this, widget); + d->list.insert(index, wi); + invalidate(); + if (d->index < 0) { + setCurrentIndex(index); + } else { + if (index <= d->index) + ++d->index; + if (d->stackingMode == StackOne) + widget->hide(); + widget->lower(); + } + return index; +} + +/*! + \reimp +*/ +QLayoutItem *QStackedLayout::itemAt(int index) const +{ + Q_D(const QStackedLayout); + return d->list.value(index); +} + +// Code that enables proper handling of the case that takeAt() is +// called somewhere inside QObject destructor (can't call hide() +// on the object then) + +class QtFriendlyLayoutWidget : public QWidget +{ +public: + inline bool wasDeleted() const { return d_ptr->wasDeleted; } +}; + +static bool qt_wasDeleted(const QWidget *w) { return static_cast(w)->wasDeleted(); } + + +/*! + \reimp +*/ +QLayoutItem *QStackedLayout::takeAt(int index) +{ + Q_D(QStackedLayout); + if (index <0 || index >= d->list.size()) + return 0; + QLayoutItem *item = d->list.takeAt(index); + if (index == d->index) { + d->index = -1; + if ( d->list.count() > 0 ) { + int newIndex = (index == d->list.count()) ? index-1 : index; + setCurrentIndex(newIndex); + } else { + emit currentChanged(-1); + } + } else if (index < d->index) { + --d->index; + } + emit widgetRemoved(index); + if (item->widget() && !qt_wasDeleted(item->widget())) + item->widget()->hide(); + return item; +} + +/*! + \property QStackedLayout::currentIndex + \brief the index position of the widget that is visible + + The current index is -1 if there is no current widget. + + \sa currentWidget(), indexOf() +*/ +void QStackedLayout::setCurrentIndex(int index) +{ + Q_D(QStackedLayout); + QWidget *prev = currentWidget(); + QWidget *next = widget(index); + if (!next || next == prev) + return; + + bool reenableUpdates = false; + QWidget *parent = parentWidget(); + + if (parent && parent->updatesEnabled()) { + reenableUpdates = true; + parent->setUpdatesEnabled(false); + } + + QWidget *fw = parent ? parent->window()->focusWidget() : 0; + if (prev) { + prev->clearFocus(); + if (d->stackingMode == StackOne) + prev->hide(); + } + + d->index = index; + next->raise(); + next->show(); + + // try to move focus onto the incoming widget if focus + // was somewhere on the outgoing widget. + + if (parent) { + if (fw && (prev && prev->isAncestorOf(fw))) { // focus was on old page + // look for the best focus widget we can find + if (QWidget *nfw = next->focusWidget()) + nfw->setFocus(); + else { + // second best: first child widget in the focus chain + QWidget *i = fw; + while ((i = i->nextInFocusChain()) != fw) { + if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus) + && !i->focusProxy() && i->isVisibleTo(next) && i->isEnabled() + && next->isAncestorOf(i)) { + i->setFocus(); + break; + } + } + // third best: incoming widget + if (i == fw ) + next->setFocus(); + } + } + } + if (reenableUpdates) + parent->setUpdatesEnabled(true); + emit currentChanged(index); +} + +int QStackedLayout::currentIndex() const +{ + Q_D(const QStackedLayout); + return d->index; +} + + +/*! + \fn void QStackedLayout::setCurrentWidget(QWidget *widget) + + Sets the current widget to be the specified \a widget. The new + current widget must already be contained in this stacked layout. + + \sa setCurrentIndex(), currentWidget() + */ +void QStackedLayout::setCurrentWidget(QWidget *widget) +{ + int index = indexOf(widget); + if (index == -1) { + qWarning("QStackedLayout::setCurrentWidget: Widget %p not contained in stack", widget); + return; + } + setCurrentIndex(index); +} + + +/*! + Returns the current widget, or 0 if there are no widgets in this + layout. + + \sa currentIndex(), setCurrentWidget() +*/ +QWidget *QStackedLayout::currentWidget() const +{ + Q_D(const QStackedLayout); + return d->index >= 0 ? d->list.at(d->index)->widget() : 0; +} + +/*! + Returns the widget at the given \a index, or 0 if there is no + widget at the given position. + + \sa currentWidget(), indexOf() +*/ +QWidget *QStackedLayout::widget(int index) const +{ + Q_D(const QStackedLayout); + if (index < 0 || index >= d->list.size()) + return 0; + return d->list.at(index)->widget(); +} + +/*! + \property QStackedLayout::count + \brief the number of widgets contained in the layout + + \sa currentIndex(), widget() +*/ +int QStackedLayout::count() const +{ + Q_D(const QStackedLayout); + return d->list.size(); +} + + +/*! + \reimp +*/ +void QStackedLayout::addItem(QLayoutItem *item) +{ + QWidget *widget = item->widget(); + if (widget) { + addWidget(widget); + delete item; + } else { + qWarning("QStackedLayout::addItem: Only widgets can be added"); + } +} + +/*! + \reimp +*/ +QSize QStackedLayout::sizeHint() const +{ + Q_D(const QStackedLayout); + QSize s(0, 0); + int n = d->list.count(); + + for (int i = 0; i < n; ++i) + if (QWidget *widget = d->list.at(i)->widget()) { + QSize ws(widget->sizeHint()); + if (widget->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) + ws.setWidth(0); + if (widget->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) + ws.setHeight(0); + s = s.expandedTo(ws); + } + return s; +} + +/*! + \reimp +*/ +QSize QStackedLayout::minimumSize() const +{ + Q_D(const QStackedLayout); + QSize s(0, 0); + int n = d->list.count(); + + for (int i = 0; i < n; ++i) + if (QWidget *widget = d->list.at(i)->widget()) + s = s.expandedTo(qSmartMinSize(widget)); + return s; +} + +/*! + \reimp +*/ +void QStackedLayout::setGeometry(const QRect &rect) +{ + Q_D(QStackedLayout); + switch (d->stackingMode) { + case StackOne: + if (QWidget *widget = currentWidget()) + widget->setGeometry(rect); + break; + case StackAll: + if (const int n = d->list.count()) + for (int i = 0; i < n; ++i) + if (QWidget *widget = d->list.at(i)->widget()) + widget->setGeometry(rect); + break; + } +} + +/*! + \enum QStackedLayout::StackingMode + \since 4.4 + + This enum specifies how the layout handles its child widgets + regarding their visibility. + + \value StackOne + Only the current widget is visible. This is the default. + + \value StackAll + All widgets are visible. The current widget is merely raised. +*/ + + +/*! + \property QStackedLayout::stackingMode + \brief determines the way visibility of child widgets are handled. + \since 4.4 + + The default value is StackOne. Setting the property to StackAll + allows you to make use of the layout for overlay widgets + that do additional drawing on top of other widgets, for example, + graphical editors. +*/ + +QStackedLayout::StackingMode QStackedLayout::stackingMode() const +{ + Q_D(const QStackedLayout); + return d->stackingMode; +} + +void QStackedLayout::setStackingMode(StackingMode stackingMode) +{ + Q_D(QStackedLayout); + if (d->stackingMode == stackingMode) + return; + d->stackingMode = stackingMode; + + const int n = d->list.count(); + if (n == 0) + return; + + switch (d->stackingMode) { + case StackOne: + if (const int idx = currentIndex()) + for (int i = 0; i < n; ++i) + if (QWidget *widget = d->list.at(i)->widget()) + widget->setVisible(i == idx); + break; + case StackAll: { // Turn overlay on: Make sure all widgets are the same size + QRect geometry; + if (const QWidget *widget = currentWidget()) + geometry = widget->geometry(); + for (int i = 0; i < n; ++i) + if (QWidget *widget = d->list.at(i)->widget()) { + if (!geometry.isNull()) + widget->setGeometry(geometry); + widget->setVisible(true); + } + } + break; + } +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qstackedlayout.h b/src/widgets/kernel/qstackedlayout.h new file mode 100644 index 0000000000..49b80c6445 --- /dev/null +++ b/src/widgets/kernel/qstackedlayout.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTACKEDLAYOUT_H +#define QSTACKEDLAYOUT_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStackedLayoutPrivate; + +class Q_GUI_EXPORT QStackedLayout : public QLayout +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QStackedLayout) + Q_ENUMS(StackingMode) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged) + Q_PROPERTY(StackingMode stackingMode READ stackingMode WRITE setStackingMode) + QDOC_PROPERTY(int count READ count) + +public: + enum StackingMode { + StackOne, + StackAll + }; + + QStackedLayout(); + explicit QStackedLayout(QWidget *parent); + explicit QStackedLayout(QLayout *parentLayout); + ~QStackedLayout(); + + int addWidget(QWidget *w); + int insertWidget(int index, QWidget *w); + + QWidget *currentWidget() const; + int currentIndex() const; +#ifdef Q_NO_USING_KEYWORD + inline QWidget *widget() { return QLayout::widget(); } +#else + using QLayout::widget; +#endif + QWidget *widget(int) const; + int count() const; + + StackingMode stackingMode() const; + void setStackingMode(StackingMode stackingMode); + + // abstract virtual functions: + void addItem(QLayoutItem *item); + QSize sizeHint() const; + QSize minimumSize() const; + QLayoutItem *itemAt(int) const; + QLayoutItem *takeAt(int); + void setGeometry(const QRect &rect); + +Q_SIGNALS: + void widgetRemoved(int index); + void currentChanged(int index); + +public Q_SLOTS: + void setCurrentIndex(int index); + void setCurrentWidget(QWidget *w); + +private: + Q_DISABLE_COPY(QStackedLayout) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSTACKEDLAYOUT_H diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp new file mode 100644 index 0000000000..6338ef7afb --- /dev/null +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstandardgestures_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qwidget.h" +#include "qabstractscrollarea.h" +#include +#include "qdebug.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +QPanGestureRecognizer::QPanGestureRecognizer() +{ +} + +QGesture *QPanGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { +#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES) + // for scroll areas on Windows we want to use native gestures instead + if (!qobject_cast(target->parent())) + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); +#else + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); +#endif + } + return new QPanGesture; +} + +QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QPanGesture *q = static_cast(state); + QPanGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast(event); + + QGestureRecognizer::Result result; + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MayBeGesture; + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + d->lastOffset = d->offset = QPointF(); + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = d->offset; + d->offset = + QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), + p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + } + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + if (ev->touchPoints().size() >= 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = d->offset; + d->offset = + QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), + p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + if (d->offset.x() > 10 || d->offset.y() > 10 || + d->offset.x() < -10 || d->offset.y() < -10) { + q->setHotSpot(p1.startScreenPos()); + result = QGestureRecognizer::TriggerGesture; + } else { + result = QGestureRecognizer::MayBeGesture; + } + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast(state); + QPanGesturePrivate *d = pan->d_func(); + + d->lastOffset = d->offset = QPointF(); + d->acceleration = 0; + + QGestureRecognizer::reset(state); +} + + +// +// QPinchGestureRecognizer +// + +QPinchGestureRecognizer::QPinchGestureRecognizer() +{ +} + +QGesture *QPinchGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QPinchGesture; +} + +QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QPinchGesture *q = static_cast(state); + QPinchGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast(event); + + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MayBeGesture; + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + d->changeFlags = 0; + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + + d->hotSpot = p1.screenPos(); + d->isHotSpotSet = true; + + QPointF centerPoint = (p1.screenPos() + p2.screenPos()) / 2.0; + if (d->isNewSequence) { + d->startPosition[0] = p1.screenPos(); + d->startPosition[1] = p2.screenPos(); + d->lastCenterPoint = centerPoint; + } else { + d->lastCenterPoint = d->centerPoint; + } + d->centerPoint = centerPoint; + + d->changeFlags |= QPinchGesture::CenterPointChanged; + + if (d->isNewSequence) { + d->scaleFactor = 1.0; + d->lastScaleFactor = 1.0; + } else { + d->lastScaleFactor = d->scaleFactor; + QLineF line(p1.screenPos(), p2.screenPos()); + QLineF lastLine(p1.lastScreenPos(), p2.lastScreenPos()); + d->scaleFactor = line.length() / lastLine.length(); + } + d->totalScaleFactor = d->totalScaleFactor * d->scaleFactor; + d->changeFlags |= QPinchGesture::ScaleFactorChanged; + + qreal angle = QLineF(p1.screenPos(), p2.screenPos()).angle(); + if (angle > 180) + angle -= 360; + qreal startAngle = QLineF(p1.startScreenPos(), p2.startScreenPos()).angle(); + if (startAngle > 180) + startAngle -= 360; + const qreal rotationAngle = startAngle - angle; + if (d->isNewSequence) + d->lastRotationAngle = 0.0; + else + d->lastRotationAngle = d->rotationAngle; + d->rotationAngle = rotationAngle; + d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle; + d->changeFlags |= QPinchGesture::RotationAngleChanged; + + d->totalChangeFlags |= d->changeFlags; + d->isNewSequence = false; + result = QGestureRecognizer::TriggerGesture; + } else { + d->isNewSequence = true; + if (q->state() == Qt::NoGesture) + result = QGestureRecognizer::Ignore; + else + result = QGestureRecognizer::FinishGesture; + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPinchGestureRecognizer::reset(QGesture *state) +{ + QPinchGesture *pinch = static_cast(state); + QPinchGesturePrivate *d = pinch->d_func(); + + d->totalChangeFlags = d->changeFlags = 0; + + d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF(); + d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 1; + d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0; + + d->isNewSequence = true; + d->startPosition[0] = d->startPosition[1] = QPointF(); + + QGestureRecognizer::reset(state); +} + +// +// QSwipeGestureRecognizer +// + +QSwipeGestureRecognizer::QSwipeGestureRecognizer() +{ +} + +QGesture *QSwipeGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QSwipeGesture; +} + +QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QSwipeGesture *q = static_cast(state); + QSwipeGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast(event); + + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + d->velocityValue = 1; + d->time.start(); + d->started = true; + result = QGestureRecognizer::MayBeGesture; + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + if (!d->started) + result = QGestureRecognizer::CancelGesture; + else if (ev->touchPoints().size() == 3) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2); + + if (d->lastPositions[0].isNull()) { + d->lastPositions[0] = p1.startScreenPos().toPoint(); + d->lastPositions[1] = p2.startScreenPos().toPoint(); + d->lastPositions[2] = p3.startScreenPos().toPoint(); + } + d->hotSpot = p1.screenPos(); + d->isHotSpotSet = true; + + int xDistance = (p1.screenPos().x() - d->lastPositions[0].x() + + p2.screenPos().x() - d->lastPositions[1].x() + + p3.screenPos().x() - d->lastPositions[2].x()) / 3; + int yDistance = (p1.screenPos().y() - d->lastPositions[0].y() + + p2.screenPos().y() - d->lastPositions[1].y() + + p3.screenPos().y() - d->lastPositions[2].y()) / 3; + + const int distance = xDistance >= yDistance ? xDistance : yDistance; + int elapsedTime = d->time.restart(); + if (!elapsedTime) + elapsedTime = 1; + d->velocityValue = 0.9 * d->velocityValue + distance / elapsedTime; + d->swipeAngle = QLineF(p1.startScreenPos(), p1.screenPos()).angle(); + + static const int MoveThreshold = 50; + if (xDistance > MoveThreshold || yDistance > MoveThreshold) { + // measure the distance to check if the direction changed + d->lastPositions[0] = p1.screenPos().toPoint(); + d->lastPositions[1] = p2.screenPos().toPoint(); + d->lastPositions[2] = p3.screenPos().toPoint(); + QSwipeGesture::SwipeDirection horizontal = + xDistance > 0 ? QSwipeGesture::Right : QSwipeGesture::Left; + QSwipeGesture::SwipeDirection vertical = + yDistance > 0 ? QSwipeGesture::Down : QSwipeGesture::Up; + if (d->verticalDirection == QSwipeGesture::NoDirection) + d->verticalDirection = vertical; + if (d->horizontalDirection == QSwipeGesture::NoDirection) + d->horizontalDirection = horizontal; + if (d->verticalDirection != vertical || d->horizontalDirection != horizontal) { + // the user has changed the direction! + result = QGestureRecognizer::CancelGesture; + } + result = QGestureRecognizer::TriggerGesture; + } else { + if (q->state() != Qt::NoGesture) + result = QGestureRecognizer::TriggerGesture; + else + result = QGestureRecognizer::MayBeGesture; + } + } else if (ev->touchPoints().size() > 3) { + result = QGestureRecognizer::CancelGesture; + } else { // less than 3 touch points + if (d->started && (ev->touchPointStates() & Qt::TouchPointPressed)) + result = QGestureRecognizer::CancelGesture; + else if (d->started) + result = QGestureRecognizer::Ignore; + else + result = QGestureRecognizer::MayBeGesture; + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QSwipeGestureRecognizer::reset(QGesture *state) +{ + QSwipeGesture *q = static_cast(state); + QSwipeGesturePrivate *d = q->d_func(); + + d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection; + d->swipeAngle = 0; + + d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint(); + d->started = false; + d->velocityValue = 0; + d->time.invalidate(); + + QGestureRecognizer::reset(state); +} + +// +// QTapGestureRecognizer +// + +QTapGestureRecognizer::QTapGestureRecognizer() +{ +} + +QGesture *QTapGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QTapGesture; +} + +QGestureRecognizer::Result QTapGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QTapGesture *q = static_cast(state); + QTapGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast(event); + + QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture; + + switch (event->type()) { + case QEvent::TouchBegin: { + d->position = ev->touchPoints().at(0).pos(); + q->setHotSpot(ev->touchPoints().at(0).screenPos()); + result = QGestureRecognizer::TriggerGesture; + break; + } + case QEvent::TouchUpdate: + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) { + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + QPoint delta = p.pos().toPoint() - p.startPos().toPoint(); + enum { TapRadius = 40 }; + if (delta.manhattanLength() <= TapRadius) { + if (event->type() == QEvent::TouchEnd) + result = QGestureRecognizer::FinishGesture; + else + result = QGestureRecognizer::TriggerGesture; + } + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QTapGestureRecognizer::reset(QGesture *state) +{ + QTapGesture *q = static_cast(state); + QTapGesturePrivate *d = q->d_func(); + + d->position = QPointF(); + + QGestureRecognizer::reset(state); +} + +// +// QTapAndHoldGestureRecognizer +// + +QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer() +{ +} + +QGesture *QTapAndHoldGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QTapAndHoldGesture; +} + +QGestureRecognizer::Result +QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object, + QEvent *event) +{ + QTapAndHoldGesture *q = static_cast(state); + QTapAndHoldGesturePrivate *d = q->d_func(); + + if (object == state && event->type() == QEvent::Timer) { + q->killTimer(d->timerId); + d->timerId = 0; + return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint; + } + + const QTouchEvent *ev = static_cast(event); + const QMouseEvent *me = static_cast(event); +#ifndef QT_NO_GRAPHICSVIEW + const QGraphicsSceneMouseEvent *gsme = static_cast(event); +#endif + + enum { TapRadius = 40 }; + + switch (event->type()) { +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMousePress: + d->position = gsme->screenPos(); + q->setHotSpot(d->position); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout); + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout +#endif + case QEvent::MouseButtonPress: + d->position = me->globalPos(); + q->setHotSpot(d->position); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout); + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout + case QEvent::TouchBegin: + d->position = ev->touchPoints().at(0).startScreenPos(); + q->setHotSpot(d->position); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout); + return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseRelease: +#endif + case QEvent::MouseButtonRelease: + case QEvent::TouchEnd: + return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state + case QEvent::TouchUpdate: + if (d->timerId && ev->touchPoints().size() == 1) { + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + QPoint delta = p.pos().toPoint() - p.startPos().toPoint(); + if (delta.manhattanLength() <= TapRadius) + return QGestureRecognizer::MayBeGesture; + } + return QGestureRecognizer::CancelGesture; + case QEvent::MouseMove: { + QPoint delta = me->globalPos() - d->position.toPoint(); + if (d->timerId && delta.manhattanLength() <= TapRadius) + return QGestureRecognizer::MayBeGesture; + return QGestureRecognizer::CancelGesture; + } +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseMove: { + QPoint delta = gsme->screenPos() - d->position.toPoint(); + if (d->timerId && delta.manhattanLength() <= TapRadius) + return QGestureRecognizer::MayBeGesture; + return QGestureRecognizer::CancelGesture; + } +#endif + default: + return QGestureRecognizer::Ignore; + } +} + +void QTapAndHoldGestureRecognizer::reset(QGesture *state) +{ + QTapAndHoldGesture *q = static_cast(state); + QTapAndHoldGesturePrivate *d = q->d_func(); + + d->position = QPointF(); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = 0; + + QGestureRecognizer::reset(state); +} + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES diff --git a/src/widgets/kernel/qstandardgestures_p.h b/src/widgets/kernel/qstandardgestures_p.h new file mode 100644 index 0000000000..b3c5002565 --- /dev/null +++ b/src/widgets/kernel/qstandardgestures_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTANDARDGESTURES_P_H +#define QSTANDARDGESTURES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qgesturerecognizer.h" +#include "private/qgesture_p.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +class QPanGestureRecognizer : public QGestureRecognizer +{ +public: + QPanGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QPinchGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QSwipeGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QTapGestureRecognizer : public QGestureRecognizer +{ +public: + QTapGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QTapAndHoldGestureRecognizer : public QGestureRecognizer +{ +public: + QTapAndHoldGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES + +#endif // QSTANDARDGESTURES_P_H diff --git a/src/widgets/kernel/qt_gui_pch.h b/src/widgets/kernel/qt_gui_pch.h new file mode 100644 index 0000000000..368c12d444 --- /dev/null +++ b/src/widgets/kernel/qt_gui_pch.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This is a precompiled header file for use in Xcode / Mac GCC / + * GCC >= 3.4 / VC to greatly speed the building of Qt. It may also be + * of use to people developing their own project, but it is probably + * better to define your own header. Use of this header is currently + * UNSUPPORTED. + */ + +// from corelib/global/qt_pch.h +#if defined __cplusplus +#include + + +#ifdef Q_WS_WIN +# define _POSIX_ +# include +# undef _POSIX_ +#endif + +#include +#include +#include // All moc genereated code has this include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#endif diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp new file mode 100644 index 0000000000..4311df58a6 --- /dev/null +++ b/src/widgets/kernel/qtooltip.cpp @@ -0,0 +1,623 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifdef Q_WS_MAC +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef QT_NO_TOOLTIP + +#ifdef Q_WS_MAC +# include +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QToolTip + + \brief The QToolTip class provides tool tips (balloon help) for any + widget. + + \ingroup helpsystem + + + The tip is a short piece of text reminding the user of the + widget's function. It is drawn immediately below the given + position in a distinctive black-on-yellow color combination. The + tip can be any \l{QTextEdit}{rich text} formatted string. + + Rich text displayed in a tool tip is implicitly word-wrapped unless + specified differently with \c{

}. + + The simplest and most common way to set a widget's tool tip is by + calling its QWidget::setToolTip() function. + + It is also possible to show different tool tips for different + regions of a widget, by using a QHelpEvent of type + QEvent::ToolTip. Intercept the help event in your widget's \l + {QWidget::}{event()} function and call QToolTip::showText() with + the text you want to display. The \l{widgets/tooltips}{Tooltips} + example illustrates this technique. + + If you are calling QToolTip::hideText(), or QToolTip::showText() + with an empty string, as a result of a \l{QEvent::}{ToolTip}-event you + should also call \l{QEvent::}{ignore()} on the event, to signal + that you don't want to start any tooltip specific modes. + + Note that, if you want to show tooltips in an item view, the + model/view architecture provides functionality to set an item's + tool tip; e.g., the QTableWidgetItem::setToolTip() function. + However, if you want to provide custom tool tips in an item view, + you must intercept the help event in the + QAbstractItemView::viewportEvent() function and handle it yourself. + + The default tool tip color and font can be customized with + setPalette() and setFont(). When a tooltip is currently on + display, isVisible() returns true and text() the currently visible + text. + + \note Tool tips use the inactive color group of QPalette, because tool + tips are not active windows. + + \sa QWidget::toolTip, QAction::toolTip, {Tool Tips Example} +*/ + +class QTipLabel : public QLabel +{ + Q_OBJECT +public: + QTipLabel(const QString &text, QWidget *w); + ~QTipLabel(); + static QTipLabel *instance; + + bool eventFilter(QObject *, QEvent *); + + QBasicTimer hideTimer, expireTimer; + + bool fadingOut; + + void reuseTip(const QString &text); + void hideTip(); + void hideTipImmediately(); + void setTipRect(QWidget *w, const QRect &r); + void restartExpireTimer(); + bool tipChanged(const QPoint &pos, const QString &text, QObject *o); + void placeTip(const QPoint &pos, QWidget *w); + + static int getTipScreen(const QPoint &pos, QWidget *w); +protected: + void timerEvent(QTimerEvent *e); + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + +#ifndef QT_NO_STYLE_STYLESHEET +public slots: + /** \internal + Cleanup the _q_stylesheet_parent propery. + */ + void styleSheetParentDestroyed() { + setProperty("_q_stylesheet_parent", QVariant()); + styleSheetParent = 0; + } + +private: + QWidget *styleSheetParent; +#endif + +private: + QWidget *widget; + QRect rect; +}; + +QTipLabel *QTipLabel::instance = 0; + +QTipLabel::QTipLabel(const QString &text, QWidget *w) +#ifndef QT_NO_STYLE_STYLESHEET + : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), styleSheetParent(0), widget(0) +#else + : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), widget(0) +#endif +{ + delete instance; + instance = this; + setForegroundRole(QPalette::ToolTipText); + setBackgroundRole(QPalette::ToolTipBase); + setPalette(QToolTip::palette()); + ensurePolished(); + setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this)); + setFrameStyle(QFrame::NoFrame); + setAlignment(Qt::AlignLeft); + setIndent(1); + qApp->installEventFilter(this); + setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); + setMouseTracking(true); + fadingOut = false; + reuseTip(text); +} + +void QTipLabel::restartExpireTimer() +{ + int time = 10000 + 40 * qMax(0, text().length()-100); + expireTimer.start(time, this); + hideTimer.stop(); +} + +void QTipLabel::reuseTip(const QString &text) +{ +#ifndef QT_NO_STYLE_STYLESHEET + if (styleSheetParent){ + disconnect(styleSheetParent, SIGNAL(destroyed()), + QTipLabel::instance, SLOT(styleSheetParentDestroyed())); + styleSheetParent = 0; + } +#endif + + setWordWrap(Qt::mightBeRichText(text)); + setText(text); + QFontMetrics fm(font()); + QSize extra(1, 0); + // Make it look good with the default ToolTip font on Mac, which has a small descent. + if (fm.descent() == 2 && fm.ascent() >= 11) + ++extra.rheight(); + resize(sizeHint() + extra); + restartExpireTimer(); +} + +void QTipLabel::paintEvent(QPaintEvent *ev) +{ + QStylePainter p(this); + QStyleOptionFrame opt; + opt.init(this); + p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); + p.end(); + + QLabel::paintEvent(ev); +} + +void QTipLabel::resizeEvent(QResizeEvent *e) +{ + QStyleHintReturnMask frameMask; + QStyleOption option; + option.init(this); + if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask)) + setMask(frameMask.region); + + QLabel::resizeEvent(e); +} + +void QTipLabel::mouseMoveEvent(QMouseEvent *e) +{ + if (rect.isNull()) + return; + QPoint pos = e->globalPos(); + if (widget) + pos = widget->mapFromGlobal(pos); + if (!rect.contains(pos)) + hideTip(); + QLabel::mouseMoveEvent(e); +} + +QTipLabel::~QTipLabel() +{ + instance = 0; +} + +void QTipLabel::hideTip() +{ + if (!hideTimer.isActive()) + hideTimer.start(300, this); +} + +void QTipLabel::hideTipImmediately() +{ + close(); // to trigger QEvent::Close which stops the animation + deleteLater(); +} + +void QTipLabel::setTipRect(QWidget *w, const QRect &r) +{ + if (!rect.isNull() && !w) + qWarning("QToolTip::setTipRect: Cannot pass null widget if rect is set"); + else{ + widget = w; + rect = r; + } +} + +void QTipLabel::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == hideTimer.timerId() + || e->timerId() == expireTimer.timerId()){ + hideTimer.stop(); + expireTimer.stop(); +#if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS) + if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)){ + // Fade out tip on mac (makes it invisible). + // The tip will not be deleted until a new tip is shown. + + // DRSWAT - Cocoa + macWindowFade(qt_mac_window_for(this)); + QTipLabel::instance->fadingOut = true; // will never be false again. + } + else + hideTipImmediately(); +#else + hideTipImmediately(); +#endif + } +} + +bool QTipLabel::eventFilter(QObject *o, QEvent *e) +{ + switch (e->type()) { +#ifdef Q_WS_MAC + case QEvent::KeyPress: + case QEvent::KeyRelease: { + int key = static_cast(e)->key(); + Qt::KeyboardModifiers mody = static_cast(e)->modifiers(); + if (!(mody & Qt::KeyboardModifierMask) + && key != Qt::Key_Shift && key != Qt::Key_Control + && key != Qt::Key_Alt && key != Qt::Key_Meta) + hideTip(); + break; + } +#endif + case QEvent::Leave: + hideTip(); + break; + case QEvent::WindowActivate: + case QEvent::WindowDeactivate: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Wheel: + hideTipImmediately(); + break; + + case QEvent::MouseMove: + if (o == widget && !rect.isNull() && !rect.contains(static_cast(e)->pos())) + hideTip(); + default: + break; + } + return false; +} + +int QTipLabel::getTipScreen(const QPoint &pos, QWidget *w) +{ + if (QApplication::desktop()->isVirtualDesktop()) + return QApplication::desktop()->screenNumber(pos); + else + return QApplication::desktop()->screenNumber(w); +} + +void QTipLabel::placeTip(const QPoint &pos, QWidget *w) +{ +#ifndef QT_NO_STYLE_STYLESHEET + if (testAttribute(Qt::WA_StyleSheet) || (w && qobject_cast(w->style()))) { + //the stylesheet need to know the real parent + QTipLabel::instance->setProperty("_q_stylesheet_parent", QVariant::fromValue(w)); + //we force the style to be the QStyleSheetStyle, and force to clear the cache as well. + QTipLabel::instance->setStyleSheet(QLatin1String("/* */")); + + // Set up for cleaning up this later... + QTipLabel::instance->styleSheetParent = w; + if (w) { + connect(w, SIGNAL(destroyed()), + QTipLabel::instance, SLOT(styleSheetParentDestroyed())); + } + } +#endif //QT_NO_STYLE_STYLESHEET + + +#ifdef Q_WS_MAC + // When in full screen mode, there is no Dock nor Menu so we can use + // the whole screen for displaying the tooltip. However when not in + // full screen mode we need to save space for the dock, so we use + // availableGeometry instead. + extern bool qt_mac_app_fullscreen; //qapplication_mac.mm + QRect screen; + if(qt_mac_app_fullscreen) + screen = QApplication::desktop()->screenGeometry(getTipScreen(pos, w)); + else + screen = QApplication::desktop()->availableGeometry(getTipScreen(pos, w)); +#else + QRect screen = QApplication::desktop()->screenGeometry(getTipScreen(pos, w)); +#endif + + QPoint p = pos; + p += QPoint(2, +#ifdef Q_WS_WIN + 21 +#else + 16 +#endif + ); + if (p.x() + this->width() > screen.x() + screen.width()) + p.rx() -= 4 + this->width(); + if (p.y() + this->height() > screen.y() + screen.height()) + p.ry() -= 24 + this->height(); + if (p.y() < screen.y()) + p.setY(screen.y()); + if (p.x() + this->width() > screen.x() + screen.width()) + p.setX(screen.x() + screen.width() - this->width()); + if (p.x() < screen.x()) + p.setX(screen.x()); + if (p.y() + this->height() > screen.y() + screen.height()) + p.setY(screen.y() + screen.height() - this->height()); + this->move(p); +} + +bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o) +{ + if (QTipLabel::instance->text() != text) + return true; + + if (o != widget) + return true; + + if (!rect.isNull()) + return !rect.contains(pos); + else + return false; +} + +/*! + Shows \a text as a tool tip, with the global position \a pos as + the point of interest. The tool tip will be shown with a platform + specific offset from this point of interest. + + If you specify a non-empty rect the tip will be hidden as soon + as you move your cursor out of this area. + + The \a rect is in the coordinates of the widget you specify with + \a w. If the \a rect is not empty you must specify a widget. + Otherwise this argument can be 0 but it is used to determine the + appropriate screen on multi-head systems. + + If \a text is empty the tool tip is hidden. If the text is the + same as the currently shown tooltip, the tip will \e not move. + You can force moving by first hiding the tip with an empty text, + and then showing the new tip at the new position. +*/ + +void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect) +{ + if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist + if (text.isEmpty()){ // empty text means hide current tip + QTipLabel::instance->hideTip(); + return; + } + else if (!QTipLabel::instance->fadingOut){ + // If the tip has changed, reuse the one + // that is showing (removes flickering) + QPoint localPos = pos; + if (w) + localPos = w->mapFromGlobal(pos); + if (QTipLabel::instance->tipChanged(localPos, text, w)){ + QTipLabel::instance->reuseTip(text); + QTipLabel::instance->setTipRect(w, rect); + QTipLabel::instance->placeTip(pos, w); + } + return; + } + } + + if (!text.isEmpty()){ // no tip can be reused, create new tip: +#ifndef Q_WS_WIN + new QTipLabel(text, w); // sets QTipLabel::instance to itself +#else + // On windows, we can't use the widget as parent otherwise the window will be + // raised when the tooltip will be shown + new QTipLabel(text, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w))); +#endif + QTipLabel::instance->setTipRect(w, rect); + QTipLabel::instance->placeTip(pos, w); + QTipLabel::instance->setObjectName(QLatin1String("qtooltip_label")); + + +#if !defined(QT_NO_EFFECTS) && !defined(Q_WS_MAC) + if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)) + qFadeEffect(QTipLabel::instance); + else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip)) + qScrollEffect(QTipLabel::instance); + else + QTipLabel::instance->show(); +#else + QTipLabel::instance->show(); +#endif + } +} + +/*! + \overload + + This is analogous to calling QToolTip::showText(\a pos, \a text, \a w, QRect()) +*/ + +void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w) +{ + QToolTip::showText(pos, text, w, QRect()); +} + + +/*! + \fn void QToolTip::hideText() + \since 4.2 + + Hides the tool tip. This is the same as calling showText() with an + empty string. + + \sa showText() +*/ + + +/*! + \since 4.4 + + Returns true if this tooltip is currently shown. + + \sa showText() + */ +bool QToolTip::isVisible() +{ + return (QTipLabel::instance != 0 && QTipLabel::instance->isVisible()); +} + +/*! + \since 4.4 + + Returns the tooltip text, if a tooltip is visible, or an + empty string if a tooltip is not visible. + */ +QString QToolTip::text() +{ + if (QTipLabel::instance) + return QTipLabel::instance->text(); + return QString(); +} + + +Q_GLOBAL_STATIC(QPalette, tooltip_palette) + +/*! + Returns the palette used to render tooltips. + + \note Tool tips use the inactive color group of QPalette, because tool + tips are not active windows. +*/ +QPalette QToolTip::palette() +{ + return *tooltip_palette(); +} + +/*! + \since 4.2 + + Returns the font used to render tooltips. +*/ +QFont QToolTip::font() +{ + return QApplication::font("QTipLabel"); +} + +/*! + \since 4.2 + + Sets the \a palette used to render tooltips. + + \note Tool tips use the inactive color group of QPalette, because tool + tips are not active windows. +*/ +void QToolTip::setPalette(const QPalette &palette) +{ + *tooltip_palette() = palette; + if (QTipLabel::instance) + QTipLabel::instance->setPalette(palette); +} + +/*! + \since 4.2 + + Sets the \a font used to render tooltips. +*/ +void QToolTip::setFont(const QFont &font) +{ + QApplication::setFont(font, "QTipLabel"); +} + + +/*! + \fn void QToolTip::add(QWidget *widget, const QString &text) + + Use QWidget::setToolTip() instead. + + \oldcode + tip->add(widget, text); + \newcode + widget->setToolTip(text); + \endcode +*/ + +/*! + \fn void QToolTip::add(QWidget *widget, const QRect &rect, const QString &text) + + Intercept the QEvent::ToolTip events in your widget's + QWidget::event() function and call QToolTip::showText() with the + text you want to display. The \l{widgets/tooltips}{Tooltips} + example illustrates this technique. +*/ + +/*! + \fn void QToolTip::remove(QWidget *widget) + + Use QWidget::setToolTip() instead. + + \oldcode + tip->remove(widget); + \newcode + widget->setToolTip(""); + \endcode +*/ + +QT_END_NAMESPACE + +#include "qtooltip.moc" +#endif // QT_NO_TOOLTIP diff --git a/src/widgets/kernel/qtooltip.h b/src/widgets/kernel/qtooltip.h new file mode 100644 index 0000000000..4195f1cb3e --- /dev/null +++ b/src/widgets/kernel/qtooltip.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTOOLTIP_H +#define QTOOLTIP_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_TOOLTIP + +class Q_GUI_EXPORT QToolTip +{ + QToolTip(); +public: + static void showText(const QPoint &pos, const QString &text, QWidget *w = 0); + static void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect); + static inline void hideText() { showText(QPoint(), QString()); } + + static bool isVisible(); + static QString text(); + + static QPalette palette(); + static void setPalette(const QPalette &); + static QFont font(); + static void setFont(const QFont &); +#ifdef QT3_SUPPORT + static inline QT3_SUPPORT void add(QWidget *w, const QString &s) { w->setToolTip(s); } + static inline QT3_SUPPORT void add(QWidget *w, const QRect &, const QString &s) + { w->setToolTip(s); } + static inline QT3_SUPPORT void remove(QWidget *w) { w->setToolTip(QString()); } +#endif +}; + +#endif // QT_NO_TOOLTIP + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTOOLTIP_H diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp new file mode 100644 index 0000000000..5e47ffa56b --- /dev/null +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -0,0 +1,777 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwhatsthis.h" +#ifndef QT_NO_WHATSTHIS +#include "qpointer.h" +#include "qapplication.h" +#include "qdesktopwidget.h" +#include "qevent.h" +#include "qpixmap.h" +#include "qpainter.h" +#include "qtimer.h" +#include "qhash.h" +#include "qaction.h" +#include "qcursor.h" +#include "qbitmap.h" +#include "qtextdocument.h" +#include "../text/qtextdocumentlayout_p.h" +#include "qtoolbutton.h" +#include "qdebug.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif +#if defined(Q_WS_WIN) +#include "qt_windows.h" +#ifndef SPI_GETDROPSHADOW +#define SPI_GETDROPSHADOW 0x1024 +#endif +#endif +#if defined(Q_WS_X11) +#include "qx11info_x11.h" +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QWhatsThis + \brief The QWhatsThis class provides a simple description of any + widget, i.e. answering the question "What's This?". + + \ingroup helpsystem + + + "What's This?" help is part of an application's online help + system, and provides users with information about the + functionality and usage of a particular widget. "What's This?" + help texts are typically longer and more detailed than \link + QToolTip tooltips\endlink, but generally provide less information + than that supplied by separate help windows. + + QWhatsThis provides a single window with an explanatory text that + pops up when the user asks "What's This?". The default way for + users to ask the question is to move the focus to the relevant + widget and press Shift+F1. The help text appears immediately; it + goes away as soon as the user does something else. + (Note that if there is a shortcut for Shift+F1, this mechanism + will not work.) Some dialogs provide a "?" button that users can + click to enter "What's This?" mode; they then click the relevant + widget to pop up the "What's This?" window. It is also possible to + provide a a menu option or toolbar button to switch into "What's + This?" mode. + + To add "What's This?" text to a widget or an action, you simply + call QWidget::setWhatsThis() or QAction::setWhatsThis(). + + The text can be either rich text or plain text. If you specify a + rich text formatted string, it will be rendered using the default + stylesheet, making it possible to embed images in the displayed + text. To be as fast as possible, the default stylesheet uses a + simple method to determine whether the text can be rendered as + plain text. See Qt::mightBeRichText() for details. + + \snippet doc/src/snippets/whatsthis/whatsthis.cpp 0 + + An alternative way to enter "What's This?" mode is to call + createAction(), and add the returned QAction to either a menu or + a tool bar. By invoking this context help action (in the picture + below, the button with the arrow and question mark icon) the user + switches into "What's This?" mode. If they now click on a widget + the appropriate help text is shown. The mode is left when help is + given or when the user presses Esc. + + \img whatsthis.png + + You can enter "What's This?" mode programmatically with + enterWhatsThisMode(), check the mode with inWhatsThisMode(), and + return to normal mode with leaveWhatsThisMode(). + + If you want to control the "What's This?" behavior of a widget + manually see Qt::WA_CustomWhatsThis. + + It is also possible to show different help texts for different + regions of a widget, by using a QHelpEvent of type + QEvent::WhatsThis. Intercept the help event in your widget's + QWidget::event() function and call QWhatsThis::showText() with the + text you want to display for the position specified in + QHelpEvent::pos(). If the text is rich text and the user clicks + on a link, the widget also receives a QWhatsThisClickedEvent with + the link's reference as QWhatsThisClickedEvent::href(). If a + QWhatsThisClickedEvent is handled (i.e. QWidget::event() returns + true), the help window remains visible. Call + QWhatsThis::hideText() to hide it explicitly. + + \sa QToolTip +*/ + +Q_CORE_EXPORT void qDeleteInEventHandler(QObject *o); + +class QWhatsThat : public QWidget +{ + Q_OBJECT + +public: + QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor); + ~QWhatsThat() ; + + static QWhatsThat *instance; + +protected: + void showEvent(QShowEvent *e); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void keyPressEvent(QKeyEvent*); + void paintEvent(QPaintEvent*); + +private: + QPointerwidget; + bool pressed; + QString text; + QTextDocument* doc; + QString anchor; + QPixmap background; +}; + +QWhatsThat *QWhatsThat::instance = 0; + +// shadowWidth not const, for XP drop-shadow-fu turns it to 0 +static int shadowWidth = 6; // also used as '5' and '6' and even '8' below +static const int vMargin = 8; +static const int hMargin = 12; + +QWhatsThat::QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor) + : QWidget(parent, Qt::Popup), + widget(showTextFor), pressed(false), text(txt) +{ + delete instance; + instance = this; + setAttribute(Qt::WA_DeleteOnClose, true); + setAttribute(Qt::WA_NoSystemBackground, true); + if (parent) + setPalette(parent->palette()); + setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); +#ifndef QT_NO_CURSOR + setCursor(Qt::ArrowCursor); +#endif + QRect r; + doc = 0; + ensurePolished(); // Ensures style sheet font before size calc + if (Qt::mightBeRichText(text)) { + doc = new QTextDocument(); + doc->setUndoRedoEnabled(false); + doc->setDefaultFont(QApplication::font(this)); +#ifdef QT_NO_TEXTHTMLPARSER + doc->setPlainText(text); +#else + doc->setHtml(text); +#endif + doc->setUndoRedoEnabled(false); + doc->adjustSize(); + r.setTop(0); + r.setLeft(0); + r.setSize(doc->size().toSize()); + } + else + { + int sw = QApplication::desktop()->width() / 3; + if (sw < 200) + sw = 200; + else if (sw > 300) + sw = 300; + + r = fontMetrics().boundingRect(0, 0, sw, 1000, + Qt::AlignLeft + Qt::AlignTop + + Qt::TextWordWrap + Qt::TextExpandTabs, + text); + } +#if defined(Q_WS_WIN) + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + { + BOOL shadow; + SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow, 0); + shadowWidth = shadow ? 0 : 6; + } +#endif + resize(r.width() + 2*hMargin + shadowWidth, r.height() + 2*vMargin + shadowWidth); +} + +QWhatsThat::~QWhatsThat() +{ + instance = 0; + if (doc) + delete doc; +} + +void QWhatsThat::showEvent(QShowEvent *) +{ + background = QPixmap::grabWindow(QApplication::desktop()->internalWinId(), + x(), y(), width(), height()); +} + +void QWhatsThat::mousePressEvent(QMouseEvent* e) +{ + pressed = true; + if (e->button() == Qt::LeftButton && rect().contains(e->pos())) { + if (doc) + anchor = doc->documentLayout()->anchorAt(e->pos() - QPoint(hMargin, vMargin)); + return; + } + close(); +} + +void QWhatsThat::mouseReleaseEvent(QMouseEvent* e) +{ + if (!pressed) + return; + if (widget && e->button() == Qt::LeftButton && doc && rect().contains(e->pos())) { + QString a = doc->documentLayout()->anchorAt(e->pos() - QPoint(hMargin, vMargin)); + QString href; + if (anchor == a) + href = a; + anchor.clear(); + if (!href.isEmpty()) { + QWhatsThisClickedEvent e(href); + if (QApplication::sendEvent(widget, &e)) + return; + } + } + close(); +} + +void QWhatsThat::mouseMoveEvent(QMouseEvent* e) +{ +#ifdef QT_NO_CURSOR + Q_UNUSED(e); +#else + if (!doc) + return; + QString a = doc->documentLayout()->anchorAt(e->pos() - QPoint(hMargin, vMargin)); + if (!a.isEmpty()) + setCursor(Qt::PointingHandCursor); + else + setCursor(Qt::ArrowCursor); +#endif +} + +void QWhatsThat::keyPressEvent(QKeyEvent*) +{ + close(); +} + +void QWhatsThat::paintEvent(QPaintEvent*) +{ + bool drawShadow = true; +#if defined(Q_WS_WIN) + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + { + BOOL shadow; + SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow, 0); + drawShadow = !shadow; + } +#elif defined(Q_WS_MAC) || defined(Q_WS_QWS) + drawShadow = false; // never draw it on OS X or QWS, as we get it for free +#endif + + QRect r = rect(); + r.adjust(0, 0, -1, -1); + if (drawShadow) + r.adjust(0, 0, -shadowWidth, -shadowWidth); + QPainter p(this); + p.drawPixmap(0, 0, background); + p.setPen(QPen(palette().toolTipText(), 0)); + p.setBrush(palette().toolTipBase()); + p.drawRect(r); + int w = r.width(); + int h = r.height(); + p.setPen(palette().brush(QPalette::Dark).color()); + p.drawRect(1, 1, w-2, h-2); + if (drawShadow) { + p.setPen(palette().shadow().color()); + p.drawPoint(w + 5, 6); + p.drawLine(w + 3, 6, w + 5, 8); + p.drawLine(w + 1, 6, w + 5, 10); + int i; + for(i=7; i < h; i += 2) + p.drawLine(w, i, w + 5, i + 5); + for(i = w - i + h; i > 6; i -= 2) + p.drawLine(i, h, i + 5, h + 5); + for(; i > 0 ; i -= 2) + p.drawLine(6, h + 6 - i, i + 5, h + 5); + } + r.adjust(0, 0, 1, 1); + p.setPen(palette().toolTipText().color()); + r.adjust(hMargin, vMargin, -hMargin, -vMargin); + + if (doc) { + p.translate(r.x(), r.y()); + QRect rect = r; + rect.translate(-r.x(), -r.y()); + p.setClipRect(rect); + QAbstractTextDocumentLayout::PaintContext context; + context.palette.setBrush(QPalette::Text, context.palette.toolTipText()); + doc->documentLayout()->draw(&p, context); + } + else + { + p.drawText(r, Qt::AlignLeft + Qt::AlignTop + Qt::TextWordWrap + Qt::TextExpandTabs, text); + } +} + +static const char * const button_image[] = { +"16 16 3 1", +" c None", +"o c #000000", +"a c #000080", +"o aaaaa ", +"oo aaa aaa ", +"ooo aaa aaa", +"oooo aa aa", +"ooooo aa aa", +"oooooo a aaa", +"ooooooo aaa ", +"oooooooo aaa ", +"ooooooooo aaa ", +"ooooo aaa ", +"oo ooo ", +"o ooo aaa ", +" ooo aaa ", +" ooo ", +" ooo ", +" ooo "}; + +class QWhatsThisPrivate : public QObject +{ + public: + QWhatsThisPrivate(); + ~QWhatsThisPrivate(); + static QWhatsThisPrivate *instance; + bool eventFilter(QObject *, QEvent *); + QPointer action; +#ifdef QT3_SUPPORT + QPointer button; +#endif + static void say(QWidget *, const QString &, int x = 0, int y = 0); + static void notifyToplevels(QEvent *e); + bool leaveOnMouseRelease; +}; + +void QWhatsThisPrivate::notifyToplevels(QEvent *e) +{ + QWidgetList toplevels = QApplication::topLevelWidgets(); + for (int i = 0; i < toplevels.count(); ++i) { + register QWidget *w = toplevels.at(i); + QApplication::sendEvent(w, e); + } +} + +QWhatsThisPrivate *QWhatsThisPrivate::instance = 0; + +QWhatsThisPrivate::QWhatsThisPrivate() + : leaveOnMouseRelease(false) +{ + instance = this; + qApp->installEventFilter(this); + + QPoint pos = QCursor::pos(); + if (QWidget *w = QApplication::widgetAt(pos)) { + QHelpEvent e(QEvent::QueryWhatsThis, w->mapFromGlobal(pos), pos); + bool sentEvent = QApplication::sendEvent(w, &e); +#ifdef QT_NO_CURSOR + Q_UNUSED(sentEvent); +#else + QApplication::setOverrideCursor((!sentEvent || !e.isAccepted())? + Qt::ForbiddenCursor:Qt::WhatsThisCursor); + } else { + QApplication::setOverrideCursor(Qt::WhatsThisCursor); +#endif + } +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(this, 0, QAccessible::ContextHelpStart); +#endif +} + +QWhatsThisPrivate::~QWhatsThisPrivate() +{ + if (action) + action->setChecked(false); +#ifdef QT3_SUPPORT + if (button) + button->setChecked(false); +#endif +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(this, 0, QAccessible::ContextHelpEnd); +#endif + instance = 0; +} + +bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e) +{ + if (!o->isWidgetType()) + return false; + QWidget * w = static_cast(o); + bool customWhatsThis = w->testAttribute(Qt::WA_CustomWhatsThis); + switch (e->type()) { + case QEvent::MouseButtonPress: + { + QMouseEvent *me = static_cast(e); + if (me->button() == Qt::RightButton || customWhatsThis) + return false; + QHelpEvent e(QEvent::WhatsThis, me->pos(), me->globalPos()); + if (!QApplication::sendEvent(w, &e) || !e.isAccepted()) + leaveOnMouseRelease = true; + + } break; + + case QEvent::MouseMove: + { + QMouseEvent *me = static_cast(e); + QHelpEvent e(QEvent::QueryWhatsThis, me->pos(), me->globalPos()); + bool sentEvent = QApplication::sendEvent(w, &e); +#ifdef QT_NO_CURSOR + Q_UNUSED(sentEvent); +#else + QApplication::changeOverrideCursor((!sentEvent || !e.isAccepted())? + Qt::ForbiddenCursor:Qt::WhatsThisCursor); +#endif + } + // fall through + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + if (leaveOnMouseRelease && e->type() == QEvent::MouseButtonRelease) + QWhatsThis::leaveWhatsThisMode(); + if (static_cast(e)->button() == Qt::RightButton || customWhatsThis) + return false; // ignore RMB release + break; + case QEvent::KeyPress: + { + QKeyEvent* kev = (QKeyEvent*)e; + + if (kev->key() == Qt::Key_Escape) { + QWhatsThis::leaveWhatsThisMode(); + return true; + } else if (customWhatsThis) { + return false; + } else if (kev->key() == Qt::Key_Menu || + (kev->key() == Qt::Key_F10 && + kev->modifiers() == Qt::ShiftModifier)) { + // we don't react to these keys, they are used for context menus + return false; + } else if (kev->key() != Qt::Key_Shift && kev->key() != Qt::Key_Alt // not a modifier key + && kev->key() != Qt::Key_Control && kev->key() != Qt::Key_Meta) { + QWhatsThis::leaveWhatsThisMode(); + } + } break; + default: + return false; + } + return true; +} + +class QWhatsThisAction: public QAction +{ + Q_OBJECT + +public: + explicit QWhatsThisAction(QObject* parent = 0); + +private slots: + void actionTriggered(); +}; + +QWhatsThisAction::QWhatsThisAction(QObject *parent) : QAction(tr("What's This?"), parent) +{ +#ifndef QT_NO_IMAGEFORMAT_XPM + QPixmap p((const char**)button_image); + setIcon(p); +#endif + setCheckable(true); + connect(this, SIGNAL(triggered()), this, SLOT(actionTriggered())); +#ifndef QT_NO_SHORTCUT + setShortcut(Qt::ShiftModifier + Qt::Key_F1); +#endif +} + +void QWhatsThisAction::actionTriggered() +{ + if (isChecked()) { + QWhatsThis::enterWhatsThisMode(); + QWhatsThisPrivate::instance->action = this; + } +} + +QWhatsThis::QWhatsThis() +{ +} + +#ifdef QT3_SUPPORT +/*! + \obsolete + + Sets the What's This text \a s for the widget \a w. + + Use QWidget::setWhatsThis() or QAction::setWhatsThis() instead. +*/ +void QWhatsThis::add(QWidget *w, const QString &s) +{ + w->setWhatsThis(s); +} + +/*! + \obsolete + + Remove's the What's This text for the widget \a w. + + Use QWidget::setWhatsThis() or QAction::setWhatsThis() instead. +*/ +void QWhatsThis::remove(QWidget *w) +{ + w->setWhatsThis(QString()); +} + +class QWhatsThisButton : public QToolButton +{ + Q_OBJECT +public: + QWhatsThisButton(QWidget *p) : QToolButton(p) { + setCheckable(true); + QPixmap pix( const_cast(button_image) ); + setIcon( pix ); + QObject::connect(this, SIGNAL(toggled(bool)), this, SLOT(whatToggled(bool))); + setAutoRaise(true); + setFocusPolicy(Qt::NoFocus); + } + +public slots: + void whatToggled(bool b) { + if (b) { + QWhatsThis::enterWhatsThisMode(); + QWhatsThisPrivate::instance->button = this; + } + } +}; + +/*! + Returns a new "What's This?" QToolButton with the given \a + parent. To do this now, create your own QToolButton and a + QWhatsThis object and call the QWhatsThis object's showText() + function when the QToolButton is invoked. + + Use createAction() instead. +*/ +QToolButton * QWhatsThis::whatsThisButton(QWidget * parent) +{ + return new QWhatsThisButton(parent); +} +#endif + +/*! + This function switches the user interface into "What's This?" + mode. The user interface can be switched back into normal mode by + the user (e.g. by them clicking or pressing Esc), or + programmatically by calling leaveWhatsThisMode(). + + When entering "What's This?" mode, a QEvent of type + Qt::EnterWhatsThisMode is sent to all toplevel widgets. + + \sa inWhatsThisMode() leaveWhatsThisMode() +*/ +void QWhatsThis::enterWhatsThisMode() +{ + if (QWhatsThisPrivate::instance) + return; + (void) new QWhatsThisPrivate; + QEvent e(QEvent::EnterWhatsThisMode); + QWhatsThisPrivate::notifyToplevels(&e); + } + +/*! + Returns true if the user interface is in "What's This?" mode; + otherwise returns false. + + \sa enterWhatsThisMode() +*/ +bool QWhatsThis::inWhatsThisMode() +{ + return (QWhatsThisPrivate::instance != 0); +} + +/*! + If the user interface is in "What's This?" mode, this function + switches back to normal mode; otherwise it does nothing. + + When leaving "What's This?" mode, a QEvent of type + Qt::LeaveWhatsThisMode is sent to all toplevel widgets. + + \sa enterWhatsThisMode() inWhatsThisMode() +*/ +void QWhatsThis::leaveWhatsThisMode() +{ + delete QWhatsThisPrivate::instance; + QEvent e(QEvent::LeaveWhatsThisMode); + QWhatsThisPrivate::notifyToplevels(&e); +} + +void QWhatsThisPrivate::say(QWidget * widget, const QString &text, int x, int y) +{ + if (text.size() == 0) + return; + // make a fresh widget, and set it up + QWhatsThat *whatsThat = new QWhatsThat( + text, +#if defined(Q_WS_X11) && !defined(QT_NO_CURSOR) + QApplication::desktop()->screen(widget ? widget->x11Info().screen() : QCursor::x11Screen()), +#else + 0, +#endif + widget + ); + + + // okay, now to find a suitable location + + int scr = (widget ? + QApplication::desktop()->screenNumber(widget) : +#if defined(Q_WS_X11) && !defined(QT_NO_CURSOR) + QCursor::x11Screen() +#else + QApplication::desktop()->screenNumber(QPoint(x,y)) +#endif // Q_WS_X11 + ); + QRect screen = QApplication::desktop()->screenGeometry(scr); + + int w = whatsThat->width(); + int h = whatsThat->height(); + int sx = screen.x(); + int sy = screen.y(); + + // first try locating the widget immediately above/below, + // with nice alignment if possible. + QPoint pos; + if (widget) + pos = widget->mapToGlobal(QPoint(0,0)); + + if (widget && w > widget->width() + 16) + x = pos.x() + widget->width()/2 - w/2; + else + x = x - w/2; + + // squeeze it in if that would result in part of what's this + // being only partially visible + if (x + w + shadowWidth > sx+screen.width()) + x = (widget? (qMin(screen.width(), + pos.x() + widget->width()) + ) : screen.width()) + - w; + + if (x < sx) + x = sx; + + if (widget && h > widget->height() + 16) { + y = pos.y() + widget->height() + 2; // below, two pixels spacing + // what's this is above or below, wherever there's most space + if (y + h + 10 > sy+screen.height()) + y = pos.y() + 2 - shadowWidth - h; // above, overlap + } + y = y + 2; + + // squeeze it in if that would result in part of what's this + // being only partially visible + if (y + h + shadowWidth > sy+screen.height()) + y = (widget ? (qMin(screen.height(), + pos.y() + widget->height()) + ) : screen.height()) + - h; + if (y < sy) + y = sy; + + whatsThat->move(x, y); + whatsThat->show(); + whatsThat->grabKeyboard(); +} + +/*! + Shows \a text as a "What's This?" window, at global position \a + pos. The optional widget argument, \a w, is used to determine the + appropriate screen on multi-head systems. + + \sa hideText() +*/ +void QWhatsThis::showText(const QPoint &pos, const QString &text, QWidget *w) +{ + leaveWhatsThisMode(); + QWhatsThisPrivate::say(w, text, pos.x(), pos.y()); +} + +/*! + If a "What's This?" window is showing, this destroys it. + + \sa showText() +*/ +void QWhatsThis::hideText() +{ + qDeleteInEventHandler(QWhatsThat::instance); +} + +/*! + Returns a ready-made QAction, used to invoke "What's This?" context + help, with the given \a parent. + + The returned QAction provides a convenient way to let users enter + "What's This?" mode. +*/ +QAction *QWhatsThis::createAction(QObject *parent) +{ + return new QWhatsThisAction(parent); +} + +QT_END_NAMESPACE + +#include "qwhatsthis.moc" + +#endif // QT_NO_WHATSTHIS diff --git a/src/widgets/kernel/qwhatsthis.h b/src/widgets/kernel/qwhatsthis.h new file mode 100644 index 0000000000..c2e396d0d0 --- /dev/null +++ b/src/widgets/kernel/qwhatsthis.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWHATSTHIS_H +#define QWHATSTHIS_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_WHATSTHIS + +class QAction; +#ifdef QT3_SUPPORT +class QToolButton; +#endif + +class Q_GUI_EXPORT QWhatsThis +{ + QWhatsThis(); + +public: + static void enterWhatsThisMode(); + static bool inWhatsThisMode(); + static void leaveWhatsThisMode(); + + static void showText(const QPoint &pos, const QString &text, QWidget *w = 0); + static void hideText(); + + static QAction *createAction(QObject *parent = 0); + +#ifdef QT3_SUPPORT + static QT3_SUPPORT void add(QWidget *w, const QString &s); + static QT3_SUPPORT void remove(QWidget *); + static QT3_SUPPORT QToolButton *whatsThisButton(QWidget *parent); +#endif +}; + +#endif // QT_NO_WHATSTHIS + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QWHATSTHIS_H diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp new file mode 100644 index 0000000000..b6e6a56f4a --- /dev/null +++ b/src/widgets/kernel/qwidget.cpp @@ -0,0 +1,12677 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qapplication_p.h" +#include "qbrush.h" +#include "qcursor.h" +#include "qdesktopwidget.h" +#include "qevent.h" +#include "qhash.h" +#include "qlayout.h" +#include "qmenu.h" +#include "qmetaobject.h" +#include "qpixmap.h" +#include "qpointer.h" +#include "qstack.h" +#include "qstyle.h" +#include "qstylefactory.h" +#include "qvariant.h" +#include "qwidget.h" +#include "qstyleoption.h" +#ifndef QT_NO_ACCESSIBILITY +# include "qaccessible.h" +#endif +#if defined(Q_WS_WIN) +# include "qt_windows.h" +#endif +#ifdef Q_WS_MAC +# include "qt_mac_p.h" +# include "qt_cocoa_helpers_mac_p.h" +# include "qmainwindow.h" +# include "qtoolbar.h" +# include +#endif +#if defined(Q_WS_QWS) +# include "qwsdisplay_qws.h" +# include "qwsmanager_qws.h" +# include "qpaintengine.h" // for PorterDuff +# include "private/qwindowsurface_qws_p.h" +#endif +#if defined(Q_WS_QPA) +#include "qplatformwindow_qpa.h" +#include "private/qwidgetwindow_qpa_p.h" +#endif +#include "qpainter.h" +#include "qtooltip.h" +#include "qwhatsthis.h" +#include "qdebug.h" +#include "private/qstylesheetstyle_p.h" +#include "private/qstyle_p.h" +#include "private/qinputcontext_p.h" +#include "qfileinfo.h" +#include "private/qsoftkeymanager_p.h" + +#if defined (Q_WS_WIN) +# include +#endif + +#if defined(Q_WS_X11) +# include +# include "qx11info_x11.h" +#endif + +#include +#include +#include +#ifdef Q_WS_MAC +# include +#endif +#include + +#if defined(Q_OS_SYMBIAN) +#include "private/qt_s60_p.h" +#endif + +#include "qwidget_p.h" +#include "qaction_p.h" +#include "qlayout_p.h" +#include "QtGui/qgraphicsproxywidget.h" +#include "QtGui/qgraphicsscene.h" +#include "private/qgraphicsproxywidget_p.h" +#include "QtGui/qabstractscrollarea.h" +#include "private/qabstractscrollarea_p.h" +#include "private/qevent_p.h" + +#include "private/qgesturemanager_p.h" + +#ifdef QT_KEYPAD_NAVIGATION +#include "qtabwidget.h" // Needed in inTabWidget() +#endif // QT_KEYPAD_NAVIGATION + +#ifdef Q_WS_S60 +#include +#endif + +// widget/widget data creation count +//#define QWIDGET_EXTRA_DEBUG +//#define ALIEN_DEBUG + +QT_BEGIN_NAMESPACE + +#if !defined(Q_WS_QWS) +static bool qt_enable_backingstore = true; +#endif +#ifdef Q_WS_X11 +// for compatibility with Qt 4.0 +Q_GUI_EXPORT void qt_x11_set_global_double_buffer(bool enable) +{ + qt_enable_backingstore = enable; +} +#endif + +#if defined(QT_MAC_USE_COCOA) +bool qt_mac_clearDirtyOnWidgetInsideDrawWidget = false; +#endif + +static inline bool qRectIntersects(const QRect &r1, const QRect &r2) +{ + return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) && + qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); +} + +static inline bool hasBackingStoreSupport() +{ + return true; +} + +#ifdef Q_WS_MAC +# define QT_NO_PAINT_DEBUG +#endif + +extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp +extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp + +/*! + \internal + \class QWidgetBackingStoreTracker + \brief Class which allows tracking of which widgets are using a given backing store + + QWidgetBackingStoreTracker is a thin wrapper around a QWidgetBackingStore pointer, + which maintains a list of the QWidgets which are currently using the backing + store. This list is modified via the registerWidget and unregisterWidget functions. + */ + +QWidgetBackingStoreTracker::QWidgetBackingStoreTracker() + : m_ptr(0) +{ + +} + +QWidgetBackingStoreTracker::~QWidgetBackingStoreTracker() +{ + delete m_ptr; +} + +/*! + \internal + Destroy the contained QWidgetBackingStore, if not null, and clear the list of + widgets using the backing store, then create a new QWidgetBackingStore, providing + the QWidget. + */ +void QWidgetBackingStoreTracker::create(QWidget *widget) +{ + destroy(); + m_ptr = new QWidgetBackingStore(widget); +} + +/*! + \internal + Destroy the contained QWidgetBackingStore, if not null, and clear the list of + widgets using the backing store. + */ +void QWidgetBackingStoreTracker::destroy() +{ + delete m_ptr; + m_ptr = 0; + m_widgets.clear(); +} + +/*! + \internal + Add the widget to the list of widgets currently using the backing store. + If the widget was already in the list, this function is a no-op. + */ +void QWidgetBackingStoreTracker::registerWidget(QWidget *w) +{ + Q_ASSERT(m_ptr); + Q_ASSERT(w->internalWinId()); + Q_ASSERT(qt_widget_private(w)->maybeBackingStore() == m_ptr); + m_widgets.insert(w); +} + +/*! + \internal + Remove the widget from the list of widgets currently using the backing store. + If the widget was in the list, and removing it causes the list to be empty, + the backing store is deleted. + If the widget was not in the list, this function is a no-op. + */ +void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w) +{ + if (m_widgets.remove(w) && m_widgets.isEmpty()) { + delete m_ptr; + m_ptr = 0; + } +} + +/*! + \internal + Recursively remove widget and all of its descendents. + */ +void QWidgetBackingStoreTracker::unregisterWidgetSubtree(QWidget *widget) +{ + unregisterWidget(widget); + foreach (QObject *child, widget->children()) + if (QWidget *childWidget = qobject_cast(child)) + unregisterWidgetSubtree(childWidget); +} + +QWidgetPrivate::QWidgetPrivate(int version) + : QObjectPrivate(version) + , extra(0) + , focus_next(0) + , focus_prev(0) + , focus_child(0) + , layout(0) + , needsFlush(0) + , redirectDev(0) + , widgetItem(0) + , extraPaintEngine(0) + , polished(0) + , graphicsEffect(0) +#if !defined(QT_NO_IM) + , imHints(Qt::ImhNone) +#endif + , inheritedFontResolveMask(0) + , inheritedPaletteResolveMask(0) + , leftmargin(0) + , topmargin(0) + , rightmargin(0) + , bottommargin(0) + , leftLayoutItemMargin(0) + , topLayoutItemMargin(0) + , rightLayoutItemMargin(0) + , bottomLayoutItemMargin(0) + , hd(0) + , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) + , fg_role(QPalette::NoRole) + , bg_role(QPalette::NoRole) + , dirtyOpaqueChildren(1) + , isOpaque(0) + , inDirtyList(0) + , isScrolled(0) + , isMoved(0) + , isGLWidget(0) + , usesDoubleBufferedGLContext(0) +#ifndef QT_NO_IM + , inheritsInputMethodHints(0) +#endif +#if defined(Q_WS_X11) + , picture(0) +#elif defined(Q_WS_WIN) + , noPaintOnScreen(0) + #ifndef QT_NO_GESTURES + , nativeGesturePanEnabled(0) + #endif +#elif defined(Q_WS_MAC) + , needWindowChange(0) + , window_event(0) + , qd_hd(0) +#elif defined(Q_OS_SYMBIAN) + , symbianScreenNumber(0) + , fixNativeOrientationCalled(false) +#endif +{ + if (!qApp) { + qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); + return; + } + + if (version != QObjectPrivateVersion) + qFatal("Cannot mix incompatible Qt libraries"); + + isWidget = true; + memset(high_attributes, 0, sizeof(high_attributes)); +#if QT_MAC_USE_COCOA + drawRectOriginalAdded = false; + originalDrawMethod = true; + changeMethods = false; + isInUnifiedToolbar = false; + unifiedSurface = 0; + toolbar_ancestor = 0; + flushRequested = false; + touchEventsEnabled = false; +#endif // QT_MAC_USE_COCOA +#ifdef QWIDGET_EXTRA_DEBUG + static int count = 0; + qDebug() << "widgets" << ++count; +#endif +} + + +QWidgetPrivate::~QWidgetPrivate() +{ + if (widgetItem) + widgetItem->wid = 0; + + if (extra) + deleteExtra(); + +#ifndef QT_NO_GRAPHICSEFFECT + delete graphicsEffect; +#endif //QT_NO_GRAPHICSEFFECT +} + +class QDummyWindowSurface : public QWindowSurface +{ +public: + QDummyWindowSurface(QWindow *window) : QWindowSurface(window) {} + QPaintDevice *paintDevice() { return static_cast(window())->widget(); } + void flush(QWindow *, const QRegion &, const QPoint &) {} +}; + +QWindowSurface *QWidgetPrivate::createDefaultWindowSurface() +{ + Q_Q(QWidget); + + QWindowSurface *surface; +#ifndef QT_NO_PROPERTIES + if (q->property("_q_DummyWindowSurface").toBool()) { + surface = new QDummyWindowSurface(q->windowHandle()); + } else +#endif + { + QWindow *win = topData()->window; + surface = QGuiApplicationPrivate::platformIntegration()->createWindowSurface(win, win->winId()); + } + + return surface; +} + +/*! + \internal +*/ +void QWidgetPrivate::scrollChildren(int dx, int dy) +{ + Q_Q(QWidget); + if (q->children().size() > 0) { // scroll children + QPoint pd(dx, dy); + QObjectList childObjects = q->children(); + for (int i = 0; i < childObjects.size(); ++i) { // move all children + QWidget *w = qobject_cast(childObjects.at(i)); + if (w && !w->isWindow()) { + QPoint oldp = w->pos(); + QRect r(w->pos() + pd, w->size()); + w->data->crect = r; +#ifndef Q_WS_QWS + if (w->testAttribute(Qt::WA_WState_Created)) + w->d_func()->setWSGeometry(); +#endif + w->d_func()->setDirtyOpaqueRegion(); + QMoveEvent e(r.topLeft(), oldp); + QApplication::sendEvent(w, &e); + } + } + } +} + +QInputContext *QWidgetPrivate::assignedInputContext() const +{ +#ifndef QT_NO_IM + const QWidget *widget = q_func(); + while (widget) { + if (QInputContext *qic = widget->d_func()->ic) + return qic; + widget = widget->parentWidget(); + } +#endif + return 0; +} + +QInputContext *QWidgetPrivate::inputContext() const +{ +#ifndef QT_NO_IM + if (QInputContext *qic = assignedInputContext()) + return qic; + return qApp->inputContext(); +#else + return 0; +#endif +} + +/*! + This function returns the QInputContext for this widget. By + default the input context is inherited from the widgets + parent. For toplevels it is inherited from QApplication. + + You can override this and set a special input context for this + widget by using the setInputContext() method. + + \sa setInputContext() +*/ +QInputContext *QWidget::inputContext() +{ + Q_D(QWidget); + if (!testAttribute(Qt::WA_InputMethodEnabled)) + return 0; + + return d->inputContext(); +} + +/*! + This function sets the input context \a context + on this widget. + + Qt takes ownership of the given input \a context. + + \sa inputContext() +*/ +void QWidget::setInputContext(QInputContext *context) +{ + Q_D(QWidget); + if (!testAttribute(Qt::WA_InputMethodEnabled)) + return; +#ifndef QT_NO_IM + if (context == d->ic) + return; + if (d->ic) + delete d->ic; + d->ic = context; + if (d->ic) + d->ic->setParent(this); +#endif +} + + +/*! + \obsolete + + This function can be called on the widget that currently has focus + to reset the input method operating on it. + + This function is providing for convenience, instead you should use + \l{QInputContext::}{reset()} on the input context that was + returned by inputContext(). + + \sa QInputContext, inputContext(), QInputContext::reset() +*/ +void QWidget::resetInputContext() +{ + if (!hasFocus()) + return; +#ifndef QT_NO_IM + QInputContext *qic = this->inputContext(); + if(qic) + qic->reset(); +#endif // QT_NO_IM +} + +#ifdef QT_KEYPAD_NAVIGATION +QPointer QWidgetPrivate::editingWidget; + +/*! + Returns true if this widget currently has edit focus; otherwise false. + + This feature is only available in Qt for Embedded Linux. + + \sa setEditFocus(), QApplication::keypadNavigationEnabled() +*/ +bool QWidget::hasEditFocus() const +{ + const QWidget* w = this; + while (w->d_func()->extra && w->d_func()->extra->focus_proxy) + w = w->d_func()->extra->focus_proxy; + return QWidgetPrivate::editingWidget == w; +} + +/*! + \fn void QWidget::setEditFocus(bool enable) + + If \a enable is true, make this widget have edit focus, in which + case Qt::Key_Up and Qt::Key_Down will be delivered to the widget + normally; otherwise, Qt::Key_Up and Qt::Key_Down are used to + change focus. + + This feature is only available in Qt for Embedded Linux and Qt + for Symbian. + + \sa hasEditFocus(), QApplication::keypadNavigationEnabled() +*/ +void QWidget::setEditFocus(bool on) +{ + QWidget *f = this; + while (f->d_func()->extra && f->d_func()->extra->focus_proxy) + f = f->d_func()->extra->focus_proxy; + + if (QWidgetPrivate::editingWidget && QWidgetPrivate::editingWidget != f) + QWidgetPrivate::editingWidget->setEditFocus(false); + + if (on && !f->hasFocus()) + f->setFocus(); + + if ((!on && !QWidgetPrivate::editingWidget) + || (on && QWidgetPrivate::editingWidget == f)) { + return; + } + + if (!on && QWidgetPrivate::editingWidget == f) { + QWidgetPrivate::editingWidget = 0; + QEvent event(QEvent::LeaveEditFocus); + QApplication::sendEvent(f, &event); + QApplication::sendEvent(f->style(), &event); + } else if (on) { + QWidgetPrivate::editingWidget = f; + QEvent event(QEvent::EnterEditFocus); + QApplication::sendEvent(f, &event); + QApplication::sendEvent(f->style(), &event); + } +} +#endif + +/*! + \property QWidget::autoFillBackground + \brief whether the widget background is filled automatically + \since 4.1 + + If enabled, this property will cause Qt to fill the background of the + widget before invoking the paint event. The color used is defined by the + QPalette::Window color role from the widget's \l{QPalette}{palette}. + + In addition, Windows are always filled with QPalette::Window, unless the + WA_OpaquePaintEvent or WA_NoSystemBackground attributes are set. + + This property cannot be turned off (i.e., set to false) if a widget's + parent has a static gradient for its background. + + \warning Use this property with caution in conjunction with + \l{Qt Style Sheets}. When a widget has a style sheet with a valid + background or a border-image, this property is automatically disabled. + + By default, this property is false. + + \sa Qt::WA_OpaquePaintEvent, Qt::WA_NoSystemBackground, + {QWidget#Transparency and Double Buffering}{Transparency and Double Buffering} +*/ +bool QWidget::autoFillBackground() const +{ + Q_D(const QWidget); + return d->extra && d->extra->autoFillBackground; +} + +void QWidget::setAutoFillBackground(bool enabled) +{ + Q_D(QWidget); + if (!d->extra) + d->createExtra(); + if (d->extra->autoFillBackground == enabled) + return; + + d->extra->autoFillBackground = enabled; + d->updateIsOpaque(); + update(); + d->updateIsOpaque(); +} + +/*! + \class QWidget + \brief The QWidget class is the base class of all user interface objects. + + \ingroup basicwidgets + + The widget is the atom of the user interface: it receives mouse, keyboard + and other events from the window system, and paints a representation of + itself on the screen. Every widget is rectangular, and they are sorted in a + Z-order. A widget is clipped by its parent and by the widgets in front of + it. + + A widget that is not embedded in a parent widget is called a window. + Usually, windows have a frame and a title bar, although it is also possible + to create windows without such decoration using suitable + \l{Qt::WindowFlags}{window flags}). In Qt, QMainWindow and the various + subclasses of QDialog are the most common window types. + + Every widget's constructor accepts one or two standard arguments: + + \list 1 + \i \c{QWidget *parent = 0} is the parent of the new widget. If it is 0 + (the default), the new widget will be a window. If not, it will be + a child of \e parent, and be constrained by \e parent's geometry + (unless you specify Qt::Window as window flag). + \i \c{Qt::WindowFlags f = 0} (where available) sets the window flags; + the default is suitable for almost all widgets, but to get, for + example, a window without a window system frame, you must use + special flags. + \endlist + + QWidget has many member functions, but some of them have little direct + functionality; for example, QWidget has a font property, but never uses + this itself. There are many subclasses which provide real functionality, + such as QLabel, QPushButton, QListWidget, and QTabWidget. + + + \section1 Top-Level and Child Widgets + + A widget without a parent widget is always an independent window (top-level + widget). For these widgets, setWindowTitle() and setWindowIcon() set the + title bar and icon respectively. + + Non-window widgets are child widgets, displayed within their parent + widgets. Most widgets in Qt are mainly useful as child widgets. For + example, it is possible to display a button as a top-level window, but most + people prefer to put their buttons inside other widgets, such as QDialog. + + \image parent-child-widgets.png A parent widget containing various child widgets. + + The diagram above shows a QGroupBox widget being used to hold various child + widgets in a layout provided by QGridLayout. The QLabel child widgets have + been outlined to indicate their full sizes. + + If you want to use a QWidget to hold child widgets you will usually want to + add a layout to the parent QWidget. See \l{Layout Management} for more + information. + + + \section1 Composite Widgets + + When a widget is used as a container to group a number of child widgets, it + is known as a composite widget. These can be created by constructing a + widget with the required visual properties - a QFrame, for example - and + adding child widgets to it, usually managed by a layout. The above diagram + shows such a composite widget that was created using \l{Qt Designer}. + + Composite widgets can also be created by subclassing a standard widget, + such as QWidget or QFrame, and adding the necessary layout and child + widgets in the constructor of the subclass. Many of the \l{Qt Examples} + {examples provided with Qt} use this approach, and it is also covered in + the Qt \l{Tutorials}. + + + \section1 Custom Widgets and Painting + + Since QWidget is a subclass of QPaintDevice, subclasses can be used to + display custom content that is composed using a series of painting + operations with an instance of the QPainter class. This approach contrasts + with the canvas-style approach used by the \l{Graphics View} + {Graphics View Framework} where items are added to a scene by the + application and are rendered by the framework itself. + + Each widget performs all painting operations from within its paintEvent() + function. This is called whenever the widget needs to be redrawn, either + as a result of some external change or when requested by the application. + + The \l{widgets/analogclock}{Analog Clock example} shows how a simple widget + can handle paint events. + + + \section1 Size Hints and Size Policies + + When implementing a new widget, it is almost always useful to reimplement + sizeHint() to provide a reasonable default size for the widget and to set + the correct size policy with setSizePolicy(). + + By default, composite widgets which do not provide a size hint will be + sized according to the space requirements of their child widgets. + + The size policy lets you supply good default behavior for the layout + management system, so that other widgets can contain and manage yours + easily. The default size policy indicates that the size hint represents + the preferred size of the widget, and this is often good enough for many + widgets. + + \note The size of top-level widgets are constrained to 2/3 of the desktop's + height and width. You can resize() the widget manually if these bounds are + inadequate. + + + \section1 Events + + Widgets respond to events that are typically caused by user actions. Qt + delivers events to widgets by calling specific event handler functions with + instances of QEvent subclasses containing information about each event. + + If your widget only contains child widgets, you probably do not need to + implement any event handlers. If you want to detect a mouse click in a + child widget call the child's underMouse() function inside the widget's + mousePressEvent(). + + The \l{widgets/scribble}{Scribble example} implements a wider set of + events to handle mouse movement, button presses, and window resizing. + + You will need to supply the behavior and content for your own widgets, but + here is a brief overview of the events that are relevant to QWidget, + starting with the most common ones: + + \list + \i paintEvent() is called whenever the widget needs to be repainted. + Every widget displaying custom content must implement it. Painting + using a QPainter can only take place in a paintEvent() or a + function called by a paintEvent(). + \i resizeEvent() is called when the widget has been resized. + \i mousePressEvent() is called when a mouse button is pressed while + the mouse cursor is inside the widget, or when the widget has + grabbed the mouse using grabMouse(). Pressing the mouse without + releasing it is effectively the same as calling grabMouse(). + \i mouseReleaseEvent() is called when a mouse button is released. A + widget receives mouse release events when it has received the + corresponding mouse press event. This means that if the user + presses the mouse inside \e your widget, then drags the mouse + somewhere else before releasing the mouse button, \e your widget + receives the release event. There is one exception: if a popup menu + appears while the mouse button is held down, this popup immediately + steals the mouse events. + \i mouseDoubleClickEvent() is called when the user double-clicks in + the widget. If the user double-clicks, the widget receives a mouse + press event, a mouse release event and finally this event instead + of a second mouse press event. (Some mouse move events may also be + received if the mouse is not held steady during this operation.) It + is \e{not possible} to distinguish a click from a double-click + until the second click arrives. (This is one reason why most GUI + books recommend that double-clicks be an extension of + single-clicks, rather than trigger a different action.) + \endlist + + Widgets that accept keyboard input need to reimplement a few more event + handlers: + + \list + \i keyPressEvent() is called whenever a key is pressed, and again when + a key has been held down long enough for it to auto-repeat. The + \key Tab and \key Shift+Tab keys are only passed to the widget if + they are not used by the focus-change mechanisms. To force those + keys to be processed by your widget, you must reimplement + QWidget::event(). + \i focusInEvent() is called when the widget gains keyboard focus + (assuming you have called setFocusPolicy()). Well-behaved widgets + indicate that they own the keyboard focus in a clear but discreet + way. + \i focusOutEvent() is called when the widget loses keyboard focus. + \endlist + + You may be required to also reimplement some of the less common event + handlers: + + \list + \i mouseMoveEvent() is called whenever the mouse moves while a mouse + button is held down. This can be useful during drag and drop + operations. If you call \l{setMouseTracking()}{setMouseTracking}(true), + you get mouse move events even when no buttons are held down. + (See also the \l{Drag and Drop} guide.) + \i keyReleaseEvent() is called whenever a key is released and while it + is held down (if the key is auto-repeating). In that case, the + widget will receive a pair of key release and key press event for + every repeat. The \key Tab and \key Shift+Tab keys are only passed + to the widget if they are not used by the focus-change mechanisms. + To force those keys to be processed by your widget, you must + reimplement QWidget::event(). + \i wheelEvent() is called whenever the user turns the mouse wheel + while the widget has the focus. + \i enterEvent() is called when the mouse enters the widget's screen + space. (This excludes screen space owned by any of the widget's + children.) + \i leaveEvent() is called when the mouse leaves the widget's screen + space. If the mouse enters a child widget it will not cause a + leaveEvent(). + \i moveEvent() is called when the widget has been moved relative to + its parent. + \i closeEvent() is called when the user closes the widget (or when + close() is called). + \endlist + + There are also some rather obscure events described in the documentation + for QEvent::Type. To handle these events, you need to reimplement event() + directly. + + The default implementation of event() handles \key Tab and \key Shift+Tab + (to move the keyboard focus), and passes on most of the other events to + one of the more specialized handlers above. + + Events and the mechanism used to deliver them are covered in + \l{The Event System}. + + \section1 Groups of Functions and Properties + + \table + \header \i Context \i Functions and Properties + + \row \i Window functions \i + show(), + hide(), + raise(), + lower(), + close(). + + \row \i Top-level windows \i + \l windowModified, \l windowTitle, \l windowIcon, \l windowIconText, + \l isActiveWindow, activateWindow(), \l minimized, showMinimized(), + \l maximized, showMaximized(), \l fullScreen, showFullScreen(), + showNormal(). + + \row \i Window contents \i + update(), + repaint(), + scroll(). + + \row \i Geometry \i + \l pos, x(), y(), \l rect, \l size, width(), height(), move(), resize(), + \l sizePolicy, sizeHint(), minimumSizeHint(), + updateGeometry(), layout(), + \l frameGeometry, \l geometry, \l childrenRect, \l childrenRegion, + adjustSize(), + mapFromGlobal(), mapToGlobal(), + mapFromParent(), mapToParent(), + \l maximumSize, \l minimumSize, \l sizeIncrement, + \l baseSize, setFixedSize() + + \row \i Mode \i + \l visible, isVisibleTo(), + \l enabled, isEnabledTo(), + \l modal, + isWindow(), + \l mouseTracking, + \l updatesEnabled, + visibleRegion(). + + \row \i Look and feel \i + style(), + setStyle(), + \l styleSheet, + \l cursor, + \l font, + \l palette, + backgroundRole(), setBackgroundRole(), + fontInfo(), fontMetrics(). + + \row \i Keyboard focus functions \i + \l focus, \l focusPolicy, + setFocus(), clearFocus(), setTabOrder(), setFocusProxy(), + focusNextChild(), focusPreviousChild(). + + \row \i Mouse and keyboard grabbing \i + grabMouse(), releaseMouse(), + grabKeyboard(), releaseKeyboard(), + mouseGrabber(), keyboardGrabber(). + + \row \i Event handlers \i + event(), + mousePressEvent(), + mouseReleaseEvent(), + mouseDoubleClickEvent(), + mouseMoveEvent(), + keyPressEvent(), + keyReleaseEvent(), + focusInEvent(), + focusOutEvent(), + wheelEvent(), + enterEvent(), + leaveEvent(), + paintEvent(), + moveEvent(), + resizeEvent(), + closeEvent(), + dragEnterEvent(), + dragMoveEvent(), + dragLeaveEvent(), + dropEvent(), + childEvent(), + showEvent(), + hideEvent(), + customEvent(). + changeEvent(), + + \row \i System functions \i + parentWidget(), window(), setParent(), winId(), + find(), metric(). + + \row \i Interactive help \i + setToolTip(), setWhatsThis() + + \endtable + + + \section1 Widget Style Sheets + + In addition to the standard widget styles for each platform, widgets can + also be styled according to rules specified in a \l{styleSheet} + {style sheet}. This feature enables you to customize the appearance of + specific widgets to provide visual cues to users about their purpose. For + example, a button could be styled in a particular way to indicate that it + performs a destructive action. + + The use of widget style sheets is described in more detail in the + \l{Qt Style Sheets} document. + + + \section1 Transparency and Double Buffering + + Since Qt 4.0, QWidget automatically double-buffers its painting, so there + is no need to write double-buffering code in paintEvent() to avoid + flicker. + + Since Qt 4.1, the Qt::WA_ContentsPropagated widget attribute has been + deprecated. Instead, the contents of parent widgets are propagated by + default to each of their children as long as Qt::WA_PaintOnScreen is not + set. Custom widgets can be written to take advantage of this feature by + updating irregular regions (to create non-rectangular child widgets), or + painting with colors that have less than full alpha component. The + following diagram shows how attributes and properties of a custom widget + can be fine-tuned to achieve different effects. + + \image propagation-custom.png + + In the above diagram, a semi-transparent rectangular child widget with an + area removed is constructed and added to a parent widget (a QLabel showing + a pixmap). Then, different properties and widget attributes are set to + achieve different effects: + + \list + \i The left widget has no additional properties or widget attributes + set. This default state suits most custom widgets using + transparency, are irregularly-shaped, or do not paint over their + entire area with an opaque brush. + \i The center widget has the \l autoFillBackground property set. This + property is used with custom widgets that rely on the widget to + supply a default background, and do not paint over their entire + area with an opaque brush. + \i The right widget has the Qt::WA_OpaquePaintEvent widget attribute + set. This indicates that the widget will paint over its entire area + with opaque colors. The widget's area will initially be + \e{uninitialized}, represented in the diagram with a red diagonal + grid pattern that shines through the overpainted area. The + Qt::WA_OpaquePaintArea attribute is useful for widgets that need to + paint their own specialized contents quickly and do not need a + default filled background. + \endlist + + To rapidly update custom widgets with simple background colors, such as + real-time plotting or graphing widgets, it is better to define a suitable + background color (using setBackgroundRole() with the + QPalette::Window role), set the \l autoFillBackground property, and only + implement the necessary drawing functionality in the widget's paintEvent(). + + To rapidly update custom widgets that constantly paint over their entire + areas with opaque content, e.g., video streaming widgets, it is better to + set the widget's Qt::WA_OpaquePaintEvent, avoiding any unnecessary overhead + associated with repainting the widget's background. + + If a widget has both the Qt::WA_OpaquePaintEvent widget attribute \e{and} + the \l autoFillBackground property set, the Qt::WA_OpaquePaintEvent + attribute takes precedence. Depending on your requirements, you should + choose either one of them. + + Since Qt 4.1, the contents of parent widgets are also propagated to + standard Qt widgets. This can lead to some unexpected results if the + parent widget is decorated in a non-standard way, as shown in the diagram + below. + + \image propagation-standard.png + + The scope for customizing the painting behavior of standard Qt widgets, + without resorting to subclassing, is slightly less than that possible for + custom widgets. Usually, the desired appearance of a standard widget can be + achieved by setting its \l autoFillBackground property. + + + \section1 Creating Translucent Windows + + Since Qt 4.5, it has been possible to create windows with translucent regions + on window systems that support compositing. + + To enable this feature in a top-level widget, set its Qt::WA_TranslucentBackground + attribute with setAttribute() and ensure that its background is painted with + non-opaque colors in the regions you want to be partially transparent. + + Platform notes: + + \list + \o X11: This feature relies on the use of an X server that supports ARGB visuals + and a compositing window manager. + \o Windows: The widget needs to have the Qt::FramelessWindowHint window flag set + for the translucency to work. + \endlist + + + \section1 Native Widgets vs Alien Widgets + + Introduced in Qt 4.4, alien widgets are widgets unknown to the windowing + system. They do not have a native window handle associated with them. This + feature significantly speeds up widget painting, resizing, and removes flicker. + + Should you require the old behavior with native windows, you can choose + one of the following options: + + \list 1 + \i Use the \c{QT_USE_NATIVE_WINDOWS=1} in your environment. + \i Set the Qt::AA_NativeWindows attribute on your application. All + widgets will be native widgets. + \i Set the Qt::WA_NativeWindow attribute on widgets: The widget itself + and all of its ancestors will become native (unless + Qt::WA_DontCreateNativeAncestors is set). + \i Call QWidget::winId to enforce a native window (this implies 3). + \i Set the Qt::WA_PaintOnScreen attribute to enforce a native window + (this implies 3). + \endlist + + \sa QEvent, QPainter, QGridLayout, QBoxLayout + + \section1 Softkeys + + Since Qt 4.6, Softkeys are usually physical keys on a device that have a corresponding label or + other visual representation on the screen that is generally located next to its + physical counterpart. They are most often found on mobile phone platforms. In + modern touch based user interfaces it is also possible to have softkeys that do + not correspond to any physical keys. Softkeys differ from other onscreen labels + in that they are contextual. + + In Qt, contextual softkeys are added to a widget by calling addAction() and + passing a \c QAction with a softkey role set on it. When the widget + containing the softkey actions has focus, its softkeys should appear in + the user interface. Softkeys are discovered by traversing the widget + hierarchy so it is possible to define a single set of softkeys that are + present at all times by calling addAction() for a given top level widget. + + On some platforms, this concept overlaps with \c QMenuBar such that if no + other softkeys are found and the top level widget is a QMainWindow containing + a QMenuBar, the menubar actions may appear on one of the softkeys. + + Note: Currently softkeys are only supported on the Symbian Platform. + + \sa addAction(), QAction, QMenuBar + +*/ + +QWidgetMapper *QWidgetPrivate::mapper = 0; // widget with wid +QWidgetSet *QWidgetPrivate::allWidgets = 0; // widgets with no wid + + +/***************************************************************************** + QWidget utility functions + *****************************************************************************/ + +QRegion qt_dirtyRegion(QWidget *widget) +{ + if (!widget) + return QRegion(); + + QWidgetBackingStore *bs = qt_widget_private(widget)->maybeBackingStore(); + if (!bs) + return QRegion(); + + return bs->dirtyRegion(widget); +} + +/***************************************************************************** + QWidget member functions + *****************************************************************************/ + +/* + Widget state flags: + \list + \i Qt::WA_WState_Created The widget has a valid winId(). + \i Qt::WA_WState_Visible The widget is currently visible. + \i Qt::WA_WState_Hidden The widget is hidden, i.e. it won't + become visible unless you call show() on it. Qt::WA_WState_Hidden + implies !Qt::WA_WState_Visible. + \i Qt::WA_WState_CompressKeys Compress keyboard events. + \i Qt::WA_WState_BlockUpdates Repaints and updates are disabled. + \i Qt::WA_WState_InPaintEvent Currently processing a paint event. + \i Qt::WA_WState_Reparented The widget has been reparented. + \i Qt::WA_WState_ConfigPending A configuration (resize/move) event is pending. + \i Qt::WA_WState_DND (Deprecated) The widget supports drag and drop, see setAcceptDrops(). + \endlist +*/ + +struct QWidgetExceptionCleaner +{ + /* this cleans up when the constructor throws an exception */ + static inline void cleanup(QWidget *that, QWidgetPrivate *d) + { +#ifdef QT_NO_EXCEPTIONS + Q_UNUSED(that); + Q_UNUSED(d); +#else + QWidgetPrivate::allWidgets->remove(that); + if (d->focus_next != that) { + if (d->focus_next) + d->focus_next->d_func()->focus_prev = d->focus_prev; + if (d->focus_prev) + d->focus_prev->d_func()->focus_next = d->focus_next; + } +#endif + } +}; + +/*! + Constructs a widget which is a child of \a parent, with widget + flags set to \a f. + + If \a parent is 0, the new widget becomes a window. If + \a parent is another widget, this widget becomes a child window + inside \a parent. The new widget is deleted when its \a parent is + deleted. + + The widget flags argument, \a f, is normally 0, but it can be set + to customize the frame of a window (i.e. \a + parent must be 0). To customize the frame, use a value composed + from the bitwise OR of any of the \l{Qt::WindowFlags}{window flags}. + + If you add a child widget to an already visible widget you must + explicitly show the child to make it visible. + + Note that the X11 version of Qt may not be able to deliver all + combinations of style flags on all systems. This is because on + X11, Qt can only ask the window manager, and the window manager + can override the application's settings. On Windows, Qt can set + whatever flags you want. + + \sa windowFlags +*/ +QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) + : QObject(*new QWidgetPrivate, 0), QPaintDevice() +{ + QT_TRY { + d_func()->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } +} + +#ifdef QT3_SUPPORT +/*! + \overload + \obsolete + */ +QWidget::QWidget(QWidget *parent, const char *name, Qt::WindowFlags f) + : QObject(*new QWidgetPrivate, 0), QPaintDevice() +{ + QT_TRY { + d_func()->init(parent , f); + setObjectName(QString::fromAscii(name)); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } +} +#endif + +/*! \internal +*/ +QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) + : QObject(dd, 0), QPaintDevice() +{ + Q_D(QWidget); + QT_TRY { + d->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } +} + +/*! + \internal +*/ +int QWidget::devType() const +{ + return QInternal::Widget; +} + + +//### w is a "this" ptr, passed as a param because QWorkspace needs special logic +void QWidgetPrivate::adjustFlags(Qt::WindowFlags &flags, QWidget *w) +{ + bool customize = (flags & (Qt::CustomizeWindowHint + | Qt::FramelessWindowHint + | Qt::WindowTitleHint + | Qt::WindowSystemMenuHint + | Qt::WindowMinimizeButtonHint + | Qt::WindowMaximizeButtonHint + | Qt::WindowCloseButtonHint + | Qt::WindowContextHelpButtonHint)); + + uint type = (flags & Qt::WindowType_Mask); + + if ((type == Qt::Widget || type == Qt::SubWindow) && w && !w->parent()) { + type = Qt::Window; + flags |= Qt::Window; + } + + if (flags & Qt::CustomizeWindowHint) { + // modify window flags to make them consistent. + // Only enable this on non-Mac platforms. Since the old way of doing this would + // interpret WindowSystemMenuHint as a close button and we can't change that behavior + // we can't just add this in. +#ifndef Q_WS_MAC + if (flags & (Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint)) { + flags |= Qt::WindowSystemMenuHint; +#else + if (flags & (Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint + | Qt::WindowSystemMenuHint)) { +#endif + flags |= Qt::WindowTitleHint; + flags &= ~Qt::FramelessWindowHint; + } + } else if (customize && !(flags & Qt::FramelessWindowHint)) { + // if any of the window hints that affect the titlebar are set + // and the window is supposed to have frame, we add a titlebar + // and system menu by default. + flags |= Qt::WindowSystemMenuHint; + flags |= Qt::WindowTitleHint; + } + if (customize) + ; // don't modify window flags if the user explicitly set them. + else if (type == Qt::Dialog || type == Qt::Sheet) +#ifndef Q_WS_WINCE + flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint | Qt::WindowCloseButtonHint; +#else + flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; +#endif + else if (type == Qt::Tool) + flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; + else + flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint; + + +} + +void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) +{ + Q_Q(QWidget); + if (QApplication::type() == QApplication::Tty) + qFatal("QWidget: Cannot create a QWidget when no GUI is being used"); + + Q_ASSERT(allWidgets); + if (allWidgets) + allWidgets->insert(q); + + QWidget *desktopWidget = 0; + if (parentWidget && parentWidget->windowType() == Qt::Desktop) { + desktopWidget = parentWidget; + parentWidget = 0; + } + + q->data = &data; + +#ifndef QT_NO_THREAD + if (!parent) { + Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget", + "Widgets must be created in the GUI thread."); + } +#endif + +#if defined(Q_WS_X11) + if (desktopWidget) { + // make sure the widget is created on the same screen as the + // programmer specified desktop widget + xinfo = desktopWidget->d_func()->xinfo; + } +#elif defined(Q_OS_SYMBIAN) + if (desktopWidget) { + symbianScreenNumber = qt_widget_private(desktopWidget)->symbianScreenNumber; + } +#elif defined(Q_WS_QPA) + if (desktopWidget) { + int screen = desktopWidget->d_func()->topData()->screenIndex; + QPlatformIntegration *platform = QGuiApplicationPrivate::platformIntegration(); + platform->moveToScreen(q->windowHandle(), screen); + } +#else + Q_UNUSED(desktopWidget); +#endif + + data.fstrut_dirty = true; + + data.winid = 0; + data.widget_attributes = 0; + data.window_flags = f; + data.window_state = 0; + data.focus_policy = 0; + data.context_menu_policy = Qt::DefaultContextMenu; + data.window_modality = Qt::NonModal; + + data.sizehint_forced = 0; + data.is_closing = 0; + data.in_show = 0; + data.in_set_window_state = 0; + data.in_destructor = false; + + // Widgets with Qt::MSWindowsOwnDC (typically QGLWidget) must have a window handle. + if (f & Qt::MSWindowsOwnDC) + q->setAttribute(Qt::WA_NativeWindow); + +//#ifdef Q_WS_MAC +// q->setAttribute(Qt::WA_NativeWindow); +//#endif + + q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute() + adjustQuitOnCloseAttribute(); + + q->setAttribute(Qt::WA_WState_Hidden); + + //give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later +#ifdef Q_OS_SYMBIAN + if (isGLWidget) { + // Don't waste GPU mem for unnecessary large egl surface until resized by application + data.crect = QRect(0,0,1,1); + } else { + data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,360,640); + } +#else + data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480); +#endif + + focus_next = focus_prev = q; + + if ((f & Qt::WindowType_Mask) == Qt::Desktop) + q->create(); + else if (parentWidget) + q->setParent(parentWidget, data.window_flags); + else { + adjustFlags(data.window_flags, q); + resolveLayoutDirection(); + // opaque system background? + const QBrush &background = q->palette().brush(QPalette::Window); + setOpaque(q->isWindow() && background.style() != Qt::NoBrush && background.isOpaque()); + } + data.fnt = QFont(data.fnt, q); +#if defined(Q_WS_X11) + data.fnt.x11SetScreen(xinfo.screen()); +#endif // Q_WS_X11 + + q->setAttribute(Qt::WA_PendingMoveEvent); + q->setAttribute(Qt::WA_PendingResizeEvent); + + if (++QWidgetPrivate::instanceCounter > QWidgetPrivate::maxInstances) + QWidgetPrivate::maxInstances = QWidgetPrivate::instanceCounter; + + if (QApplicationPrivate::app_compile_version < 0x040200 + || QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation)) + q->create(); + + + QEvent e(QEvent::Create); + QApplication::sendEvent(q, &e); + QApplication::postEvent(q, new QEvent(QEvent::PolishRequest)); + + extraPaintEngine = 0; + +#ifdef QT_MAC_USE_COCOA + // If we add a child to the unified toolbar, we have to redirect the painting. + if (parentWidget && parentWidget->d_func() && parentWidget->d_func()->isInUnifiedToolbar) { + if (parentWidget->d_func()->unifiedSurface) { + QWidget *toolbar = parentWidget->d_func()->toolbar_ancestor; + parentWidget->d_func()->unifiedSurface->recursiveRedirect(toolbar, toolbar, toolbar->d_func()->toolbar_offset); + } + } +#endif // QT_MAC_USE_COCOA +} + + + +void QWidgetPrivate::createRecursively() +{ + Q_Q(QWidget); + q->create(0, true, true); + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast(children.at(i)); + if (child && !child->isHidden() && !child->isWindow() && !child->testAttribute(Qt::WA_WState_Created)) + child->d_func()->createRecursively(); + } +} + + + + +/*! + Creates a new widget window if \a window is 0, otherwise sets the + widget's window to \a window. + + Initializes the window (sets the geometry etc.) if \a + initializeWindow is true. If \a initializeWindow is false, no + initialization is performed. This parameter only makes sense if \a + window is a valid window. + + Destroys the old window if \a destroyOldWindow is true. If \a + destroyOldWindow is false, you are responsible for destroying the + window yourself (using platform native code). + + The QWidget constructor calls create(0,true,true) to create a + window for this widget. +*/ + +void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) +{ + Q_D(QWidget); + if (testAttribute(Qt::WA_WState_Created) && window == 0 && internalWinId()) + return; + + if (d->data.in_destructor) + return; + + Qt::WindowType type = windowType(); + Qt::WindowFlags &flags = data->window_flags; + + if ((type == Qt::Widget || type == Qt::SubWindow) && !parentWidget()) { + type = Qt::Window; + flags |= Qt::Window; + } + +#ifndef Q_WS_QPA + if (QWidget *parent = parentWidget()) { + if (type & Qt::Window) { + if (!parent->testAttribute(Qt::WA_WState_Created)) + parent->createWinId(); + } else if (testAttribute(Qt::WA_NativeWindow) && !parent->internalWinId() + && !testAttribute(Qt::WA_DontCreateNativeAncestors)) { + // We're about to create a native child widget that doesn't have a native parent; + // enforce a native handle for the parent unless the Qt::WA_DontCreateNativeAncestors + // attribute is set. + d->createWinId(window); + // Nothing more to do. + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + Q_ASSERT(internalWinId()); + return; + } + } +#endif //Q_WS_QPA + +#ifdef QT3_SUPPORT + if (flags & Qt::WStaticContents) + setAttribute(Qt::WA_StaticContents); + if (flags & Qt::WDestructiveClose) + setAttribute(Qt::WA_DeleteOnClose); + if (flags & Qt::WShowModal) + setWindowModality(Qt::ApplicationModal); + if (flags & Qt::WMouseNoMask) + setAttribute(Qt::WA_MouseNoMask); + if (flags & Qt::WGroupLeader) + setAttribute(Qt::WA_GroupLeader); + if (flags & Qt::WNoMousePropagation) + setAttribute(Qt::WA_NoMousePropagation); +#endif + + static int paintOnScreenEnv = -1; + if (paintOnScreenEnv == -1) + paintOnScreenEnv = qgetenv("QT_ONSCREEN_PAINT").toInt() > 0 ? 1 : 0; + if (paintOnScreenEnv == 1) + setAttribute(Qt::WA_PaintOnScreen); + + if (QApplicationPrivate::testAttribute(Qt::AA_NativeWindows)) + setAttribute(Qt::WA_NativeWindow); + +#ifdef ALIEN_DEBUG + qDebug() << "QWidget::create:" << this << "parent:" << parentWidget() + << "Alien?" << !testAttribute(Qt::WA_NativeWindow); +#endif + +#if defined (Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) + // Unregister the dropsite (if already registered) before we + // re-create the widget with a native window. + if (testAttribute(Qt::WA_WState_Created) && !internalWinId() && testAttribute(Qt::WA_NativeWindow) + && d->extra && d->extra->dropTarget) { + d->registerDropSite(false); + } +#endif // defined (Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) + + d->updateIsOpaque(); + + setAttribute(Qt::WA_WState_Created); // set created flag + d->create_sys(window, initializeWindow, destroyOldWindow); + + // a real toplevel window needs a backing store + if (isWindow() && windowType() != Qt::Desktop) { + d->topData()->backingStore.destroy(); + if (hasBackingStoreSupport()) + d->topData()->backingStore.create(this); + } + + d->setModal_sys(); + + if (!isWindow() && parentWidget() && parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)) + setAttribute(Qt::WA_DropSiteRegistered, true); + +#ifdef QT_EVAL + extern void qt_eval_init_widget(QWidget *w); + qt_eval_init_widget(this); +#endif + + // need to force the resting of the icon after changing parents + if (testAttribute(Qt::WA_SetWindowIcon)) + d->setWindowIcon_sys(true); + if (isWindow() && !d->topData()->iconText.isEmpty()) + d->setWindowIconText_helper(d->topData()->iconText); + if (isWindow() && !d->topData()->caption.isEmpty()) + d->setWindowTitle_helper(d->topData()->caption); + if (windowType() != Qt::Desktop) { + d->updateSystemBackground(); + + if (isWindow() && !testAttribute(Qt::WA_SetWindowIcon)) + d->setWindowIcon_sys(); + } +} + +/*! + Destroys the widget. + + All this widget's children are deleted first. The application + exits if this widget is the main widget. +*/ + +QWidget::~QWidget() +{ + Q_D(QWidget); + d->data.in_destructor = true; + +#if defined (QT_CHECK_STATE) + if (paintingActive()) + qWarning("QWidget: %s (%s) deleted while being painted", className(), name()); +#endif + +#ifndef QT_NO_GESTURES + foreach (Qt::GestureType type, d->gestureContext.keys()) + ungrabGesture(type); +#endif + + // force acceptDrops false before winId is destroyed. + d->registerDropSite(false); + +#ifndef QT_NO_ACTION + // remove all actions from this widget + for (int i = 0; i < d->actions.size(); ++i) { + QActionPrivate *apriv = d->actions.at(i)->d_func(); + apriv->widgets.removeAll(this); + } + d->actions.clear(); +#endif + +#ifndef QT_NO_SHORTCUT + // Remove all shortcuts grabbed by this + // widget, unless application is closing + if (!QApplicationPrivate::is_app_closing && testAttribute(Qt::WA_GrabbedShortcut)) + qApp->d_func()->shortcutMap.removeShortcut(0, this, QKeySequence()); +#endif + + // delete layout while we still are a valid widget + delete d->layout; + // Remove myself from focus list + + Q_ASSERT(d->focus_next->d_func()->focus_prev == this); + Q_ASSERT(d->focus_prev->d_func()->focus_next == this); + + if (d->focus_next != this) { + d->focus_next->d_func()->focus_prev = d->focus_prev; + d->focus_prev->d_func()->focus_next = d->focus_next; + d->focus_next = d->focus_prev = 0; + } + +#ifdef QT3_SUPPORT + if (QApplicationPrivate::main_widget == this) { // reset main widget + QApplicationPrivate::main_widget = 0; + QApplication::quit(); + } +#endif + + QT_TRY { + clearFocus(); + } QT_CATCH(...) { + // swallow this problem because we are in a destructor + } + + d->setDirtyOpaqueRegion(); + + if (isWindow() && isVisible() && internalWinId()) { + QT_TRY { + d->close_helper(QWidgetPrivate::CloseNoEvent); + } QT_CATCH(...) { + // if we're out of memory, at least hide the window. + QT_TRY { + hide(); + } QT_CATCH(...) { + // and if that also doesn't work, then give up + } + } + } + +#if defined(Q_WS_WIN) || defined(Q_WS_X11)|| defined(Q_WS_MAC) + else if (!internalWinId() && isVisible()) { + qApp->d_func()->sendSyntheticEnterLeave(this); + } +#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) + else if (isVisible()) { + qApp->d_func()->sendSyntheticEnterLeave(this); + } +#endif + +#ifdef Q_OS_SYMBIAN + if (d->extra && d->extra->topextra && d->extra->topextra->backingStore) { + // Okay, we are about to destroy the top-level window that owns + // the backing store. Make sure we delete the backing store right away + // before the window handle is invalid. This is important because + // the backing store will delete its window surface, which may or may + // not have a reference to this widget that will be used later to + // notify the window it no longer has a surface. + d->extra->topextra->backingStore.destroy(); + } +#endif + if (QWidgetBackingStore *bs = d->maybeBackingStore()) { + bs->removeDirtyWidget(this); + if (testAttribute(Qt::WA_StaticContents)) + bs->removeStaticWidget(this); + } + + delete d->needsFlush; + d->needsFlush = 0; + + // set all QPointers for this object to zero + if (d->hasGuards) + QObjectPrivate::clearGuards(this); + + if (d->declarativeData) { + QAbstractDeclarativeData::destroyed(d->declarativeData, this); + d->declarativeData = 0; // don't activate again in ~QObject + } + +#ifdef QT_MAC_USE_COCOA + // QCocoaView holds a pointer back to this widget. Clear it now + // to make sure it's not followed later on. The lifetime of the + // QCocoaView might exceed the lifetime of this widget in cases + // where Cocoa itself holds references to it. + extern void qt_mac_clearCocoaViewQWidgetPointers(QWidget *); + qt_mac_clearCocoaViewQWidgetPointers(this); +#endif + + if (!d->children.isEmpty()) + d->deleteChildren(); + + QApplication::removePostedEvents(this); + + QT_TRY { + destroy(); // platform-dependent cleanup + } QT_CATCH(...) { + // if this fails we can't do anything about it but at least we are not allowed to throw. + } + --QWidgetPrivate::instanceCounter; + + if (QWidgetPrivate::allWidgets) // might have been deleted by ~QApplication + QWidgetPrivate::allWidgets->remove(this); + + QT_TRY { + QEvent e(QEvent::Destroy); + QCoreApplication::sendEvent(this, &e); + } QT_CATCH(const std::exception&) { + // if this fails we can't do anything about it but at least we are not allowed to throw. + } +} + +int QWidgetPrivate::instanceCounter = 0; // Current number of widget instances +int QWidgetPrivate::maxInstances = 0; // Maximum number of widget instances + +void QWidgetPrivate::setWinId(WId id) // set widget identifier +{ + Q_Q(QWidget); + // the user might create a widget with Qt::Desktop window + // attribute (or create another QDesktopWidget instance), which + // will have the same windowid (the root window id) as the + // qt_desktopWidget. We should not add the second desktop widget + // to the mapper. + bool userDesktopWidget = qt_desktopWidget != 0 && qt_desktopWidget != q && q->windowType() == Qt::Desktop; + if (mapper && data.winid && !userDesktopWidget) { + mapper->remove(data.winid); + } + + const WId oldWinId = data.winid; + + data.winid = id; +#if defined(Q_WS_X11) + hd = id; // X11: hd == ident +#endif + if (mapper && id && !userDesktopWidget) { + mapper->insert(data.winid, q); + } + + if(oldWinId != id) { + QEvent e(QEvent::WinIdChange); + QCoreApplication::sendEvent(q, &e); + } +} + +void QWidgetPrivate::createTLExtra() +{ + if (!extra) + createExtra(); + if (!extra->topextra) { + QTLWExtra* x = extra->topextra = new QTLWExtra; + x->icon = 0; + x->iconPixmap = 0; + x->windowSurface = 0; + x->sharedPainter = 0; + x->incw = x->inch = 0; + x->basew = x->baseh = 0; + x->frameStrut.setCoords(0, 0, 0, 0); + x->normalGeometry = QRect(0,0,-1,-1); + x->savedFlags = 0; + x->opacity = 255; + x->posFromMove = false; + x->sizeAdjusted = false; + x->inTopLevelResize = false; + x->inRepaint = false; + x->embedded = 0; +#ifdef Q_WS_MAC +#ifdef QT_MAC_USE_COCOA + x->wasMaximized = false; +#endif // QT_MAC_USE_COCOA +#endif // Q_WS_MAC + createTLSysExtra(); +#ifdef QWIDGET_EXTRA_DEBUG + static int count = 0; + qDebug() << "tlextra" << ++count; +#endif + } +} + +/*! + \internal + Creates the widget extra data. +*/ + +void QWidgetPrivate::createExtra() +{ + if (!extra) { // if not exists + extra = new QWExtra; + extra->glContext = 0; + extra->topextra = 0; +#ifndef QT_NO_GRAPHICSVIEW + extra->proxyWidget = 0; +#endif +#ifndef QT_NO_CURSOR + extra->curs = 0; +#endif + extra->minw = 0; + extra->minh = 0; + extra->maxw = QWIDGETSIZE_MAX; + extra->maxh = QWIDGETSIZE_MAX; + extra->customDpiX = 0; + extra->customDpiY = 0; + extra->explicitMinSize = 0; + extra->explicitMaxSize = 0; + extra->autoFillBackground = 0; + extra->nativeChildrenForced = 0; + extra->inRenderWithPainter = 0; + extra->hasMask = 0; + createSysExtra(); +#ifdef QWIDGET_EXTRA_DEBUG + static int count = 0; + qDebug() << "extra" << ++count; +#endif + } +} + + +/*! + \internal + Deletes the widget extra data. +*/ + +void QWidgetPrivate::deleteExtra() +{ + if (extra) { // if exists +#ifndef QT_NO_CURSOR + delete extra->curs; +#endif + deleteSysExtra(); +#ifndef QT_NO_STYLE_STYLESHEET + // dereference the stylesheet style + if (QStyleSheetStyle *proxy = qobject_cast(extra->style)) + proxy->deref(); +#endif + if (extra->topextra) { + deleteTLSysExtra(); + extra->topextra->backingStore.destroy(); + delete extra->topextra->icon; + delete extra->topextra->iconPixmap; +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + delete extra->topextra->qwsManager; +#endif + delete extra->topextra->windowSurface; + delete extra->topextra; + } + delete extra; + // extra->xic destroyed in QWidget::destroy() + extra = 0; + } +} + +/* + Returns true if there are widgets above this which overlap with + \a rect, which is in parent's coordinate system (same as crect). +*/ + +bool QWidgetPrivate::isOverlapped(const QRect &rect) const +{ + Q_Q(const QWidget); + + const QWidget *w = q; + QRect r = rect; + while (w) { + if (w->isWindow()) + return false; + QWidgetPrivate *pd = w->parentWidget()->d_func(); + bool above = false; + for (int i = 0; i < pd->children.size(); ++i) { + QWidget *sibling = qobject_cast(pd->children.at(i)); + if (!sibling || !sibling->isVisible() || sibling->isWindow()) + continue; + if (!above) { + above = (sibling == w); + continue; + } + + if (qRectIntersects(sibling->d_func()->effectiveRectFor(sibling->data->crect), r)) { + const QWExtra *siblingExtra = sibling->d_func()->extra; + if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect + && !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) { + continue; + } + return true; + } + } + w = w->parentWidget(); + r.translate(pd->data.crect.topLeft()); + } + return false; +} + +void QWidgetPrivate::syncBackingStore() +{ + if (paintOnScreen()) { + repaint_sys(dirty); + dirty = QRegion(); + } else if (QWidgetBackingStore *bs = maybeBackingStore()) { + bs->sync(); + } +} + +void QWidgetPrivate::syncBackingStore(const QRegion ®ion) +{ + if (paintOnScreen()) + repaint_sys(region); + else if (QWidgetBackingStore *bs = maybeBackingStore()) { + bs->sync(q_func(), region); + } +} + +void QWidgetPrivate::setUpdatesEnabled_helper(bool enable) +{ + Q_Q(QWidget); + + if (enable && !q->isWindow() && q->parentWidget() && !q->parentWidget()->updatesEnabled()) + return; // nothing we can do + + if (enable != q->testAttribute(Qt::WA_UpdatesDisabled)) + return; // nothing to do + + q->setAttribute(Qt::WA_UpdatesDisabled, !enable); + if (enable) + q->update(); + + Qt::WidgetAttribute attribute = enable ? Qt::WA_ForceUpdatesDisabled : Qt::WA_UpdatesDisabled; + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w && !w->isWindow() && !w->testAttribute(attribute)) + w->d_func()->setUpdatesEnabled_helper(enable); + } +} + +/*! + \internal + + Propagate this widget's palette to all children, except style sheet + widgets, and windows that don't enable window propagation (palettes don't + normally propagate to windows). +*/ +void QWidgetPrivate::propagatePaletteChange() +{ + Q_Q(QWidget); + // Propagate a new inherited mask to all children. +#ifndef QT_NO_GRAPHICSVIEW + if (!q->parentWidget() && extra && extra->proxyWidget) { + QGraphicsProxyWidget *p = extra->proxyWidget; + inheritedPaletteResolveMask = p->d_func()->inheritedPaletteResolveMask | p->palette().resolve(); + } else +#endif //QT_NO_GRAPHICSVIEW + if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { + inheritedPaletteResolveMask = 0; + } + int mask = data.pal.resolve() | inheritedPaletteResolveMask; + + QEvent pc(QEvent::PaletteChange); + QApplication::sendEvent(q, &pc); + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w && !w->testAttribute(Qt::WA_StyleSheet) + && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))) { + QWidgetPrivate *wd = w->d_func(); + wd->inheritedPaletteResolveMask = mask; + wd->resolvePalette(); + } + } +#if defined(QT3_SUPPORT) + q->paletteChange(q->palette()); // compatibility +#endif +} + +/* + Returns the widget's clipping rectangle. +*/ +QRect QWidgetPrivate::clipRect() const +{ + Q_Q(const QWidget); + const QWidget * w = q; + if (!w->isVisible()) + return QRect(); + QRect r = effectiveRectFor(q->rect()); + int ox = 0; + int oy = 0; + while (w + && w->isVisible() + && !w->isWindow() + && w->parentWidget()) { + ox -= w->x(); + oy -= w->y(); + w = w->parentWidget(); + r &= QRect(ox, oy, w->width(), w->height()); + } + return r; +} + +/* + Returns the widget's clipping region (without siblings). +*/ +QRegion QWidgetPrivate::clipRegion() const +{ + Q_Q(const QWidget); + if (!q->isVisible()) + return QRegion(); + QRegion r(q->rect()); + const QWidget * w = q; + const QWidget *ignoreUpTo; + int ox = 0; + int oy = 0; + while (w + && w->isVisible() + && !w->isWindow() + && w->parentWidget()) { + ox -= w->x(); + oy -= w->y(); + ignoreUpTo = w; + w = w->parentWidget(); + r &= QRegion(ox, oy, w->width(), w->height()); + + int i = 0; + while(w->d_func()->children.at(i++) != static_cast(ignoreUpTo)) + ; + for ( ; i < w->d_func()->children.size(); ++i) { + if(QWidget *sibling = qobject_cast(w->d_func()->children.at(i))) { + if(sibling->isVisible() && !sibling->isWindow()) { + QRect siblingRect(ox+sibling->x(), oy+sibling->y(), + sibling->width(), sibling->height()); + if (qRectIntersects(siblingRect, q->rect())) + r -= QRegion(siblingRect); + } + } + } + } + return r; +} + +#ifndef QT_NO_GRAPHICSEFFECT +void QWidgetPrivate::invalidateGraphicsEffectsRecursively() +{ + Q_Q(QWidget); + QWidget *w = q; + do { + if (w->graphicsEffect()) { + QWidgetEffectSourcePrivate *sourced = + static_cast(w->graphicsEffect()->source()->d_func()); + if (!sourced->updateDueToGraphicsEffect) + w->graphicsEffect()->source()->d_func()->invalidateCache(); + } + w = w->parentWidget(); + } while (w); +} +#endif //QT_NO_GRAPHICSEFFECT + +void QWidgetPrivate::setDirtyOpaqueRegion() +{ + Q_Q(QWidget); + + dirtyOpaqueChildren = true; + +#ifndef QT_NO_GRAPHICSEFFECT + invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + if (q->isWindow()) + return; + + QWidget *parent = q->parentWidget(); + if (!parent) + return; + + // TODO: instead of setting dirtyflag, manipulate the dirtyregion directly? + QWidgetPrivate *pd = parent->d_func(); + if (!pd->dirtyOpaqueChildren) + pd->setDirtyOpaqueRegion(); +} + +const QRegion &QWidgetPrivate::getOpaqueChildren() const +{ + if (!dirtyOpaqueChildren) + return opaqueChildren; + + QWidgetPrivate *that = const_cast(this); + that->opaqueChildren = QRegion(); + + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast(children.at(i)); + if (!child || !child->isVisible() || child->isWindow()) + continue; + + const QPoint offset = child->geometry().topLeft(); + QWidgetPrivate *childd = child->d_func(); + QRegion r = childd->isOpaque ? child->rect() : childd->getOpaqueChildren(); + if (childd->extra && childd->extra->hasMask) + r &= childd->extra->mask; + if (r.isEmpty()) + continue; + r.translate(offset); + that->opaqueChildren += r; + } + + that->opaqueChildren &= q_func()->rect(); + that->dirtyOpaqueChildren = false; + + return that->opaqueChildren; +} + +void QWidgetPrivate::subtractOpaqueChildren(QRegion &source, const QRect &clipRect) const +{ + if (children.isEmpty() || clipRect.isEmpty()) + return; + + const QRegion &r = getOpaqueChildren(); + if (!r.isEmpty()) + source -= (r & clipRect); +} + +//subtract any relatives that are higher up than me --- this is too expensive !!! +void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirtySiblingsAbove, + bool alsoNonOpaque) const +{ + Q_Q(const QWidget); + static int disableSubtractOpaqueSiblings = qgetenv("QT_NO_SUBTRACTOPAQUESIBLINGS").toInt(); + if (disableSubtractOpaqueSiblings || q->isWindow()) + return; + +#ifdef QT_MAC_USE_COCOA + if (q->d_func()->isInUnifiedToolbar) + return; +#endif // QT_MAC_USE_COCOA + + QRect clipBoundingRect; + bool dirtyClipBoundingRect = true; + + QRegion parentClip; + bool dirtyParentClip = true; + + QPoint parentOffset = data.crect.topLeft(); + + const QWidget *w = q; + + while (w) { + if (w->isWindow()) + break; + QWidgetPrivate *pd = w->parentWidget()->d_func(); + const int myIndex = pd->children.indexOf(const_cast(w)); + const QRect widgetGeometry = w->d_func()->effectiveRectFor(w->data->crect); + for (int i = myIndex + 1; i < pd->children.size(); ++i) { + QWidget *sibling = qobject_cast(pd->children.at(i)); + if (!sibling || !sibling->isVisible() || sibling->isWindow()) + continue; + + const QRect siblingGeometry = sibling->d_func()->effectiveRectFor(sibling->data->crect); + if (!qRectIntersects(siblingGeometry, widgetGeometry)) + continue; + + if (dirtyClipBoundingRect) { + clipBoundingRect = sourceRegion.boundingRect(); + dirtyClipBoundingRect = false; + } + + if (!qRectIntersects(siblingGeometry, clipBoundingRect.translated(parentOffset))) + continue; + + if (dirtyParentClip) { + parentClip = sourceRegion.translated(parentOffset); + dirtyParentClip = false; + } + + const QPoint siblingPos(sibling->data->crect.topLeft()); + const QRect siblingClipRect(sibling->d_func()->clipRect()); + QRegion siblingDirty(parentClip); + siblingDirty &= (siblingClipRect.translated(siblingPos)); + const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask + && !sibling->d_func()->graphicsEffect; + if (hasMask) + siblingDirty &= sibling->d_func()->extra->mask.translated(siblingPos); + if (siblingDirty.isEmpty()) + continue; + + if (sibling->d_func()->isOpaque || alsoNonOpaque) { + if (hasMask) { + siblingDirty.translate(-parentOffset); + sourceRegion -= siblingDirty; + } else { + sourceRegion -= siblingGeometry.translated(-parentOffset); + } + } else { + if (hasDirtySiblingsAbove) + *hasDirtySiblingsAbove = true; + if (sibling->d_func()->children.isEmpty()) + continue; + QRegion opaqueSiblingChildren(sibling->d_func()->getOpaqueChildren()); + opaqueSiblingChildren.translate(-parentOffset + siblingPos); + sourceRegion -= opaqueSiblingChildren; + } + if (sourceRegion.isEmpty()) + return; + + dirtyClipBoundingRect = true; + dirtyParentClip = true; + } + + w = w->parentWidget(); + parentOffset += pd->data.crect.topLeft(); + dirtyParentClip = true; + } +} + +void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const +{ + Q_Q(const QWidget); + + const QWidget *w = q; + QPoint offset; + +#ifndef QT_NO_GRAPHICSEFFECT + if (graphicsEffect) { + w = q->parentWidget(); + offset -= data.crect.topLeft(); + } +#endif //QT_NO_GRAPHICSEFFECT + + while (w) { + const QWidgetPrivate *wd = w->d_func(); + if (wd->extra && wd->extra->hasMask) + region &= (w != q) ? wd->extra->mask.translated(offset) : wd->extra->mask; + if (w->isWindow()) + return; + offset -= wd->data.crect.topLeft(); + w = w->parentWidget(); + } +} + +bool QWidgetPrivate::paintOnScreen() const +{ +#if defined(Q_WS_QWS) + return false; +#elif defined(QT_NO_BACKINGSTORE) + return true; +#else + Q_Q(const QWidget); + if (q->testAttribute(Qt::WA_PaintOnScreen) + || (!q->isWindow() && q->window()->testAttribute(Qt::WA_PaintOnScreen))) { + return true; + } + + return !qt_enable_backingstore; +#endif +} + +void QWidgetPrivate::updateIsOpaque() +{ + // hw: todo: only needed if opacity actually changed + setDirtyOpaqueRegion(); + +#ifndef QT_NO_GRAPHICSEFFECT + if (graphicsEffect) { + // ### We should probably add QGraphicsEffect::isOpaque at some point. + setOpaque(false); + return; + } +#endif //QT_NO_GRAPHICSEFFECT + + Q_Q(QWidget); +#ifdef Q_WS_X11 + if (q->testAttribute(Qt::WA_X11OpenGLOverlay)) { + setOpaque(false); + return; + } +#endif + +#ifdef Q_WS_S60 + if (q->windowType() == Qt::Dialog && q->testAttribute(Qt::WA_TranslucentBackground) + && S60->avkonComponentsSupportTransparency) { + setOpaque(false); + return; + } +#endif + + if (q->testAttribute(Qt::WA_OpaquePaintEvent) || q->testAttribute(Qt::WA_PaintOnScreen)) { + setOpaque(true); + return; + } + + const QPalette &pal = q->palette(); + + if (q->autoFillBackground()) { + const QBrush &autoFillBrush = pal.brush(q->backgroundRole()); + if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) { + setOpaque(true); + return; + } + } + + if (q->isWindow() && !q->testAttribute(Qt::WA_NoSystemBackground)) { + const QBrush &windowBrush = q->palette().brush(QPalette::Window); + if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) { + setOpaque(true); + return; + } + } + setOpaque(false); +} + +void QWidgetPrivate::setOpaque(bool opaque) +{ + if (isOpaque == opaque) + return; + isOpaque = opaque; +#ifdef Q_WS_MAC + macUpdateIsOpaque(); +#endif +#ifdef Q_WS_X11 + x11UpdateIsOpaque(); +#endif +#ifdef Q_WS_WIN + winUpdateIsOpaque(); +#endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif +} + +void QWidgetPrivate::updateIsTranslucent() +{ +#ifdef Q_WS_MAC + macUpdateIsOpaque(); +#endif +#ifdef Q_WS_X11 + x11UpdateIsOpaque(); +#endif +#ifdef Q_WS_WIN + winUpdateIsOpaque(); +#endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif +} + +static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrush &brush) +{ + Q_ASSERT(painter); + + if (brush.style() == Qt::TexturePattern) { +#ifdef Q_WS_MAC + // Optimize pattern filling on mac by using HITheme directly + // when filling with the standard widget background. + // Defined in qmacstyle_mac.cpp + extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); + qt_mac_fill_background(painter, rgn, brush); +#else +#if !defined(QT_NO_STYLE_S60) + // Defined in qs60style.cpp + extern bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); + if (!qt_s60_fill_background(painter, rgn, brush)) +#endif // !defined(QT_NO_STYLE_S60) + { + const QRect rect(rgn.boundingRect()); + painter->setClipRegion(rgn); + painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); + } +#endif // Q_WS_MAC + + } else if (brush.gradient() + && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) { + painter->save(); + painter->setClipRegion(rgn); + painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush); + painter->restore(); + } else { + const QVector &rects = rgn.rects(); + for (int i = 0; i < rects.size(); ++i) + painter->fillRect(rects.at(i), brush); + } +} + +void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int flags) const +{ + Q_Q(const QWidget); + +#ifndef QT_NO_SCROLLAREA + bool resetBrushOrigin = false; + QPointF oldBrushOrigin; + //If we are painting the viewport of a scrollarea, we must apply an offset to the brush in case we are drawing a texture + QAbstractScrollArea *scrollArea = qobject_cast(parent); + if (scrollArea && scrollArea->viewport() == q) { + QObjectData *scrollPrivate = static_cast(scrollArea)->d_ptr.data(); + QAbstractScrollAreaPrivate *priv = static_cast(scrollPrivate); + oldBrushOrigin = painter->brushOrigin(); + resetBrushOrigin = true; + painter->setBrushOrigin(-priv->contentsOffset()); + + } +#endif // QT_NO_SCROLLAREA + + const QBrush autoFillBrush = q->palette().brush(q->backgroundRole()); + + if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) { + const QBrush bg = q->palette().brush(QPalette::Window); +#ifdef Q_WS_QWS + if (!(flags & DontSetCompositionMode) && painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in +#endif + fillRegion(painter, rgn, bg); + } + + if (q->autoFillBackground()) + fillRegion(painter, rgn, autoFillBrush); + + if (q->testAttribute(Qt::WA_StyledBackground)) { + painter->setClipRegion(rgn); + QStyleOption opt; + opt.initFrom(q); + q->style()->drawPrimitive(QStyle::PE_Widget, &opt, painter, q); + } + +#ifndef QT_NO_SCROLLAREA + if (resetBrushOrigin) + painter->setBrushOrigin(oldBrushOrigin); +#endif // QT_NO_SCROLLAREA +} + +/* + \internal + This function is called when a widget is hidden or destroyed. + It resets some application global pointers that should only refer active, + visible widgets. +*/ + +#ifdef Q_WS_MAC + extern QPointer qt_button_down; +#else + extern QWidget *qt_button_down; +#endif + +void QWidgetPrivate::deactivateWidgetCleanup() +{ + Q_Q(QWidget); + // If this was the active application window, reset it + if (QApplication::activeWindow() == q) + QApplication::setActiveWindow(0); + // If the is the active mouse press widget, reset it + if (q == qt_button_down) + qt_button_down = 0; +} + + +/*! + Returns a pointer to the widget with window identifer/handle \a + id. + + The window identifier type depends on the underlying window + system, see \c qwindowdefs.h for the actual definition. If there + is no widget with this identifier, 0 is returned. +*/ + +QWidget *QWidget::find(WId id) +{ + return QWidgetPrivate::mapper ? QWidgetPrivate::mapper->value(id, 0) : 0; +} + + + +/*! + \fn WId QWidget::internalWinId() const + \internal + Returns the window system identifier of the widget, or 0 if the widget is not created yet. + +*/ + +/*! + \fn WId QWidget::winId() const + + Returns the window system identifier of the widget. + + Portable in principle, but if you use it you are probably about to + do something non-portable. Be careful. + + If a widget is non-native (alien) and winId() is invoked on it, that widget + will be provided a native handle. + + On Mac OS X, the type returned depends on which framework Qt was linked + against. If Qt is using Carbon, the {WId} is actually an HIViewRef. If Qt + is using Cocoa, {WId} is a pointer to an NSView. + + This value may change at run-time. An event with type QEvent::WinIdChange + will be sent to the widget following a change in window system identifier. + + \sa find() +*/ +WId QWidget::winId() const +{ + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { +#ifdef ALIEN_DEBUG + qDebug() << "QWidget::winId: creating native window for" << this; +#endif + QWidget *that = const_cast(this); +#ifndef Q_WS_QPA + that->setAttribute(Qt::WA_NativeWindow); +#endif + that->d_func()->createWinId(); + return that->data->winid; + } + return data->winid; +} + + +void QWidgetPrivate::createWinId(WId winid) +{ + Q_Q(QWidget); + +#ifdef ALIEN_DEBUG + qDebug() << "QWidgetPrivate::createWinId for" << q << winid; +#endif + const bool forceNativeWindow = q->testAttribute(Qt::WA_NativeWindow); + if (!q->testAttribute(Qt::WA_WState_Created) || (forceNativeWindow && !q->internalWinId())) { +#ifndef Q_WS_QPA + if (!q->isWindow()) { + QWidget *parent = q->parentWidget(); + QWidgetPrivate *pd = parent->d_func(); + if (forceNativeWindow && !q->testAttribute(Qt::WA_DontCreateNativeAncestors)) + parent->setAttribute(Qt::WA_NativeWindow); + if (!parent->internalWinId()) { + pd->createWinId(); + } + + for (int i = 0; i < pd->children.size(); ++i) { + QWidget *w = qobject_cast(pd->children.at(i)); + if (w && !w->isWindow() && (!w->testAttribute(Qt::WA_WState_Created) + || (!w->internalWinId() && w->testAttribute(Qt::WA_NativeWindow)))) { + if (w!=q) { + w->create(); + } else { + w->create(winid); + // if the window has already been created, we + // need to raise it to its proper stacking position + if (winid) + w->raise(); + } + } + } + } else { + q->create(); + } +#else + Q_UNUSED(winid); + q->create(); +#endif //Q_WS_QPA + + } +} + + +/*! +\internal +Ensures that the widget has a window system identifier, i.e. that it is known to the windowing system. + +*/ + +void QWidget::createWinId() +{ + Q_D(QWidget); +#ifdef ALIEN_DEBUG + qDebug() << "QWidget::createWinId" << this; +#endif +// qWarning("QWidget::createWinId is obsolete, please fix your code."); + d->createWinId(); +} + +/*! + \since 4.4 + + Returns the effective window system identifier of the widget, i.e. the + native parent's window system identifier. + + If the widget is native, this function returns the native widget ID. + Otherwise, the window ID of the first native parent widget, i.e., the + top-level widget that contains this widget, is returned. + + \note We recommend that you do not store this value as it is likely to + change at run-time. + + \sa nativeParentWidget() +*/ +WId QWidget::effectiveWinId() const +{ + WId id = internalWinId(); + if (id || !testAttribute(Qt::WA_WState_Created)) + return id; + QWidget *realParent = nativeParentWidget(); + Q_ASSERT(realParent); + Q_ASSERT(realParent->internalWinId()); + return realParent->internalWinId(); +} + +#ifndef QT_NO_STYLE_STYLESHEET + +/*! + \property QWidget::styleSheet + \brief the widget's style sheet + \since 4.2 + + The style sheet contains a textual description of customizations to the + widget's style, as described in the \l{Qt Style Sheets} document. + + Since Qt 4.5, Qt style sheets fully supports Mac OS X. + + \warning Qt style sheets are currently not supported for custom QStyle + subclasses. We plan to address this in some future release. + + \sa setStyle(), QApplication::styleSheet, {Qt Style Sheets} +*/ +QString QWidget::styleSheet() const +{ + Q_D(const QWidget); + if (!d->extra) + return QString(); + return d->extra->styleSheet; +} + +void QWidget::setStyleSheet(const QString& styleSheet) +{ + Q_D(QWidget); + d->createExtra(); + + QStyleSheetStyle *proxy = qobject_cast(d->extra->style); + d->extra->styleSheet = styleSheet; + if (styleSheet.isEmpty()) { // stylesheet removed + if (!proxy) + return; + + d->inheritStyle(); + return; + } + + if (proxy) { // style sheet update + proxy->repolish(this); + return; + } + + if (testAttribute(Qt::WA_SetStyle)) { + d->setStyle_helper(new QStyleSheetStyle(d->extra->style), true); + } else { + d->setStyle_helper(new QStyleSheetStyle(0), true); + } +} + +#endif // QT_NO_STYLE_STYLESHEET + +/*! + \sa QWidget::setStyle(), QApplication::setStyle(), QApplication::style() +*/ + +QStyle *QWidget::style() const +{ + Q_D(const QWidget); + + if (d->extra && d->extra->style) + return d->extra->style; + return QApplication::style(); +} + +/*! + Sets the widget's GUI style to \a style. The ownership of the style + object is not transferred. + + If no style is set, the widget uses the application's style, + QApplication::style() instead. + + Setting a widget's style has no effect on existing or future child + widgets. + + \warning This function is particularly useful for demonstration + purposes, where you want to show Qt's styling capabilities. Real + applications should avoid it and use one consistent GUI style + instead. + + \warning Qt style sheets are currently not supported for custom QStyle + subclasses. We plan to address this in some future release. + + \sa style(), QStyle, QApplication::style(), QApplication::setStyle() +*/ + +void QWidget::setStyle(QStyle *style) +{ + Q_D(QWidget); + setAttribute(Qt::WA_SetStyle, style != 0); + d->createExtra(); +#ifndef QT_NO_STYLE_STYLESHEET + if (QStyleSheetStyle *proxy = qobject_cast(style)) { + //if for some reason someone try to set a QStyleSheetStyle, ref it + //(this may happen for exemple in QButtonDialogBox which propagates its style) + proxy->ref(); + d->setStyle_helper(style, false); + } else if (qobject_cast(d->extra->style) || !qApp->styleSheet().isEmpty()) { + // if we have an application stylesheet or have a proxy already, propagate + d->setStyle_helper(new QStyleSheetStyle(style), true); + } else +#endif + d->setStyle_helper(style, false); +} + +void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool +#ifdef Q_WS_MAC + metalHack +#endif + ) +{ + Q_Q(QWidget); + QStyle *oldStyle = q->style(); +#ifndef QT_NO_STYLE_STYLESHEET + QWeakPointer origStyle; +#endif + +#ifdef Q_WS_MAC + // the metalhack boolean allows Qt/Mac to do a proper re-polish depending + // on how the Qt::WA_MacBrushedMetal attribute is set. It is only ever + // set when changing that attribute and passes the widget's CURRENT style. + // therefore no need to do a reassignment. + if (!metalHack) +#endif + { + createExtra(); + +#ifndef QT_NO_STYLE_STYLESHEET + origStyle = extra->style.data(); +#endif + extra->style = newStyle; + } + + // repolish + if (q->windowType() != Qt::Desktop) { + if (polished) { + oldStyle->unpolish(q); +#ifdef Q_WS_MAC + if (metalHack) + macUpdateMetalAttribute(); +#endif + q->style()->polish(q); +#ifdef Q_WS_MAC + } else if (metalHack) { + macUpdateMetalAttribute(); +#endif + } + } + + if (propagate) { + for (int i = 0; i < children.size(); ++i) { + QWidget *c = qobject_cast(children.at(i)); + if (c) + c->d_func()->inheritStyle(); + } + } + +#ifndef QT_NO_STYLE_STYLESHEET + if (!qobject_cast(newStyle)) { + if (const QStyleSheetStyle* cssStyle = qobject_cast(origStyle.data())) { + cssStyle->clearWidgetFont(q); + } + } +#endif + + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(q, &e); +#ifdef QT3_SUPPORT + q->styleChange(*oldStyle); +#endif + +#ifndef QT_NO_STYLE_STYLESHEET + // dereference the old stylesheet style + if (QStyleSheetStyle *proxy = qobject_cast(origStyle.data())) + proxy->deref(); +#endif +} + +// Inherits style from the current parent and propagates it as necessary +void QWidgetPrivate::inheritStyle() +{ +#ifndef QT_NO_STYLE_STYLESHEET + Q_Q(QWidget); + + QStyleSheetStyle *proxy = extra ? qobject_cast(extra->style) : 0; + + if (!q->styleSheet().isEmpty()) { + Q_ASSERT(proxy); + proxy->repolish(q); + return; + } + + QStyle *origStyle = proxy ? proxy->base : (extra ? (QStyle*)extra->style : 0); + QWidget *parent = q->parentWidget(); + QStyle *parentStyle = (parent && parent->d_func()->extra) ? (QStyle*)parent->d_func()->extra->style : 0; + // If we have stylesheet on app or parent has stylesheet style, we need + // to be running a proxy + if (!qApp->styleSheet().isEmpty() || qobject_cast(parentStyle)) { + QStyle *newStyle = parentStyle; + if (q->testAttribute(Qt::WA_SetStyle)) + newStyle = new QStyleSheetStyle(origStyle); + else if (QStyleSheetStyle *newProxy = qobject_cast(parentStyle)) + newProxy->ref(); + + setStyle_helper(newStyle, true); + return; + } + + // So, we have no stylesheet on parent/app and we have an empty stylesheet + // we just need our original style back + if (origStyle == (extra ? (QStyle*)extra->style : 0)) // is it any different? + return; + + // We could have inherited the proxy from our parent (which has a custom style) + // In such a case we need to start following the application style (i.e revert + // the propagation behavior of QStyleSheetStyle) + if (!q->testAttribute(Qt::WA_SetStyle)) + origStyle = 0; + + setStyle_helper(origStyle, true); +#endif // QT_NO_STYLE_STYLESHEET +} + +#ifdef QT3_SUPPORT +/*! + \overload + + Sets the widget's GUI style to \a style using the QStyleFactory. +*/ +QStyle* QWidget::setStyle(const QString &style) +{ + QStyle *s = QStyleFactory::create(style); + setStyle(s); + return s; +} +#endif + +/*! + \fn bool QWidget::isWindow() const + + Returns true if the widget is an independent window, otherwise + returns false. + + A window is a widget that isn't visually the child of any other + widget and that usually has a frame and a + \l{QWidget::setWindowTitle()}{window title}. + + A window can have a \l{QWidget::parentWidget()}{parent widget}. + It will then be grouped with its parent and deleted when the + parent is deleted, minimized when the parent is minimized etc. If + supported by the window manager, it will also have a common + taskbar entry with its parent. + + QDialog and QMainWindow widgets are by default windows, even if a + parent widget is specified in the constructor. This behavior is + specified by the Qt::Window flag. + + \sa window(), isModal(), parentWidget() +*/ + +/*! + \property QWidget::modal + \brief whether the widget is a modal widget + + This property only makes sense for windows. A modal widget + prevents widgets in all other windows from getting any input. + + By default, this property is false. + + \sa isWindow(), windowModality, QDialog +*/ + +/*! + \property QWidget::windowModality + \brief which windows are blocked by the modal widget + \since 4.1 + + This property only makes sense for windows. A modal widget + prevents widgets in other windows from getting input. The value of + this property controls which windows are blocked when the widget + is visible. Changing this property while the window is visible has + no effect; you must hide() the widget first, then show() it again. + + By default, this property is Qt::NonModal. + + \sa isWindow(), QWidget::modal, QDialog +*/ + +Qt::WindowModality QWidget::windowModality() const +{ + return static_cast(data->window_modality); +} + +void QWidget::setWindowModality(Qt::WindowModality windowModality) +{ + data->window_modality = windowModality; + // setModal_sys() will be called by setAttribute() + setAttribute(Qt::WA_ShowModal, (data->window_modality != Qt::NonModal)); + setAttribute(Qt::WA_SetWindowModality, true); +} + +/*! + \fn bool QWidget::underMouse() const + + Returns true if the widget is under the mouse cursor; otherwise + returns false. + + This value is not updated properly during drag and drop + operations. + + \sa enterEvent(), leaveEvent() +*/ + +/*! + \property QWidget::minimized + \brief whether this widget is minimized (iconified) + + This property is only relevant for windows. + + By default, this property is false. + + \sa showMinimized(), visible, show(), hide(), showNormal(), maximized +*/ +bool QWidget::isMinimized() const +{ return data->window_state & Qt::WindowMinimized; } + +/*! + Shows the widget minimized, as an icon. + + Calling this function only affects \l{isWindow()}{windows}. + + \sa showNormal(), showMaximized(), show(), hide(), isVisible(), + isMinimized() +*/ +void QWidget::showMinimized() +{ + bool isMin = isMinimized(); + if (isMin && isVisible()) + return; + + ensurePolished(); +#ifdef QT3_SUPPORT + if (parent()) + QApplication::sendPostedEvents(parent(), QEvent::ChildInserted); +#endif + + if (!isMin) + setWindowState((windowState() & ~Qt::WindowActive) | Qt::WindowMinimized); + show(); +} + +/*! + \property QWidget::maximized + \brief whether this widget is maximized + + This property is only relevant for windows. + + \note Due to limitations on some window systems, this does not always + report the expected results (e.g., if the user on X11 maximizes the + window via the window manager, Qt has no way of distinguishing this + from any other resize). This is expected to improve as window manager + protocols evolve. + + By default, this property is false. + + \sa windowState(), showMaximized(), visible, show(), hide(), showNormal(), minimized +*/ +bool QWidget::isMaximized() const +{ return data->window_state & Qt::WindowMaximized; } + + + +/*! + Returns the current window state. The window state is a OR'ed + combination of Qt::WindowState: Qt::WindowMinimized, + Qt::WindowMaximized, Qt::WindowFullScreen, and Qt::WindowActive. + + \sa Qt::WindowState setWindowState() + */ +Qt::WindowStates QWidget::windowState() const +{ + return Qt::WindowStates(data->window_state); +} + +/*!\internal + + The function sets the window state on child widgets similar to + setWindowState(). The difference is that the window state changed + event has the isOverride() flag set. It exists mainly to keep + Q3Workspace working. + */ +void QWidget::overrideWindowState(Qt::WindowStates newstate) +{ + QWindowStateChangeEvent e(Qt::WindowStates(data->window_state), true); + data->window_state = newstate; + QApplication::sendEvent(this, &e); +} + +/*! + \fn void QWidget::setWindowState(Qt::WindowStates windowState) + + Sets the window state to \a windowState. The window state is a OR'ed + combination of Qt::WindowState: Qt::WindowMinimized, + Qt::WindowMaximized, Qt::WindowFullScreen, and Qt::WindowActive. + + If the window is not visible (i.e. isVisible() returns false), the + window state will take effect when show() is called. For visible + windows, the change is immediate. For example, to toggle between + full-screen and normal mode, use the following code: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 0 + + In order to restore and activate a minimized window (while + preserving its maximized and/or full-screen state), use the following: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 1 + + Calling this function will hide the widget. You must call show() to make + the widget visible again. + + \note On some window systems Qt::WindowActive is not immediate, and may be + ignored in certain cases. + + When the window state changes, the widget receives a changeEvent() + of type QEvent::WindowStateChange. + + \sa Qt::WindowState windowState() +*/ + +/*! + \property QWidget::fullScreen + \brief whether the widget is shown in full screen mode + + A widget in full screen mode occupies the whole screen area and does not + display window decorations, such as a title bar. + + By default, this property is false. + + \sa windowState(), minimized, maximized +*/ +bool QWidget::isFullScreen() const +{ return data->window_state & Qt::WindowFullScreen; } + +/*! + Shows the widget in full-screen mode. + + Calling this function only affects \l{isWindow()}{windows}. + + To return from full-screen mode, call showNormal(). + + Full-screen mode works fine under Windows, but has certain + problems under X. These problems are due to limitations of the + ICCCM protocol that specifies the communication between X11 + clients and the window manager. ICCCM simply does not understand + the concept of non-decorated full-screen windows. Therefore, the + best we can do is to request a borderless window and place and + resize it to fill the entire screen. Depending on the window + manager, this may or may not work. The borderless window is + requested using MOTIF hints, which are at least partially + supported by virtually all modern window managers. + + An alternative would be to bypass the window manager entirely and + create a window with the Qt::X11BypassWindowManagerHint flag. This + has other severe problems though, like totally broken keyboard focus + and very strange effects on desktop changes or when the user raises + other windows. + + X11 window managers that follow modern post-ICCCM specifications + support full-screen mode properly. + + \sa showNormal(), showMaximized(), show(), hide(), isVisible() +*/ +void QWidget::showFullScreen() +{ +#ifdef Q_WS_MAC + // If the unified toolbar is enabled, we have to disable it before going fullscreen. + QMainWindow *mainWindow = qobject_cast(this); + if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) { + mainWindow->setUnifiedTitleAndToolBarOnMac(false); + QMainWindowLayout *mainLayout = qobject_cast(mainWindow->layout()); + mainLayout->activateUnifiedToolbarAfterFullScreen = true; + } +#endif // Q_WS_MAC + ensurePolished(); +#ifdef QT3_SUPPORT + if (parent()) + QApplication::sendPostedEvents(parent(), QEvent::ChildInserted); +#endif + + setWindowState((windowState() & ~(Qt::WindowMinimized | Qt::WindowMaximized)) + | Qt::WindowFullScreen); + show(); + activateWindow(); +} + +/*! + Shows the widget maximized. + + Calling this function only affects \l{isWindow()}{windows}. + + On X11, this function may not work properly with certain window + managers. See the \l{Window Geometry} documentation for an explanation. + + \sa setWindowState(), showNormal(), showMinimized(), show(), hide(), isVisible() +*/ +void QWidget::showMaximized() +{ + ensurePolished(); +#ifdef QT3_SUPPORT + if (parent()) + QApplication::sendPostedEvents(parent(), QEvent::ChildInserted); +#endif + + setWindowState((windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) + | Qt::WindowMaximized); +#ifdef Q_WS_MAC + // If the unified toolbar was enabled before going fullscreen, we have to enable it back. + QMainWindow *mainWindow = qobject_cast(this); + if (mainWindow) + { + QMainWindowLayout *mainLayout = qobject_cast(mainWindow->layout()); + if (mainLayout->activateUnifiedToolbarAfterFullScreen) { + mainWindow->setUnifiedTitleAndToolBarOnMac(true); + mainLayout->activateUnifiedToolbarAfterFullScreen = false; + } + } +#endif // Q_WS_MAC + show(); +} + +/*! + Restores the widget after it has been maximized or minimized. + + Calling this function only affects \l{isWindow()}{windows}. + + \sa setWindowState(), showMinimized(), showMaximized(), show(), hide(), isVisible() +*/ +void QWidget::showNormal() +{ + ensurePolished(); +#ifdef QT3_SUPPORT + if (parent()) + QApplication::sendPostedEvents(parent(), QEvent::ChildInserted); +#endif + + setWindowState(windowState() & ~(Qt::WindowMinimized + | Qt::WindowMaximized + | Qt::WindowFullScreen)); +#ifdef Q_WS_MAC + // If the unified toolbar was enabled before going fullscreen, we have to enable it back. + QMainWindow *mainWindow = qobject_cast(this); + if (mainWindow) + { + QMainWindowLayout *mainLayout = qobject_cast(mainWindow->layout()); + if (mainLayout->activateUnifiedToolbarAfterFullScreen) { + mainWindow->setUnifiedTitleAndToolBarOnMac(true); + mainLayout->activateUnifiedToolbarAfterFullScreen = false; + } + } +#endif // Q_WS_MAC + show(); +} + +/*! + Returns true if this widget would become enabled if \a ancestor is + enabled; otherwise returns false. + + + + This is the case if neither the widget itself nor every parent up + to but excluding \a ancestor has been explicitly disabled. + + isEnabledTo(0) is equivalent to isEnabled(). + + \sa setEnabled() enabled +*/ + +bool QWidget::isEnabledTo(QWidget* ancestor) const +{ + const QWidget * w = this; + while (!w->testAttribute(Qt::WA_ForceDisabled) + && !w->isWindow() + && w->parentWidget() + && w->parentWidget() != ancestor) + w = w->parentWidget(); + return !w->testAttribute(Qt::WA_ForceDisabled); +} + +#ifndef QT_NO_ACTION +/*! + Appends the action \a action to this widget's list of actions. + + All QWidgets have a list of \l{QAction}s, however they can be + represented graphically in many different ways. The default use of + the QAction list (as returned by actions()) is to create a context + QMenu. + + A QWidget should only have one of each action and adding an action + it already has will not cause the same action to be in the widget twice. + + The ownership of \a action is not transferred to this QWidget. + + \sa removeAction(), insertAction(), actions(), QMenu +*/ +void QWidget::addAction(QAction *action) +{ + insertAction(0, action); +} + +/*! + Appends the actions \a actions to this widget's list of actions. + + \sa removeAction(), QMenu, addAction() +*/ +void QWidget::addActions(QList actions) +{ + for(int i = 0; i < actions.count(); i++) + insertAction(0, actions.at(i)); +} + +/*! + Inserts the action \a action to this widget's list of actions, + before the action \a before. It appends the action if \a before is 0 or + \a before is not a valid action for this widget. + + A QWidget should only have one of each action. + + \sa removeAction(), addAction(), QMenu, contextMenuPolicy, actions() +*/ +void QWidget::insertAction(QAction *before, QAction *action) +{ + if(!action) { + qWarning("QWidget::insertAction: Attempt to insert null action"); + return; + } + + Q_D(QWidget); + if(d->actions.contains(action)) + removeAction(action); + + int pos = d->actions.indexOf(before); + if (pos < 0) { + before = 0; + pos = d->actions.size(); + } + d->actions.insert(pos, action); + + QActionPrivate *apriv = action->d_func(); + apriv->widgets.append(this); + + QActionEvent e(QEvent::ActionAdded, action, before); + QApplication::sendEvent(this, &e); +} + +/*! + Inserts the actions \a actions to this widget's list of actions, + before the action \a before. It appends the action if \a before is 0 or + \a before is not a valid action for this widget. + + A QWidget can have at most one of each action. + + \sa removeAction(), QMenu, insertAction(), contextMenuPolicy +*/ +void QWidget::insertActions(QAction *before, QList actions) +{ + for(int i = 0; i < actions.count(); ++i) + insertAction(before, actions.at(i)); +} + +/*! + Removes the action \a action from this widget's list of actions. + \sa insertAction(), actions(), insertAction() +*/ +void QWidget::removeAction(QAction *action) +{ + if (!action) + return; + + Q_D(QWidget); + + QActionPrivate *apriv = action->d_func(); + apriv->widgets.removeAll(this); + + if (d->actions.removeAll(action)) { + QActionEvent e(QEvent::ActionRemoved, action); + QApplication::sendEvent(this, &e); + } +} + +/*! + Returns the (possibly empty) list of this widget's actions. + + \sa contextMenuPolicy, insertAction(), removeAction() +*/ +QList QWidget::actions() const +{ + Q_D(const QWidget); + return d->actions; +} +#endif // QT_NO_ACTION + +/*! + \fn bool QWidget::isEnabledToTLW() const + \obsolete + + This function is deprecated. It is equivalent to isEnabled() +*/ + +/*! + \property QWidget::enabled + \brief whether the widget is enabled + + An enabled widget handles keyboard and mouse events; a disabled + widget does not. + + Some widgets display themselves differently when they are + disabled. For example a button might draw its label grayed out. If + your widget needs to know when it becomes enabled or disabled, you + can use the changeEvent() with type QEvent::EnabledChange. + + Disabling a widget implicitly disables all its children. Enabling + respectively enables all child widgets unless they have been + explicitly disabled. + + By default, this property is true. + + \sa isEnabledTo(), QKeyEvent, QMouseEvent, changeEvent() +*/ +void QWidget::setEnabled(bool enable) +{ + Q_D(QWidget); + setAttribute(Qt::WA_ForceDisabled, !enable); + d->setEnabled_helper(enable); +} + +void QWidgetPrivate::setEnabled_helper(bool enable) +{ + Q_Q(QWidget); + + if (enable && !q->isWindow() && q->parentWidget() && !q->parentWidget()->isEnabled()) + return; // nothing we can do + + if (enable != q->testAttribute(Qt::WA_Disabled)) + return; // nothing to do + + q->setAttribute(Qt::WA_Disabled, !enable); + updateSystemBackground(); + + if (!enable && q->window()->focusWidget() == q) { + bool parentIsEnabled = (!q->parentWidget() || q->parentWidget()->isEnabled()); + if (!parentIsEnabled || !q->focusNextChild()) + q->clearFocus(); + } + + Qt::WidgetAttribute attribute = enable ? Qt::WA_ForceDisabled : Qt::WA_Disabled; + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w && !w->testAttribute(attribute)) + w->d_func()->setEnabled_helper(enable); + } +#if defined(Q_WS_X11) + if (q->testAttribute(Qt::WA_SetCursor) || q->isWindow()) { + // enforce the windows behavior of clearing the cursor on + // disabled widgets + qt_x11_enforce_cursor(q); + } +#endif +#if defined(Q_WS_MAC) + setEnabled_helper_sys(enable); +#endif +#ifndef QT_NO_IM + if (q->testAttribute(Qt::WA_InputMethodEnabled) && q->hasFocus()) { + QWidget *focusWidget = effectiveFocusWidget(); + QInputContext *qic = focusWidget->d_func()->inputContext(); + if (enable) { + if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) + qic->setFocusWidget(focusWidget); + } else { + qic->reset(); + qic->setFocusWidget(0); + } + } +#endif //QT_NO_IM + QEvent e(QEvent::EnabledChange); + QApplication::sendEvent(q, &e); +#ifdef QT3_SUPPORT + q->enabledChange(!enable); // compatibility +#endif +} + +/*! + \property QWidget::acceptDrops + \brief whether drop events are enabled for this widget + + Setting this property to true announces to the system that this + widget \e may be able to accept drop events. + + If the widget is the desktop (windowType() == Qt::Desktop), this may + fail if another application is using the desktop; you can call + acceptDrops() to test if this occurs. + + \warning Do not modify this property in a drag and drop event handler. + + By default, this property is false. + + \sa {Drag and Drop} +*/ +bool QWidget::acceptDrops() const +{ + return testAttribute(Qt::WA_AcceptDrops); +} + +void QWidget::setAcceptDrops(bool on) +{ + setAttribute(Qt::WA_AcceptDrops, on); + +} + +/*! + \fn void QWidget::enabledChange(bool) + + \internal + \obsolete +*/ + +/*! + \fn void QWidget::paletteChange(const QPalette &) + + \internal + \obsolete +*/ + +/*! + \fn void QWidget::fontChange(const QFont &) + + \internal + \obsolete +*/ + +/*! + \fn void QWidget::windowActivationChange(bool) + + \internal + \obsolete +*/ + +/*! + \fn void QWidget::languageChange() + + \obsolete +*/ + +/*! + \fn void QWidget::styleChange(QStyle& style) + + \internal + \obsolete +*/ + +/*! + Disables widget input events if \a disable is true; otherwise + enables input events. + + See the \l enabled documentation for more information. + + \sa isEnabledTo(), QKeyEvent, QMouseEvent, changeEvent() +*/ +void QWidget::setDisabled(bool disable) +{ + setEnabled(!disable); +} + +/*! + \property QWidget::frameGeometry + \brief geometry of the widget relative to its parent including any + window frame + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \sa geometry() x() y() pos() +*/ +QRect QWidget::frameGeometry() const +{ + Q_D(const QWidget); + if (isWindow() && ! (windowType() == Qt::Popup)) { + QRect fs = d->frameStrut(); + return QRect(data->crect.x() - fs.left(), + data->crect.y() - fs.top(), + data->crect.width() + fs.left() + fs.right(), + data->crect.height() + fs.top() + fs.bottom()); + } + return data->crect; +} + +/*! + \property QWidget::x + + \brief the x coordinate of the widget relative to its parent including + any window frame + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + By default, this property has a value of 0. + + \sa frameGeometry, y, pos +*/ +int QWidget::x() const +{ + Q_D(const QWidget); + if (isWindow() && ! (windowType() == Qt::Popup)) + return data->crect.x() - d->frameStrut().left(); + return data->crect.x(); +} + +/*! + \property QWidget::y + \brief the y coordinate of the widget relative to its parent and + including any window frame + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + By default, this property has a value of 0. + + \sa frameGeometry, x, pos +*/ +int QWidget::y() const +{ + Q_D(const QWidget); + if (isWindow() && ! (windowType() == Qt::Popup)) + return data->crect.y() - d->frameStrut().top(); + return data->crect.y(); +} + +/*! + \property QWidget::pos + \brief the position of the widget within its parent widget + + If the widget is a window, the position is that of the widget on + the desktop, including its frame. + + When changing the position, the widget, if visible, receives a + move event (moveEvent()) immediately. If the widget is not + currently visible, it is guaranteed to receive an event before it + is shown. + + By default, this property contains a position that refers to the + origin. + + \warning Calling move() or setGeometry() inside moveEvent() can + lead to infinite recursion. + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + \sa frameGeometry, size x(), y() +*/ +QPoint QWidget::pos() const +{ + Q_D(const QWidget); + if (isWindow() && ! (windowType() == Qt::Popup)) { + QRect fs = d->frameStrut(); + return QPoint(data->crect.x() - fs.left(), data->crect.y() - fs.top()); + } + return data->crect.topLeft(); +} + +/*! + \property QWidget::geometry + \brief the geometry of the widget relative to its parent and + excluding the window frame + + When changing the geometry, the widget, if visible, receives a + move event (moveEvent()) and/or a resize event (resizeEvent()) + immediately. If the widget is not currently visible, it is + guaranteed to receive appropriate events before it is shown. + + The size component is adjusted if it lies outside the range + defined by minimumSize() and maximumSize(). + + \warning Calling setGeometry() inside resizeEvent() or moveEvent() + can lead to infinite recursion. + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \sa frameGeometry(), rect(), move(), resize(), moveEvent(), + resizeEvent(), minimumSize(), maximumSize() +*/ + +/*! + \property QWidget::normalGeometry + + \brief the geometry of the widget as it will appear when shown as + a normal (not maximized or full screen) top-level widget + + For child widgets this property always holds an empty rectangle. + + By default, this property contains an empty rectangle. + + \sa QWidget::windowState(), QWidget::geometry +*/ + +/*! + \property QWidget::size + \brief the size of the widget excluding any window frame + + If the widget is visible when it is being resized, it receives a resize event + (resizeEvent()) immediately. If the widget is not currently + visible, it is guaranteed to receive an event before it is shown. + + The size is adjusted if it lies outside the range defined by + minimumSize() and maximumSize(). + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \warning Calling resize() or setGeometry() inside resizeEvent() can + lead to infinite recursion. + + \note Setting the size to \c{QSize(0, 0)} will cause the widget to not + appear on screen. This also applies to windows. + + \sa pos, geometry, minimumSize, maximumSize, resizeEvent(), adjustSize() +*/ + +/*! + \property QWidget::width + \brief the width of the widget excluding any window frame + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + \note Do not use this function to find the width of a screen on + a \l{QDesktopWidget}{multiple screen desktop}. Read + \l{QDesktopWidget#Screen Geometry}{this note} for details. + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \sa geometry, height, size +*/ + +/*! + \property QWidget::height + \brief the height of the widget excluding any window frame + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + \note Do not use this function to find the height of a screen + on a \l{QDesktopWidget}{multiple screen desktop}. Read + \l{QDesktopWidget#Screen Geometry}{this note} for details. + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \sa geometry, width, size +*/ + +/*! + \property QWidget::rect + \brief the internal geometry of the widget excluding any window + frame + + The rect property equals QRect(0, 0, width(), height()). + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + By default, this property contains a value that depends on the user's + platform and screen geometry. + + \sa size +*/ + + +QRect QWidget::normalGeometry() const +{ + Q_D(const QWidget); + if (!d->extra || !d->extra->topextra) + return QRect(); + + if (!isMaximized() && !isFullScreen()) + return geometry(); + + return d->topData()->normalGeometry; +} + + +/*! + \property QWidget::childrenRect + \brief the bounding rectangle of the widget's children + + Hidden children are excluded. + + By default, for a widget with no children, this property contains a + rectangle with zero width and height located at the origin. + + \sa childrenRegion() geometry() +*/ + +QRect QWidget::childrenRect() const +{ + Q_D(const QWidget); + QRect r(0, 0, 0, 0); + for (int i = 0; i < d->children.size(); ++i) { + QWidget *w = qobject_cast(d->children.at(i)); + if (w && !w->isWindow() && !w->isHidden()) + r |= w->geometry(); + } + return r; +} + +/*! + \property QWidget::childrenRegion + \brief the combined region occupied by the widget's children + + Hidden children are excluded. + + By default, for a widget with no children, this property contains an + empty region. + + \sa childrenRect() geometry() mask() +*/ + +QRegion QWidget::childrenRegion() const +{ + Q_D(const QWidget); + QRegion r; + for (int i = 0; i < d->children.size(); ++i) { + QWidget *w = qobject_cast(d->children.at(i)); + if (w && !w->isWindow() && !w->isHidden()) { + QRegion mask = w->mask(); + if (mask.isEmpty()) + r |= w->geometry(); + else + r |= mask.translated(w->pos()); + } + } + return r; +} + + +/*! + \property QWidget::minimumSize + \brief the widget's minimum size + + The widget cannot be resized to a smaller size than the minimum + widget size. The widget's size is forced to the minimum size if + the current size is smaller. + + The minimum size set by this function will override the minimum size + defined by QLayout. In order to unset the minimum size, use a + value of \c{QSize(0, 0)}. + + By default, this property contains a size with zero width and height. + + \sa minimumWidth, minimumHeight, maximumSize, sizeIncrement +*/ + +QSize QWidget::minimumSize() const +{ + Q_D(const QWidget); + return d->extra ? QSize(d->extra->minw, d->extra->minh) : QSize(0, 0); +} + +/*! + \property QWidget::maximumSize + \brief the widget's maximum size in pixels + + The widget cannot be resized to a larger size than the maximum + widget size. + + By default, this property contains a size in which both width and height + have values of 16777215. + + \note The definition of the \c QWIDGETSIZE_MAX macro limits the maximum size + of widgets. + + \sa maximumWidth, maximumHeight, minimumSize, sizeIncrement +*/ + +QSize QWidget::maximumSize() const +{ + Q_D(const QWidget); + return d->extra ? QSize(d->extra->maxw, d->extra->maxh) + : QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); +} + + +/*! + \property QWidget::minimumWidth + \brief the widget's minimum width in pixels + + This property corresponds to the width held by the \l minimumSize property. + + By default, this property has a value of 0. + + \sa minimumSize, minimumHeight +*/ + +/*! + \property QWidget::minimumHeight + \brief the widget's minimum height in pixels + + This property corresponds to the height held by the \l minimumSize property. + + By default, this property has a value of 0. + + \sa minimumSize, minimumWidth +*/ + +/*! + \property QWidget::maximumWidth + \brief the widget's maximum width in pixels + + This property corresponds to the width held by the \l maximumSize property. + + By default, this property contains a value of 16777215. + + \note The definition of the \c QWIDGETSIZE_MAX macro limits the maximum size + of widgets. + + \sa maximumSize, maximumHeight +*/ + +/*! + \property QWidget::maximumHeight + \brief the widget's maximum height in pixels + + This property corresponds to the height held by the \l maximumSize property. + + By default, this property contains a value of 16777215. + + \note The definition of the \c QWIDGETSIZE_MAX macro limits the maximum size + of widgets. + + \sa maximumSize, maximumWidth +*/ + +/*! + \property QWidget::sizeIncrement + \brief the size increment of the widget + + When the user resizes the window, the size will move in steps of + sizeIncrement().width() pixels horizontally and + sizeIncrement.height() pixels vertically, with baseSize() as the + basis. Preferred widget sizes are for non-negative integers \e i + and \e j: + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 2 + + Note that while you can set the size increment for all widgets, it + only affects windows. + + By default, this property contains a size with zero width and height. + + \warning The size increment has no effect under Windows, and may + be disregarded by the window manager on X11. + + \sa size, minimumSize, maximumSize +*/ +QSize QWidget::sizeIncrement() const +{ + Q_D(const QWidget); + return (d->extra && d->extra->topextra) + ? QSize(d->extra->topextra->incw, d->extra->topextra->inch) + : QSize(0, 0); +} + +/*! + \property QWidget::baseSize + \brief the base size of the widget + + The base size is used to calculate a proper widget size if the + widget defines sizeIncrement(). + + By default, for a newly-created widget, this property contains a size with + zero width and height. + + \sa setSizeIncrement() +*/ + +QSize QWidget::baseSize() const +{ + Q_D(const QWidget); + return (d->extra != 0 && d->extra->topextra != 0) + ? QSize(d->extra->topextra->basew, d->extra->topextra->baseh) + : QSize(0, 0); +} + +bool QWidgetPrivate::setMinimumSize_helper(int &minw, int &minh) +{ + Q_Q(QWidget); + +#ifdef Q_WS_QWS + if (q->isWindow()) { + const QRect maxWindowRect = QApplication::desktop()->availableGeometry(QApplication::desktop()->screenNumber(q)); + if (!maxWindowRect.isEmpty()) { + // ### This is really just a work-around. Layout shouldn't be + // asking for minimum sizes bigger than the screen. + if (minw > maxWindowRect.width()) + minw = maxWindowRect.width(); + if (minh > maxWindowRect.height()) + minh = maxWindowRect.height(); + } + } +#endif + int mw = minw, mh = minh; + if (mw == QWIDGETSIZE_MAX) + mw = 0; + if (mh == QWIDGETSIZE_MAX) + mh = 0; + if (minw > QWIDGETSIZE_MAX || minh > QWIDGETSIZE_MAX) { + qWarning("QWidget::setMinimumSize: (%s/%s) " + "The largest allowed size is (%d,%d)", + q->objectName().toLocal8Bit().data(), q->metaObject()->className(), QWIDGETSIZE_MAX, + QWIDGETSIZE_MAX); + minw = mw = qMin(minw, QWIDGETSIZE_MAX); + minh = mh = qMin(minh, QWIDGETSIZE_MAX); + } + if (minw < 0 || minh < 0) { + qWarning("QWidget::setMinimumSize: (%s/%s) Negative sizes (%d,%d) " + "are not possible", + q->objectName().toLocal8Bit().data(), q->metaObject()->className(), minw, minh); + minw = mw = qMax(minw, 0); + minh = mh = qMax(minh, 0); + } + createExtra(); + if (extra->minw == mw && extra->minh == mh) + return false; + extra->minw = mw; + extra->minh = mh; + extra->explicitMinSize = (mw ? Qt::Horizontal : 0) | (mh ? Qt::Vertical : 0); + return true; +} + +/*! + \overload + + This function corresponds to setMinimumSize(QSize(minw, minh)). + Sets the minimum width to \a minw and the minimum height to \a + minh. +*/ + +void QWidget::setMinimumSize(int minw, int minh) +{ + Q_D(QWidget); + if (!d->setMinimumSize_helper(minw, minh)) + return; + + if (isWindow()) + d->setConstraints_sys(); + if (minw > width() || minh > height()) { + bool resized = testAttribute(Qt::WA_Resized); + bool maximized = isMaximized(); + resize(qMax(minw,width()), qMax(minh,height())); + setAttribute(Qt::WA_Resized, resized); //not a user resize + if (maximized) + data->window_state = data->window_state | Qt::WindowMaximized; + } +#ifndef QT_NO_GRAPHICSVIEW + if (d->extra) { + if (d->extra->proxyWidget) + d->extra->proxyWidget->setMinimumSize(minw, minh); + } +#endif + d->updateGeometry_helper(d->extra->minw == d->extra->maxw && d->extra->minh == d->extra->maxh); +} + +bool QWidgetPrivate::setMaximumSize_helper(int &maxw, int &maxh) +{ + Q_Q(QWidget); + if (maxw > QWIDGETSIZE_MAX || maxh > QWIDGETSIZE_MAX) { + qWarning("QWidget::setMaximumSize: (%s/%s) " + "The largest allowed size is (%d,%d)", + q->objectName().toLocal8Bit().data(), q->metaObject()->className(), QWIDGETSIZE_MAX, + QWIDGETSIZE_MAX); + maxw = qMin(maxw, QWIDGETSIZE_MAX); + maxh = qMin(maxh, QWIDGETSIZE_MAX); + } + if (maxw < 0 || maxh < 0) { + qWarning("QWidget::setMaximumSize: (%s/%s) Negative sizes (%d,%d) " + "are not possible", + q->objectName().toLocal8Bit().data(), q->metaObject()->className(), maxw, maxh); + maxw = qMax(maxw, 0); + maxh = qMax(maxh, 0); + } + createExtra(); + if (extra->maxw == maxw && extra->maxh == maxh) + return false; + extra->maxw = maxw; + extra->maxh = maxh; + extra->explicitMaxSize = (maxw != QWIDGETSIZE_MAX ? Qt::Horizontal : 0) | + (maxh != QWIDGETSIZE_MAX ? Qt::Vertical : 0); + return true; +} + +/*! + \overload + + This function corresponds to setMaximumSize(QSize(\a maxw, \a + maxh)). Sets the maximum width to \a maxw and the maximum height + to \a maxh. +*/ +void QWidget::setMaximumSize(int maxw, int maxh) +{ + Q_D(QWidget); + if (!d->setMaximumSize_helper(maxw, maxh)) + return; + + if (isWindow()) + d->setConstraints_sys(); + if (maxw < width() || maxh < height()) { + bool resized = testAttribute(Qt::WA_Resized); + resize(qMin(maxw,width()), qMin(maxh,height())); + setAttribute(Qt::WA_Resized, resized); //not a user resize + } + +#ifndef QT_NO_GRAPHICSVIEW + if (d->extra) { + if (d->extra->proxyWidget) + d->extra->proxyWidget->setMaximumSize(maxw, maxh); + } +#endif + + d->updateGeometry_helper(d->extra->minw == d->extra->maxw && d->extra->minh == d->extra->maxh); +} + +/*! + \overload + + Sets the x (width) size increment to \a w and the y (height) size + increment to \a h. +*/ +void QWidget::setSizeIncrement(int w, int h) +{ + Q_D(QWidget); + d->createTLExtra(); + QTLWExtra* x = d->topData(); + if (x->incw == w && x->inch == h) + return; + x->incw = w; + x->inch = h; + if (isWindow()) + d->setConstraints_sys(); +} + +/*! + \overload + + This corresponds to setBaseSize(QSize(\a basew, \a baseh)). Sets + the widgets base size to width \a basew and height \a baseh. +*/ +void QWidget::setBaseSize(int basew, int baseh) +{ + Q_D(QWidget); + d->createTLExtra(); + QTLWExtra* x = d->topData(); + if (x->basew == basew && x->baseh == baseh) + return; + x->basew = basew; + x->baseh = baseh; + if (isWindow()) + d->setConstraints_sys(); +} + +/*! + Sets both the minimum and maximum sizes of the widget to \a s, + thereby preventing it from ever growing or shrinking. + + This will override the default size constraints set by QLayout. + + To remove constraints, set the size to QWIDGETSIZE_MAX. + + Alternatively, if you want the widget to have a + fixed size based on its contents, you can call + QLayout::setSizeConstraint(QLayout::SetFixedSize); + + \sa maximumSize, minimumSize +*/ + +void QWidget::setFixedSize(const QSize & s) +{ + setFixedSize(s.width(), s.height()); +} + + +/*! + \fn void QWidget::setFixedSize(int w, int h) + \overload + + Sets the width of the widget to \a w and the height to \a h. +*/ + +void QWidget::setFixedSize(int w, int h) +{ + Q_D(QWidget); +#ifdef Q_WS_QWS + // temporary fix for 4.3.x. + // Should move the embedded spesific contraints in setMinimumSize_helper into QLayout + int tmpW = w; + int tmpH = h; + bool minSizeSet = d->setMinimumSize_helper(tmpW, tmpH); +#else + bool minSizeSet = d->setMinimumSize_helper(w, h); +#endif + bool maxSizeSet = d->setMaximumSize_helper(w, h); + if (!minSizeSet && !maxSizeSet) + return; + + if (isWindow()) + d->setConstraints_sys(); + else + d->updateGeometry_helper(true); + + if (w != QWIDGETSIZE_MAX || h != QWIDGETSIZE_MAX) + resize(w, h); +} + +void QWidget::setMinimumWidth(int w) +{ + Q_D(QWidget); + d->createExtra(); + uint expl = d->extra->explicitMinSize | (w ? Qt::Horizontal : 0); + setMinimumSize(w, minimumSize().height()); + d->extra->explicitMinSize = expl; +} + +void QWidget::setMinimumHeight(int h) +{ + Q_D(QWidget); + d->createExtra(); + uint expl = d->extra->explicitMinSize | (h ? Qt::Vertical : 0); + setMinimumSize(minimumSize().width(), h); + d->extra->explicitMinSize = expl; +} + +void QWidget::setMaximumWidth(int w) +{ + Q_D(QWidget); + d->createExtra(); + uint expl = d->extra->explicitMaxSize | (w == QWIDGETSIZE_MAX ? 0 : Qt::Horizontal); + setMaximumSize(w, maximumSize().height()); + d->extra->explicitMaxSize = expl; +} + +void QWidget::setMaximumHeight(int h) +{ + Q_D(QWidget); + d->createExtra(); + uint expl = d->extra->explicitMaxSize | (h == QWIDGETSIZE_MAX ? 0 : Qt::Vertical); + setMaximumSize(maximumSize().width(), h); + d->extra->explicitMaxSize = expl; +} + +/*! + Sets both the minimum and maximum width of the widget to \a w + without changing the heights. Provided for convenience. + + \sa sizeHint() minimumSize() maximumSize() setFixedSize() +*/ + +void QWidget::setFixedWidth(int w) +{ + Q_D(QWidget); + d->createExtra(); + uint explMin = d->extra->explicitMinSize | Qt::Horizontal; + uint explMax = d->extra->explicitMaxSize | Qt::Horizontal; + setMinimumSize(w, minimumSize().height()); + setMaximumSize(w, maximumSize().height()); + d->extra->explicitMinSize = explMin; + d->extra->explicitMaxSize = explMax; +} + + +/*! + Sets both the minimum and maximum heights of the widget to \a h + without changing the widths. Provided for convenience. + + \sa sizeHint() minimumSize() maximumSize() setFixedSize() +*/ + +void QWidget::setFixedHeight(int h) +{ + Q_D(QWidget); + d->createExtra(); + uint explMin = d->extra->explicitMinSize | Qt::Vertical; + uint explMax = d->extra->explicitMaxSize | Qt::Vertical; + setMinimumSize(minimumSize().width(), h); + setMaximumSize(maximumSize().width(), h); + d->extra->explicitMinSize = explMin; + d->extra->explicitMaxSize = explMax; +} + + +/*! + Translates the widget coordinate \a pos to the coordinate system + of \a parent. The \a parent must not be 0 and must be a parent + of the calling widget. + + \sa mapFrom() mapToParent() mapToGlobal() underMouse() +*/ + +QPoint QWidget::mapTo(QWidget * parent, const QPoint & pos) const +{ + QPoint p = pos; + if (parent) { + const QWidget * w = this; + while (w != parent) { + Q_ASSERT_X(w, "QWidget::mapTo(QWidget *parent, const QPoint &pos)", + "parent must be in parent hierarchy"); + p = w->mapToParent(p); + w = w->parentWidget(); + } + } + return p; +} + + +/*! + Translates the widget coordinate \a pos from the coordinate system + of \a parent to this widget's coordinate system. The \a parent + must not be 0 and must be a parent of the calling widget. + + \sa mapTo() mapFromParent() mapFromGlobal() underMouse() +*/ + +QPoint QWidget::mapFrom(QWidget * parent, const QPoint & pos) const +{ + QPoint p(pos); + if (parent) { + const QWidget * w = this; + while (w != parent) { + Q_ASSERT_X(w, "QWidget::mapFrom(QWidget *parent, const QPoint &pos)", + "parent must be in parent hierarchy"); + + p = w->mapFromParent(p); + w = w->parentWidget(); + } + } + return p; +} + + +/*! + Translates the widget coordinate \a pos to a coordinate in the + parent widget. + + Same as mapToGlobal() if the widget has no parent. + + \sa mapFromParent() mapTo() mapToGlobal() underMouse() +*/ + +QPoint QWidget::mapToParent(const QPoint &pos) const +{ + return pos + data->crect.topLeft(); +} + +/*! + Translates the parent widget coordinate \a pos to widget + coordinates. + + Same as mapFromGlobal() if the widget has no parent. + + \sa mapToParent() mapFrom() mapFromGlobal() underMouse() +*/ + +QPoint QWidget::mapFromParent(const QPoint &pos) const +{ + return pos - data->crect.topLeft(); +} + + +/*! + Returns the window for this widget, i.e. the next ancestor widget + that has (or could have) a window-system frame. + + If the widget is a window, the widget itself is returned. + + Typical usage is changing the window title: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 3 + + \sa isWindow() +*/ + +QWidget *QWidget::window() const +{ + QWidget *w = (QWidget *)this; + QWidget *p = w->parentWidget(); + while (!w->isWindow() && p) { + w = p; + p = p->parentWidget(); + } + return w; +} + +/*! + \since 4.4 + + Returns the native parent for this widget, i.e. the next ancestor widget + that has a system identifier, or 0 if it does not have any native parent. + + \sa effectiveWinId() +*/ +QWidget *QWidget::nativeParentWidget() const +{ + QWidget *parent = parentWidget(); + while (parent && !parent->internalWinId()) + parent = parent->parentWidget(); + return parent; +} + +/*! \fn QWidget *QWidget::topLevelWidget() const + \obsolete + + Use window() instead. +*/ + +#ifdef QT3_SUPPORT +/*! + Returns the color role used for painting the widget's background. + + Use QPalette(backgroundRole(()) instead. +*/ +Qt::BackgroundMode QWidget::backgroundMode() const +{ + if (testAttribute(Qt::WA_NoSystemBackground)) + return Qt::NoBackground; + switch(backgroundRole()) { + case QPalette::WindowText: + return Qt::PaletteForeground; + case QPalette::Button: + return Qt::PaletteButton; + case QPalette::Light: + return Qt::PaletteLight; + case QPalette::Midlight: + return Qt::PaletteMidlight; + case QPalette::Dark: + return Qt::PaletteDark; + case QPalette::Mid: + return Qt::PaletteMid; + case QPalette::Text: + return Qt::PaletteText; + case QPalette::BrightText: + return Qt::PaletteBrightText; + case QPalette::Base: + return Qt::PaletteBase; + case QPalette::Window: + return Qt::PaletteBackground; + case QPalette::Shadow: + return Qt::PaletteShadow; + case QPalette::Highlight: + return Qt::PaletteHighlight; + case QPalette::HighlightedText: + return Qt::PaletteHighlightedText; + case QPalette::ButtonText: + return Qt::PaletteButtonText; + case QPalette::Link: + return Qt::PaletteLink; + case QPalette::LinkVisited: + return Qt::PaletteLinkVisited; + default: + break; + } + return Qt::NoBackground; +} + +/*! + \fn void QWidget::setBackgroundMode(Qt::BackgroundMode + widgetBackground, Qt::BackgroundMode paletteBackground) + + Sets the color role used for painting the widget's background to + background mode \a widgetBackground. The \a paletteBackground mode + parameter is ignored. +*/ +void QWidget::setBackgroundMode(Qt::BackgroundMode m, Qt::BackgroundMode) +{ + Q_D(QWidget); + if(m == Qt::NoBackground) { + setAttribute(Qt::WA_NoSystemBackground, true); + return; + } + setAttribute(Qt::WA_NoSystemBackground, false); + d->fg_role = QPalette::NoRole; + QPalette::ColorRole role = d->bg_role; + switch(m) { + case Qt::FixedColor: + case Qt::FixedPixmap: + break; + case Qt::PaletteForeground: + role = QPalette::WindowText; + break; + case Qt::PaletteButton: + role = QPalette::Button; + break; + case Qt::PaletteLight: + role = QPalette::Light; + break; + case Qt::PaletteMidlight: + role = QPalette::Midlight; + break; + case Qt::PaletteDark: + role = QPalette::Dark; + break; + case Qt::PaletteMid: + role = QPalette::Mid; + break; + case Qt::PaletteText: + role = QPalette::Text; + break; + case Qt::PaletteBrightText: + role = QPalette::BrightText; + break; + case Qt::PaletteBase: + role = QPalette::Base; + break; + case Qt::PaletteBackground: + role = QPalette::Window; + break; + case Qt::PaletteShadow: + role = QPalette::Shadow; + break; + case Qt::PaletteHighlight: + role = QPalette::Highlight; + break; + case Qt::PaletteHighlightedText: + role = QPalette::HighlightedText; + break; + case Qt::PaletteButtonText: + role = QPalette::ButtonText; + break; + case Qt::PaletteLink: + role = QPalette::Link; + break; + case Qt::PaletteLinkVisited: + role = QPalette::LinkVisited; + break; + case Qt::X11ParentRelative: + d->fg_role = role = QPalette::NoRole; + default: + break; + } + setBackgroundRole(role); +} + +/*! + The widget mapper is no longer part of the public API. +*/ +QT3_SUPPORT QWidgetMapper *QWidget::wmapper() { return QWidgetPrivate::mapper; } + +#endif + + +/*! + Returns the background role of the widget. + + The background role defines the brush from the widget's \l palette that + is used to render the background. + + If no explicit background role is set, the widget inherts its parent + widget's background role. + + \sa setBackgroundRole(), foregroundRole() + */ +QPalette::ColorRole QWidget::backgroundRole() const +{ + + const QWidget *w = this; + do { + QPalette::ColorRole role = w->d_func()->bg_role; + if (role != QPalette::NoRole) + return role; + if (w->isWindow() || w->windowType() == Qt::SubWindow) + break; + w = w->parentWidget(); + } while (w); + return QPalette::Window; +} + +/*! + Sets the background role of the widget to \a role. + + The background role defines the brush from the widget's \l palette that + is used to render the background. + + If \a role is QPalette::NoRole, then the widget inherits its + parent's background role. + + Note that styles are free to choose any color from the palette. + You can modify the palette or set a style sheet if you don't + achieve the result you want with setBackgroundRole(). + + \sa backgroundRole(), foregroundRole() + */ + +void QWidget::setBackgroundRole(QPalette::ColorRole role) +{ + Q_D(QWidget); + d->bg_role = role; + d->updateSystemBackground(); + d->propagatePaletteChange(); + d->updateIsOpaque(); +} + +/*! + Returns the foreground role. + + The foreground role defines the color from the widget's \l palette that + is used to draw the foreground. + + If no explicit foreground role is set, the function returns a role + that contrasts with the background role. + + \sa setForegroundRole(), backgroundRole() + */ +QPalette::ColorRole QWidget::foregroundRole() const +{ + Q_D(const QWidget); + QPalette::ColorRole rl = QPalette::ColorRole(d->fg_role); + if (rl != QPalette::NoRole) + return rl; + QPalette::ColorRole role = QPalette::WindowText; + switch (backgroundRole()) { + case QPalette::Button: + role = QPalette::ButtonText; + break; + case QPalette::Base: + role = QPalette::Text; + break; + case QPalette::Dark: + case QPalette::Shadow: + role = QPalette::Light; + break; + case QPalette::Highlight: + role = QPalette::HighlightedText; + break; + case QPalette::ToolTipBase: + role = QPalette::ToolTipText; + break; + default: + ; + } + return role; +} + +/*! + Sets the foreground role of the widget to \a role. + + The foreground role defines the color from the widget's \l palette that + is used to draw the foreground. + + If \a role is QPalette::NoRole, the widget uses a foreground role + that contrasts with the background role. + + Note that styles are free to choose any color from the palette. + You can modify the palette or set a style sheet if you don't + achieve the result you want with setForegroundRole(). + + \sa foregroundRole(), backgroundRole() + */ +void QWidget::setForegroundRole(QPalette::ColorRole role) +{ + Q_D(QWidget); + d->fg_role = role; + d->updateSystemBackground(); + d->propagatePaletteChange(); +} + +/*! + \property QWidget::palette + \brief the widget's palette + + This property describes the widget's palette. The palette is used by the + widget's style when rendering standard components, and is available as a + means to ensure that custom widgets can maintain consistency with the + native platform's look and feel. It's common that different platforms, or + different styles, have different palettes. + + When you assign a new palette to a widget, the color roles from this + palette are combined with the widget's default palette to form the + widget's final palette. The palette entry for the widget's background role + is used to fill the widget's background (see QWidget::autoFillBackground), + and the foreground role initializes QPainter's pen. + + The default depends on the system environment. QApplication maintains a + system/theme palette which serves as a default for all widgets. There may + also be special palette defaults for certain types of widgets (e.g., on + Windows XP and Vista, all classes that derive from QMenuBar have a special + default palette). You can also define default palettes for widgets + yourself by passing a custom palette and the name of a widget to + QApplication::setPalette(). Finally, the style always has the option of + polishing the palette as it's assigned (see QStyle::polish()). + + QWidget propagates explicit palette roles from parent to child. If you + assign a brush or color to a specific role on a palette and assign that + palette to a widget, that role will propagate to all the widget's + children, overriding any system defaults for that role. Note that palettes + by default don't propagate to windows (see isWindow()) unless the + Qt::WA_WindowPropagation attribute is enabled. + + QWidget's palette propagation is similar to its font propagation. + + The current style, which is used to render the content of all standard Qt + widgets, is free to choose colors and brushes from the widget palette, or + in some cases, to ignore the palette (partially, or completely). In + particular, certain styles like GTK style, Mac style, Windows XP, and + Vista style, depend on third party APIs to render the content of widgets, + and these styles typically do not follow the palette. Because of this, + assigning roles to a widget's palette is not guaranteed to change the + appearance of the widget. Instead, you may choose to apply a \l + styleSheet. You can refer to our Knowledge Base article + \l{http://qt.nokia.com/developer/knowledgebase/22}{here} for more + information. + + \warning Do not use this function in conjunction with \l{Qt Style Sheets}. + When using style sheets, the palette of a widget can be customized using + the "color", "background-color", "selection-color", + "selection-background-color" and "alternate-background-color". + + \sa QApplication::palette(), QWidget::font() +*/ +const QPalette &QWidget::palette() const +{ + if (!isEnabled()) { + data->pal.setCurrentColorGroup(QPalette::Disabled); + } else if ((!isVisible() || isActiveWindow()) +#if defined(Q_OS_WIN) && !defined(Q_WS_WINCE) + && !QApplicationPrivate::isBlockedByModal(const_cast(this)) +#endif + ) { + data->pal.setCurrentColorGroup(QPalette::Active); + } else { +#ifdef Q_WS_MAC + extern bool qt_mac_can_clickThrough(const QWidget *); //qwidget_mac.cpp + if (qt_mac_can_clickThrough(this)) + data->pal.setCurrentColorGroup(QPalette::Active); + else +#endif + data->pal.setCurrentColorGroup(QPalette::Inactive); + } + return data->pal; +} + +void QWidget::setPalette(const QPalette &palette) +{ + Q_D(QWidget); + setAttribute(Qt::WA_SetPalette, palette.resolve() != 0); + + // Determine which palette is inherited from this widget's ancestors and + // QApplication::palette, resolve this against \a palette (attributes from + // the inherited palette are copied over this widget's palette). Then + // propagate this palette to this widget's children. + QPalette naturalPalette = d->naturalWidgetPalette(d->inheritedPaletteResolveMask); + QPalette resolvedPalette = palette.resolve(naturalPalette); + d->setPalette_helper(resolvedPalette); +} + +/*! + \internal + + Returns the palette that the widget \a w inherits from its ancestors and + QApplication::palette. \a inheritedMask is the combination of the widget's + ancestors palette request masks (i.e., which attributes from the parent + widget's palette are implicitly imposed on this widget by the user). Note + that this font does not take into account the palette set on \a w itself. +*/ +QPalette QWidgetPrivate::naturalWidgetPalette(uint inheritedMask) const +{ + Q_Q(const QWidget); + QPalette naturalPalette = QApplication::palette(q); + if (!q->testAttribute(Qt::WA_StyleSheet) + && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) +#ifndef QT_NO_GRAPHICSVIEW + || (extra && extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + )) { + if (QWidget *p = q->parentWidget()) { + if (!p->testAttribute(Qt::WA_StyleSheet)) { + if (!naturalPalette.isCopyOf(QApplication::palette())) { + QPalette inheritedPalette = p->palette(); + inheritedPalette.resolve(inheritedMask); + naturalPalette = inheritedPalette.resolve(naturalPalette); + } else { + naturalPalette = p->palette(); + } + } + } +#ifndef QT_NO_GRAPHICSVIEW + else if (extra && extra->proxyWidget) { + QPalette inheritedPalette = extra->proxyWidget->palette(); + inheritedPalette.resolve(inheritedMask); + naturalPalette = inheritedPalette.resolve(naturalPalette); + } +#endif //QT_NO_GRAPHICSVIEW + } + naturalPalette.resolve(0); + return naturalPalette; +} +/*! + \internal + + Determine which palette is inherited from this widget's ancestors and + QApplication::palette, resolve this against this widget's palette + (attributes from the inherited palette are copied over this widget's + palette). Then propagate this palette to this widget's children. +*/ +void QWidgetPrivate::resolvePalette() +{ + QPalette naturalPalette = naturalWidgetPalette(inheritedPaletteResolveMask); + QPalette resolvedPalette = data.pal.resolve(naturalPalette); + setPalette_helper(resolvedPalette); +} + +void QWidgetPrivate::setPalette_helper(const QPalette &palette) +{ + Q_Q(QWidget); + if (data.pal == palette && data.pal.resolve() == palette.resolve()) + return; + data.pal = palette; + updateSystemBackground(); + propagatePaletteChange(); + updateIsOpaque(); + q->update(); + updateIsOpaque(); +} + +/*! + \property QWidget::font + \brief the font currently set for the widget + + This property describes the widget's requested font. The font is used by + the widget's style when rendering standard components, and is available as + a means to ensure that custom widgets can maintain consistency with the + native platform's look and feel. It's common that different platforms, or + different styles, define different fonts for an application. + + When you assign a new font to a widget, the properties from this font are + combined with the widget's default font to form the widget's final + font. You can call fontInfo() to get a copy of the widget's final + font. The final font is also used to initialize QPainter's font. + + The default depends on the system environment. QApplication maintains a + system/theme font which serves as a default for all widgets. There may + also be special font defaults for certain types of widgets. You can also + define default fonts for widgets yourself by passing a custom font and the + name of a widget to QApplication::setFont(). Finally, the font is matched + against Qt's font database to find the best match. + + QWidget propagates explicit font properties from parent to child. If you + change a specific property on a font and assign that font to a widget, + that property will propagate to all the widget's children, overriding any + system defaults for that property. Note that fonts by default don't + propagate to windows (see isWindow()) unless the Qt::WA_WindowPropagation + attribute is enabled. + + QWidget's font propagation is similar to its palette propagation. + + The current style, which is used to render the content of all standard Qt + widgets, is free to choose to use the widget font, or in some cases, to + ignore it (partially, or completely). In particular, certain styles like + GTK style, Mac style, Windows XP, and Vista style, apply special + modifications to the widget font to match the platform's native look and + feel. Because of this, assigning properties to a widget's font is not + guaranteed to change the appearance of the widget. Instead, you may choose + to apply a \l styleSheet. + + \note If \l{Qt Style Sheets} are used on the same widget as setFont(), + style sheets will take precedence if the settings conflict. + + \sa fontInfo(), fontMetrics() +*/ + +void QWidget::setFont(const QFont &font) +{ + Q_D(QWidget); + +#ifndef QT_NO_STYLE_STYLESHEET + const QStyleSheetStyle* style; + if (d->extra && (style = qobject_cast(d->extra->style))) { + style->saveWidgetFont(this, font); + } +#endif + + setAttribute(Qt::WA_SetFont, font.resolve() != 0); + + // Determine which font is inherited from this widget's ancestors and + // QApplication::font, resolve this against \a font (attributes from the + // inherited font are copied over). Then propagate this font to this + // widget's children. + QFont naturalFont = d->naturalWidgetFont(d->inheritedFontResolveMask); + QFont resolvedFont = font.resolve(naturalFont); + d->setFont_helper(resolvedFont); +} + +/* + \internal + + Returns the font that the widget \a w inherits from its ancestors and + QApplication::font. \a inheritedMask is the combination of the widget's + ancestors font request masks (i.e., which attributes from the parent + widget's font are implicitly imposed on this widget by the user). Note + that this font does not take into account the font set on \a w itself. + + ### Stylesheet has a different font propagation mechanism. When a stylesheet + is applied, fonts are not propagated anymore +*/ +QFont QWidgetPrivate::naturalWidgetFont(uint inheritedMask) const +{ + Q_Q(const QWidget); + QFont naturalFont = QApplication::font(q); + if (!q->testAttribute(Qt::WA_StyleSheet) + && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) +#ifndef QT_NO_GRAPHICSVIEW + || (extra && extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + )) { + if (QWidget *p = q->parentWidget()) { + if (!p->testAttribute(Qt::WA_StyleSheet)) { + if (!naturalFont.isCopyOf(QApplication::font())) { + QFont inheritedFont = p->font(); + inheritedFont.resolve(inheritedMask); + naturalFont = inheritedFont.resolve(naturalFont); + } else { + naturalFont = p->font(); + } + } + } +#ifndef QT_NO_GRAPHICSVIEW + else if (extra && extra->proxyWidget) { + QFont inheritedFont = extra->proxyWidget->font(); + inheritedFont.resolve(inheritedMask); + naturalFont = inheritedFont.resolve(naturalFont); + } +#endif //QT_NO_GRAPHICSVIEW + } + naturalFont.resolve(0); + return naturalFont; +} + +/*! + \internal + + Determine which font is implicitly imposed on this widget by its ancestors + and QApplication::font, resolve this against its own font (attributes from + the implicit font are copied over). Then propagate this font to this + widget's children. +*/ +void QWidgetPrivate::resolveFont() +{ + QFont naturalFont = naturalWidgetFont(inheritedFontResolveMask); + QFont resolvedFont = data.fnt.resolve(naturalFont); + setFont_helper(resolvedFont); +} + +/*! + \internal + + Assign \a font to this widget, and propagate it to all children, except + style sheet widgets (handled differently) and windows that don't enable + window propagation. \a implicitMask is the union of all ancestor widgets' + font request masks, and determines which attributes from this widget's + font should propagate. +*/ +void QWidgetPrivate::updateFont(const QFont &font) +{ + Q_Q(QWidget); +#ifndef QT_NO_STYLE_STYLESHEET + const QStyleSheetStyle* cssStyle; + cssStyle = extra ? qobject_cast(extra->style) : 0; +#endif + +#ifdef QT3_SUPPORT + QFont old = data.fnt; +#endif + data.fnt = QFont(font, q); +#if defined(Q_WS_X11) + // make sure the font set on this widget is associated with the correct screen + data.fnt.x11SetScreen(xinfo.screen()); +#endif + // Combine new mask with natural mask and propagate to children. +#ifndef QT_NO_GRAPHICSVIEW + if (!q->parentWidget() && extra && extra->proxyWidget) { + QGraphicsProxyWidget *p = extra->proxyWidget; + inheritedFontResolveMask = p->d_func()->inheritedFontResolveMask | p->font().resolve(); + } else +#endif //QT_NO_GRAPHICSVIEW + if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { + inheritedFontResolveMask = 0; + } + uint newMask = data.fnt.resolve() | inheritedFontResolveMask; + + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w) { + if (0) { +#ifndef QT_NO_STYLE_STYLESHEET + } else if (w->testAttribute(Qt::WA_StyleSheet)) { + // Style sheets follow a different font propagation scheme. + if (cssStyle) + cssStyle->updateStyleSheetFont(w); +#endif + } else if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))) { + // Propagate font changes. + QWidgetPrivate *wd = w->d_func(); + wd->inheritedFontResolveMask = newMask; + wd->resolveFont(); + } + } + } + +#ifndef QT_NO_STYLE_STYLESHEET + if (cssStyle) { + cssStyle->updateStyleSheetFont(q); + } +#endif + + QEvent e(QEvent::FontChange); + QApplication::sendEvent(q, &e); +#ifdef QT3_SUPPORT + q->fontChange(old); +#endif +} + +void QWidgetPrivate::setLayoutDirection_helper(Qt::LayoutDirection direction) +{ + Q_Q(QWidget); + + if ( (direction == Qt::RightToLeft) == q->testAttribute(Qt::WA_RightToLeft)) + return; + q->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft)); + if (!children.isEmpty()) { + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w && !w->isWindow() && !w->testAttribute(Qt::WA_SetLayoutDirection)) + w->d_func()->setLayoutDirection_helper(direction); + } + } + QEvent e(QEvent::LayoutDirectionChange); + QApplication::sendEvent(q, &e); +} + +void QWidgetPrivate::resolveLayoutDirection() +{ + Q_Q(const QWidget); + if (!q->testAttribute(Qt::WA_SetLayoutDirection)) + setLayoutDirection_helper(q->isWindow() ? QApplication::layoutDirection() : q->parentWidget()->layoutDirection()); +} + +/*! + \property QWidget::layoutDirection + + \brief the layout direction for this widget + + By default, this property is set to Qt::LeftToRight. + + When the layout direction is set on a widget, it will propagate to + the widget's children, but not to a child that is a window and not + to a child for which setLayoutDirection() has been explicitly + called. Also, child widgets added \e after setLayoutDirection() + has been called for the parent do not inherit the parent's layout + direction. + + This method no longer affects text layout direction since Qt 4.7. + + \sa QApplication::layoutDirection +*/ +void QWidget::setLayoutDirection(Qt::LayoutDirection direction) +{ + Q_D(QWidget); + + if (direction == Qt::LayoutDirectionAuto) { + unsetLayoutDirection(); + return; + } + + setAttribute(Qt::WA_SetLayoutDirection); + d->setLayoutDirection_helper(direction); +} + +Qt::LayoutDirection QWidget::layoutDirection() const +{ + return testAttribute(Qt::WA_RightToLeft) ? Qt::RightToLeft : Qt::LeftToRight; +} + +void QWidget::unsetLayoutDirection() +{ + Q_D(QWidget); + setAttribute(Qt::WA_SetLayoutDirection, false); + d->resolveLayoutDirection(); +} + +/*! + \fn QFontMetrics QWidget::fontMetrics() const + + Returns the font metrics for the widget's current font. + Equivalent to QFontMetrics(widget->font()). + + \sa font(), fontInfo(), setFont() +*/ + +/*! + \fn QFontInfo QWidget::fontInfo() const + + Returns the font info for the widget's current font. + Equivalent to QFontInto(widget->font()). + + \sa font(), fontMetrics(), setFont() +*/ + + +/*! + \property QWidget::cursor + \brief the cursor shape for this widget + + The mouse cursor will assume this shape when it's over this + widget. See the \link Qt::CursorShape list of predefined cursor + objects\endlink for a range of useful shapes. + + An editor widget might use an I-beam cursor: + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 6 + + If no cursor has been set, or after a call to unsetCursor(), the + parent's cursor is used. + + By default, this property contains a cursor with the Qt::ArrowCursor + shape. + + Some underlying window implementations will reset the cursor if it + leaves a widget even if the mouse is grabbed. If you want to have + a cursor set for all widgets, even when outside the window, consider + QApplication::setOverrideCursor(). + + \sa QApplication::setOverrideCursor() +*/ + +#ifndef QT_NO_CURSOR +QCursor QWidget::cursor() const +{ + Q_D(const QWidget); + if (testAttribute(Qt::WA_SetCursor)) + return (d->extra && d->extra->curs) + ? *d->extra->curs + : QCursor(Qt::ArrowCursor); + if (isWindow() || !parentWidget()) + return QCursor(Qt::ArrowCursor); + return parentWidget()->cursor(); +} + +void QWidget::setCursor(const QCursor &cursor) +{ + Q_D(QWidget); +// On Mac we must set the cursor even if it is the ArrowCursor. +#if !defined(Q_WS_MAC) && !defined(Q_WS_QWS) + if (cursor.shape() != Qt::ArrowCursor + || (d->extra && d->extra->curs)) +#endif + { + d->createExtra(); + QCursor *newCursor = new QCursor(cursor); + delete d->extra->curs; + d->extra->curs = newCursor; + } + setAttribute(Qt::WA_SetCursor); + d->setCursor_sys(cursor); + + QEvent event(QEvent::CursorChange); + QApplication::sendEvent(this, &event); +} + +void QWidget::unsetCursor() +{ + Q_D(QWidget); + if (d->extra) { + delete d->extra->curs; + d->extra->curs = 0; + } + if (!isWindow()) + setAttribute(Qt::WA_SetCursor, false); + d->unsetCursor_sys(); + + QEvent event(QEvent::CursorChange); + QApplication::sendEvent(this, &event); +} + +#endif + +/*! + \enum QWidget::RenderFlag + + This enum describes how to render the widget when calling QWidget::render(). + + \value DrawWindowBackground If you enable this option, the widget's background + is rendered into the target even if autoFillBackground is not set. By default, + this option is enabled. + + \value DrawChildren If you enable this option, the widget's children + are rendered recursively into the target. By default, this option is enabled. + + \value IgnoreMask If you enable this option, the widget's QWidget::mask() + is ignored when rendering into the target. By default, this option is disabled. + + \since 4.3 +*/ + +/*! + \since 4.3 + + Renders the \a sourceRegion of this widget into the \a target + using \a renderFlags to determine how to render. Rendering + starts at \a targetOffset in the \a target. For example: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 7 + + If \a sourceRegion is a null region, this function will use QWidget::rect() as + the region, i.e. the entire widget. + + Ensure that you call QPainter::end() for the \a target device's + active painter (if any) before rendering. For example: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 8 + + \note To obtain the contents of an OpenGL widget, use QGLWidget::grabFrameBuffer() + or QGLWidget::renderPixmap() instead. +*/ +void QWidget::render(QPaintDevice *target, const QPoint &targetOffset, + const QRegion &sourceRegion, RenderFlags renderFlags) +{ + d_func()->render(target, targetOffset, sourceRegion, renderFlags, false); +} + +/*! + \overload + + Renders the widget into the \a painter's QPainter::device(). + + Transformations and settings applied to the \a painter will be used + when rendering. + + \note The \a painter must be active. On Mac OS X the widget will be + rendered into a QPixmap and then drawn by the \a painter. + + \sa QPainter::device() +*/ +void QWidget::render(QPainter *painter, const QPoint &targetOffset, + const QRegion &sourceRegion, RenderFlags renderFlags) +{ + if (!painter) { + qWarning("QWidget::render: Null pointer to painter"); + return; + } + + if (!painter->isActive()) { + qWarning("QWidget::render: Cannot render with an inactive painter"); + return; + } + + const qreal opacity = painter->opacity(); + if (qFuzzyIsNull(opacity)) + return; // Fully transparent. + + Q_D(QWidget); + const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; + const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) + : sourceRegion; + if (toBePainted.isEmpty()) + return; + + if (!d->extra) + d->createExtra(); + d->extra->inRenderWithPainter = true; + +#ifdef Q_WS_MAC + d->render_helper(painter, targetOffset, toBePainted, renderFlags); +#else + QPaintEngine *engine = painter->paintEngine(); + Q_ASSERT(engine); + QPaintEnginePrivate *enginePriv = engine->d_func(); + Q_ASSERT(enginePriv); + QPaintDevice *target = engine->paintDevice(); + Q_ASSERT(target); + + // Render via a pixmap when dealing with non-opaque painters or printers. + if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { + d->render_helper(painter, targetOffset, toBePainted, renderFlags); + d->extra->inRenderWithPainter = false; + return; + } + + // Set new shared painter. + QPainter *oldPainter = d->sharedPainter(); + d->setSharedPainter(painter); + + // Save current system clip, viewport and transform, + const QTransform oldTransform = enginePriv->systemTransform; + const QRegion oldSystemClip = enginePriv->systemClip; + const QRegion oldSystemViewport = enginePriv->systemViewport; + + // This ensures that all painting triggered by render() is clipped to the current engine clip. + if (painter->hasClipping()) { + const QRegion painterClip = painter->deviceTransform().map(painter->clipRegion()); + enginePriv->setSystemViewport(oldSystemClip.isEmpty() ? painterClip : oldSystemClip & painterClip); + } else { + enginePriv->setSystemViewport(oldSystemClip); + } + + render(target, targetOffset, toBePainted, renderFlags); + + // Restore system clip, viewport and transform. + enginePriv->systemClip = oldSystemClip; + enginePriv->setSystemViewport(oldSystemViewport); + enginePriv->setSystemTransform(oldTransform); + + // Restore shared painter. + d->setSharedPainter(oldPainter); +#endif + + d->extra->inRenderWithPainter = false; +} + +/*! + \brief The graphicsEffect function returns a pointer to the + widget's graphics effect. + + If the widget has no graphics effect, 0 is returned. + + \since 4.6 + + \sa setGraphicsEffect() +*/ +#ifndef QT_NO_GRAPHICSEFFECT +QGraphicsEffect *QWidget::graphicsEffect() const +{ + Q_D(const QWidget); + return d->graphicsEffect; +} +#endif //QT_NO_GRAPHICSEFFECT + +/*! + + \brief The setGraphicsEffect function is for setting the widget's graphics effect. + + Sets \a effect as the widget's effect. If there already is an effect installed + on this widget, QWidget will delete the existing effect before installing + the new \a effect. + + If \a effect is the installed on a different widget, setGraphicsEffect() will remove + the effect from the widget and install it on this widget. + + QWidget takes ownership of \a effect. + + \note This function will apply the effect on itself and all its children. + + \since 4.6 + + \sa graphicsEffect() +*/ +#ifndef QT_NO_GRAPHICSEFFECT +void QWidget::setGraphicsEffect(QGraphicsEffect *effect) +{ + Q_D(QWidget); + if (d->graphicsEffect == effect) + return; + + if (d->graphicsEffect) { + d->invalidateBuffer(rect()); + delete d->graphicsEffect; + d->graphicsEffect = 0; + } + + if (effect) { + // Set new effect. + QGraphicsEffectSourcePrivate *sourced = new QWidgetEffectSourcePrivate(this); + QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); + d->graphicsEffect = effect; + effect->d_func()->setGraphicsEffectSource(source); + update(); + } + + d->updateIsOpaque(); +} +#endif //QT_NO_GRAPHICSEFFECT + +bool QWidgetPrivate::isAboutToShow() const +{ + if (data.in_show) + return true; + + Q_Q(const QWidget); + if (q->isHidden()) + return false; + + // The widget will be shown if any of its ancestors are about to show. + QWidget *parent = q->parentWidget(); + return parent ? parent->d_func()->isAboutToShow() : false; +} + +QRegion QWidgetPrivate::prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags) +{ + Q_Q(QWidget); + const bool isVisible = q->isVisible(); + + // Make sure the widget is laid out correctly. + if (!isVisible && !isAboutToShow()) { + QWidget *topLevel = q->window(); + (void)topLevel->d_func()->topData(); // Make sure we at least have top-data. + topLevel->ensurePolished(); + + // Invalidate the layout of hidden ancestors (incl. myself) and pretend + // they're not explicitly hidden. + QWidget *widget = q; + QWidgetList hiddenWidgets; + while (widget) { + if (widget->isHidden()) { + widget->setAttribute(Qt::WA_WState_Hidden, false); + hiddenWidgets.append(widget); + if (!widget->isWindow() && widget->parentWidget()->d_func()->layout) + widget->d_func()->updateGeometry_helper(true); + } + widget = widget->parentWidget(); + } + + // Activate top-level layout. + if (topLevel->d_func()->layout) + topLevel->d_func()->layout->activate(); + + // Adjust size if necessary. + QTLWExtra *topLevelExtra = topLevel->d_func()->maybeTopData(); + if (topLevelExtra && !topLevelExtra->sizeAdjusted + && !topLevel->testAttribute(Qt::WA_Resized)) { + topLevel->adjustSize(); + topLevel->setAttribute(Qt::WA_Resized, false); + } + + // Activate child layouts. + topLevel->d_func()->activateChildLayoutsRecursively(); + + // We're not cheating with WA_WState_Hidden anymore. + for (int i = 0; i < hiddenWidgets.size(); ++i) { + QWidget *widget = hiddenWidgets.at(i); + widget->setAttribute(Qt::WA_WState_Hidden); + if (!widget->isWindow() && widget->parentWidget()->d_func()->layout) + widget->parentWidget()->d_func()->layout->invalidate(); + } + } else if (isVisible) { + q->window()->d_func()->sendPendingMoveAndResizeEvents(true, true); + } + + // Calculate the region to be painted. + QRegion toBePainted = !region.isEmpty() ? region : QRegion(q->rect()); + if (!(renderFlags & QWidget::IgnoreMask) && extra && extra->hasMask) + toBePainted &= extra->mask; + return toBePainted; +} + +void QWidgetPrivate::render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &toBePainted, + QWidget::RenderFlags renderFlags) +{ + Q_ASSERT(painter); + Q_ASSERT(!toBePainted.isEmpty()); + + Q_Q(QWidget); +#ifndef Q_WS_MAC + const QTransform originalTransform = painter->worldTransform(); + const bool useDeviceCoordinates = originalTransform.isScaling(); + if (!useDeviceCoordinates) { +#endif + // Render via a pixmap. + const QRect rect = toBePainted.boundingRect(); + const QSize size = rect.size(); + if (size.isNull()) + return; + + QPixmap pixmap(size); + if (!(renderFlags & QWidget::DrawWindowBackground) || !isOpaque) + pixmap.fill(Qt::transparent); + q->render(&pixmap, QPoint(), toBePainted, renderFlags); + + const bool restore = !(painter->renderHints() & QPainter::SmoothPixmapTransform); + painter->setRenderHints(QPainter::SmoothPixmapTransform, true); + + painter->drawPixmap(targetOffset, pixmap); + + if (restore) + painter->setRenderHints(QPainter::SmoothPixmapTransform, false); + +#ifndef Q_WS_MAC + } else { + // Render via a pixmap in device coordinates (to avoid pixmap scaling). + QTransform transform = originalTransform; + transform.translate(targetOffset.x(), targetOffset.y()); + + QPaintDevice *device = painter->device(); + Q_ASSERT(device); + + // Calculate device rect. + const QRectF rect(toBePainted.boundingRect()); + QRect deviceRect = transform.mapRect(QRectF(0, 0, rect.width(), rect.height())).toAlignedRect(); + deviceRect &= QRect(0, 0, device->width(), device->height()); + + QPixmap pixmap(deviceRect.size()); + pixmap.fill(Qt::transparent); + + // Create a pixmap device coordinate painter. + QPainter pixmapPainter(&pixmap); + pixmapPainter.setRenderHints(painter->renderHints()); + transform *= QTransform::fromTranslate(-deviceRect.x(), -deviceRect.y()); + pixmapPainter.setTransform(transform); + + q->render(&pixmapPainter, QPoint(), toBePainted, renderFlags); + pixmapPainter.end(); + + // And then draw the pixmap. + painter->setTransform(QTransform()); + painter->drawPixmap(deviceRect.topLeft(), pixmap); + painter->setTransform(originalTransform); + } +#endif +} + +void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, + QPainter *sharedPainter, QWidgetBackingStore *backingStore) +{ + if (rgn.isEmpty()) + return; + +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + if (qt_mac_clearDirtyOnWidgetInsideDrawWidget) + dirtyOnWidget = QRegion(); + + // We disable the rendering of QToolBar in the backingStore if + // it's supposed to be in the unified toolbar on Mac OS X. + if (backingStore && isInUnifiedToolbar) + return; +#endif // Q_WS_MAC && QT_MAC_USE_COCOA + + + Q_Q(QWidget); +#ifndef QT_NO_GRAPHICSEFFECT + if (graphicsEffect && graphicsEffect->isEnabled()) { + QGraphicsEffectSource *source = graphicsEffect->d_func()->source; + QWidgetEffectSourcePrivate *sourced = static_cast + (source->d_func()); + if (!sourced->context) { + QWidgetPaintContext context(pdev, rgn, offset, flags, sharedPainter, backingStore); + sourced->context = &context; + if (!sharedPainter) { + QPaintEngine *paintEngine = pdev->paintEngine(); + paintEngine->d_func()->systemClip = rgn.translated(offset); + QPainter p(pdev); + p.translate(offset); + context.painter = &p; + graphicsEffect->draw(&p); + paintEngine->d_func()->systemClip = QRegion(); + } else { + context.painter = sharedPainter; + if (sharedPainter->worldTransform() != sourced->lastEffectTransform) { + sourced->invalidateCache(); + sourced->lastEffectTransform = sharedPainter->worldTransform(); + } + sharedPainter->save(); + sharedPainter->translate(offset); + graphicsEffect->draw(sharedPainter); + sharedPainter->restore(); + } + sourced->context = 0; + return; + } + } +#endif //QT_NO_GRAFFICSEFFECT + + const bool asRoot = flags & DrawAsRoot; + const bool alsoOnScreen = flags & DrawPaintOnScreen; + const bool recursive = flags & DrawRecursive; + const bool alsoInvisible = flags & DrawInvisible; + + Q_ASSERT(sharedPainter ? sharedPainter->isActive() : true); + + QRegion toBePainted(rgn); + if (asRoot && !alsoInvisible) + toBePainted &= clipRect(); //(rgn & visibleRegion()); + if (!(flags & DontSubtractOpaqueChildren)) + subtractOpaqueChildren(toBePainted, q->rect()); + + if (!toBePainted.isEmpty()) { + bool onScreen = paintOnScreen(); + if (!onScreen || alsoOnScreen) { + //update the "in paint event" flag + if (q->testAttribute(Qt::WA_WState_InPaintEvent)) + qWarning("QWidget::repaint: Recursive repaint detected"); + q->setAttribute(Qt::WA_WState_InPaintEvent); + + //clip away the new area +#ifndef QT_NO_PAINT_DEBUG + bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); +#endif + QPaintEngine *paintEngine = pdev->paintEngine(); + if (paintEngine) { + setRedirected(pdev, -offset); + +#ifdef Q_WS_MAC + // (Alien support) Special case for Mac when redirecting: If the paint device + // is of the Widget type we need to set WA_WState_InPaintEvent since painting + // outside the paint event is not supported on QWidgets. The attributeis + // restored further down. + if (pdev->devType() == QInternal::Widget) + static_cast(pdev)->setAttribute(Qt::WA_WState_InPaintEvent); + +#endif + if (sharedPainter) + paintEngine->d_func()->systemClip = toBePainted; + else + paintEngine->d_func()->systemRect = q->data->crect; + + //paint the background + if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground)) + && !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { + QPainter p(q); + paintBackground(&p, toBePainted, (asRoot || onScreen) ? flags | DrawAsRoot : 0); + } + + if (!sharedPainter) + paintEngine->d_func()->systemClip = toBePainted.translated(offset); + + if (!onScreen && !asRoot && !isOpaque && q->testAttribute(Qt::WA_TintedBackground)) { + QPainter p(q); + QColor tint = q->palette().window().color(); + tint.setAlphaF(qreal(.6)); + p.fillRect(toBePainted.boundingRect(), tint); + } + } + +#if 0 + qDebug() << "painting" << q << "opaque ==" << isOpaque(); + qDebug() << "clipping to" << toBePainted << "location == " << offset + << "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size()); +#endif + + //actually send the paint event + QPaintEvent e(toBePainted); + QCoreApplication::sendSpontaneousEvent(q, &e); +#if !defined(Q_WS_QWS) && !defined(Q_WS_QPA) + if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow())) + backingStore->markDirtyOnScreen(toBePainted, q, offset); +#endif + + //restore + if (paintEngine) { +#ifdef Q_WS_MAC + if (pdev->devType() == QInternal::Widget) + static_cast(pdev)->setAttribute(Qt::WA_WState_InPaintEvent, false); +#endif + restoreRedirected(); + if (!sharedPainter) + paintEngine->d_func()->systemRect = QRect(); + else + paintEngine->d_func()->currentClipDevice = 0; + paintEngine->d_func()->systemClip = QRegion(); + } + q->setAttribute(Qt::WA_WState_InPaintEvent, false); + if (q->paintingActive() && !q->testAttribute(Qt::WA_PaintOutsidePaintEvent)) + qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); + + if (paintEngine && paintEngine->autoDestruct()) { + delete paintEngine; + } + +#ifndef QT_NO_PAINT_DEBUG + if (flushed) + QWidgetBackingStore::unflushPaint(q, toBePainted); +#endif + } else if (q->isWindow()) { + QPaintEngine *engine = pdev->paintEngine(); + if (engine) { + QPainter p(pdev); + p.setClipRegion(toBePainted); + const QBrush bg = q->palette().brush(QPalette::Window); + if (bg.style() == Qt::TexturePattern) + p.drawTiledPixmap(q->rect(), bg.texture()); + else + p.fillRect(q->rect(), bg); + + if (engine->autoDestruct()) + delete engine; + } + } + } + + if (recursive && !children.isEmpty()) { + paintSiblingsRecursive(pdev, children, children.size() - 1, rgn, offset, flags & ~DrawAsRoot +#ifdef Q_BACKINGSTORE_SUBSURFACES + , q->windowSurface() +#endif + , sharedPainter, backingStore); + } +} + +void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, + const QRegion &sourceRegion, QWidget::RenderFlags renderFlags, + bool readyToRender) +{ + if (!target) { + qWarning("QWidget::render: null pointer to paint device"); + return; + } + + const bool inRenderWithPainter = extra && extra->inRenderWithPainter; + QRegion paintRegion = !inRenderWithPainter && !readyToRender + ? prepareToRender(sourceRegion, renderFlags) + : sourceRegion; + if (paintRegion.isEmpty()) + return; + +#ifndef Q_WS_MAC + QPainter *oldSharedPainter = inRenderWithPainter ? sharedPainter() : 0; + + // Use the target's shared painter if set (typically set when doing + // "other->render(widget);" in the widget's paintEvent. + if (target->devType() == QInternal::Widget) { + QWidgetPrivate *targetPrivate = static_cast(target)->d_func(); + if (targetPrivate->extra && targetPrivate->extra->inRenderWithPainter) { + QPainter *targetPainter = targetPrivate->sharedPainter(); + if (targetPainter && targetPainter->isActive()) + setSharedPainter(targetPainter); + } + } +#endif + + // Use the target's redirected device if set and adjust offset and paint + // region accordingly. This is typically the case when people call render + // from the paintEvent. + QPoint offset = targetOffset; + offset -= paintRegion.boundingRect().topLeft(); + QPoint redirectionOffset; + QPaintDevice *redirected = 0; + + if (target->devType() == QInternal::Widget) + redirected = static_cast(target)->d_func()->redirected(&redirectionOffset); + if (!redirected) + redirected = QPainter::redirected(target, &redirectionOffset); + + if (redirected) { + target = redirected; + offset -= redirectionOffset; + } + + if (!inRenderWithPainter) { // Clip handled by shared painter (in qpainter.cpp). + if (QPaintEngine *targetEngine = target->paintEngine()) { + const QRegion targetSystemClip = targetEngine->systemClip(); + if (!targetSystemClip.isEmpty()) + paintRegion &= targetSystemClip.translated(-offset); + } + } + + // Set backingstore flags. + int flags = DrawPaintOnScreen | DrawInvisible; + if (renderFlags & QWidget::DrawWindowBackground) + flags |= DrawAsRoot; + + if (renderFlags & QWidget::DrawChildren) + flags |= DrawRecursive; + else + flags |= DontSubtractOpaqueChildren; + +#ifdef Q_WS_QWS + flags |= DontSetCompositionMode; +#endif + + if (target->devType() == QInternal::Printer) { + QPainter p(target); + render_helper(&p, targetOffset, paintRegion, renderFlags); + return; + } + +#ifndef Q_WS_MAC + // Render via backingstore. + drawWidget(target, paintRegion, offset, flags, sharedPainter()); + + // Restore shared painter. + if (oldSharedPainter) + setSharedPainter(oldSharedPainter); +#else + // Render via backingstore (no shared painter). + drawWidget(target, paintRegion, offset, flags, 0); +#endif +} + +void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn, + const QPoint &offset, int flags +#ifdef Q_BACKINGSTORE_SUBSURFACES + , const QWindowSurface *currentSurface +#endif + , QPainter *sharedPainter, QWidgetBackingStore *backingStore) +{ + QWidget *w = 0; + QRect boundingRect; + bool dirtyBoundingRect = true; + const bool exludeOpaqueChildren = (flags & DontDrawOpaqueChildren); + const bool excludeNativeChildren = (flags & DontDrawNativeChildren); + + do { + QWidget *x = qobject_cast(siblings.at(index)); + if (x && !(exludeOpaqueChildren && x->d_func()->isOpaque) && !x->isHidden() && !x->isWindow() + && !(excludeNativeChildren && x->internalWinId())) { + if (dirtyBoundingRect) { + boundingRect = rgn.boundingRect(); + dirtyBoundingRect = false; + } + + if (qRectIntersects(boundingRect, x->d_func()->effectiveRectFor(x->data->crect))) { +#ifdef Q_BACKINGSTORE_SUBSURFACES + if (x->windowSurface() == currentSurface) +#endif + { + w = x; + break; + } + } + } + --index; + } while (index >= 0); + + if (!w) + return; + + QWidgetPrivate *wd = w->d_func(); + const QPoint widgetPos(w->data->crect.topLeft()); + const bool hasMask = wd->extra && wd->extra->hasMask && !wd->graphicsEffect; + if (index > 0) { + QRegion wr(rgn); + if (wd->isOpaque) + wr -= hasMask ? wd->extra->mask.translated(widgetPos) : w->data->crect; + paintSiblingsRecursive(pdev, siblings, --index, wr, offset, flags +#ifdef Q_BACKINGSTORE_SUBSURFACES + , currentSurface +#endif + , sharedPainter, backingStore); + } + + if (w->updatesEnabled() +#ifndef QT_NO_GRAPHICSVIEW + && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + ) { + QRegion wRegion(rgn); + wRegion &= wd->effectiveRectFor(w->data->crect); + wRegion.translate(-widgetPos); + if (hasMask) + wRegion &= wd->extra->mask; + wd->drawWidget(pdev, wRegion, offset + widgetPos, flags, sharedPainter, backingStore); + } +} + +#ifndef QT_NO_GRAPHICSEFFECT +QRectF QWidgetEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const +{ + if (system != Qt::DeviceCoordinates) + return m_widget->rect(); + + if (!context) { + // Device coordinates without context not yet supported. + qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context"); + return QRectF(); + } + + return context->painter->worldTransform().mapRect(m_widget->rect()); +} + +void QWidgetEffectSourcePrivate::draw(QPainter *painter) +{ + if (!context || context->painter != painter) { + m_widget->render(painter); + return; + } + + // The region saved in the context is neither clipped to the rect + // nor the mask, so we have to clip it here before calling drawWidget. + QRegion toBePainted = context->rgn; + toBePainted &= m_widget->rect(); + QWidgetPrivate *wd = qt_widget_private(m_widget); + if (wd->extra && wd->extra->hasMask) + toBePainted &= wd->extra->mask; + + wd->drawWidget(context->pdev, toBePainted, context->offset, context->flags, + context->sharedPainter, context->backingStore); +} + +QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, + QGraphicsEffect::PixmapPadMode mode) const +{ + const bool deviceCoordinates = (system == Qt::DeviceCoordinates); + if (!context && deviceCoordinates) { + // Device coordinates without context not yet supported. + qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); + return QPixmap(); + } + + QPoint pixmapOffset; + QRectF sourceRect = m_widget->rect(); + + if (deviceCoordinates) { + const QTransform &painterTransform = context->painter->worldTransform(); + sourceRect = painterTransform.mapRect(sourceRect); + pixmapOffset = painterTransform.map(pixmapOffset); + } + + QRect effectRect; + + if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) + effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); + else if (mode == QGraphicsEffect::PadToTransparentBorder) + effectRect = sourceRect.adjusted(-1, -1, 1, 1).toAlignedRect(); + else + effectRect = sourceRect.toAlignedRect(); + + if (offset) + *offset = effectRect.topLeft(); + + pixmapOffset -= effectRect.topLeft(); + + QPixmap pixmap(effectRect.size()); + pixmap.fill(Qt::transparent); + m_widget->render(&pixmap, pixmapOffset, QRegion(), QWidget::DrawChildren); + return pixmap; +} +#endif //QT_NO_GRAPHICSEFFECT + +#ifndef QT_NO_GRAPHICSVIEW +/*! + \internal + + Finds the nearest widget embedded in a graphics proxy widget along the chain formed by this + widget and its ancestors. The search starts at \a origin (inclusive). + If successful, the function returns the proxy that embeds the widget, or 0 if no embedded + widget was found. +*/ +QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin) +{ + if (origin) { + QWExtra *extra = origin->d_func()->extra; + if (extra && extra->proxyWidget) + return extra->proxyWidget; + return nearestGraphicsProxyWidget(origin->parentWidget()); + } + return 0; +} +#endif + +/*! + \property QWidget::locale + \brief the widget's locale + \since 4.3 + + As long as no special locale has been set, this is either + the parent's locale or (if this widget is a top level widget), + the default locale. + + If the widget displays dates or numbers, these should be formatted + using the widget's locale. + + \sa QLocale QLocale::setDefault() +*/ + +void QWidgetPrivate::setLocale_helper(const QLocale &loc, bool forceUpdate) +{ + Q_Q(QWidget); + if (locale == loc && !forceUpdate) + return; + + locale = loc; + + if (!children.isEmpty()) { + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (!w) + continue; + if (w->testAttribute(Qt::WA_SetLocale)) + continue; + if (w->isWindow() && !w->testAttribute(Qt::WA_WindowPropagation)) + continue; + w->d_func()->setLocale_helper(loc, forceUpdate); + } + } + QEvent e(QEvent::LocaleChange); + QApplication::sendEvent(q, &e); +} + +void QWidget::setLocale(const QLocale &locale) +{ + Q_D(QWidget); + + setAttribute(Qt::WA_SetLocale); + d->setLocale_helper(locale); +} + +QLocale QWidget::locale() const +{ + Q_D(const QWidget); + + return d->locale; +} + +void QWidgetPrivate::resolveLocale() +{ + Q_Q(const QWidget); + + if (!q->testAttribute(Qt::WA_SetLocale)) { + setLocale_helper(q->isWindow() + ? QLocale() + : q->parentWidget()->locale()); + } +} + +void QWidget::unsetLocale() +{ + Q_D(QWidget); + setAttribute(Qt::WA_SetLocale, false); + d->resolveLocale(); +} + +static QString constructWindowTitleFromFilePath(const QString &filePath) +{ + QFileInfo fi(filePath); + QString windowTitle = fi.fileName() + QLatin1String("[*]"); +#ifndef Q_WS_MAC + QString appName = QApplication::applicationName(); + if (!appName.isEmpty()) + windowTitle += QLatin1Char(' ') + QChar(0x2014) + QLatin1Char(' ') + appName; +#endif + return windowTitle; +} + +/*! + \property QWidget::windowTitle + \brief the window title (caption) + + This property only makes sense for top-level widgets, such as + windows and dialogs. If no caption has been set, the title is based of the + \l windowFilePath. If neither of these is set, then the title is + an empty string. + + If you use the \l windowModified mechanism, the window title must + contain a "[*]" placeholder, which indicates where the '*' should + appear. Normally, it should appear right after the file name + (e.g., "document1.txt[*] - Text Editor"). If the \l + windowModified property is false (the default), the placeholder + is simply removed. + + \sa windowIcon, windowIconText, windowModified, windowFilePath +*/ +QString QWidget::windowTitle() const +{ + Q_D(const QWidget); + if (d->extra && d->extra->topextra) { + if (!d->extra->topextra->caption.isEmpty()) + return d->extra->topextra->caption; + if (!d->extra->topextra->filePath.isEmpty()) + return constructWindowTitleFromFilePath(d->extra->topextra->filePath); + } + return QString(); +} + +/*! + Returns a modified window title with the [*] place holder + replaced according to the rules described in QWidget::setWindowTitle + + This function assumes that "[*]" can be quoted by another + "[*]", so it will replace two place holders by one and + a single last one by either "*" or nothing depending on + the modified flag. + + \internal +*/ +QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widget) +{ + Q_ASSERT(widget); + +#ifdef QT_EVAL + extern QString qt_eval_adapt_window_title(const QString &title); + QString cap = qt_eval_adapt_window_title(title); +#else + QString cap = title; +#endif + + if (cap.isEmpty()) + return cap; + + QLatin1String placeHolder("[*]"); + int placeHolderLength = 3; // QLatin1String doesn't have length() + + int index = cap.indexOf(placeHolder); + + // here the magic begins + while (index != -1) { + index += placeHolderLength; + int count = 1; + while (cap.indexOf(placeHolder, index) == index) { + ++count; + index += placeHolderLength; + } + + if (count%2) { // odd number of [*] -> replace last one + int lastIndex = cap.lastIndexOf(placeHolder, index - 1); + if (widget->isWindowModified() + && widget->style()->styleHint(QStyle::SH_TitleBar_ModifyNotification, 0, widget)) + cap.replace(lastIndex, 3, QWidget::tr("*")); + else + cap.remove(lastIndex, 3); + } + + index = cap.indexOf(placeHolder, index); + } + + cap.replace(QLatin1String("[*][*]"), placeHolder); + + return cap; +} + +void QWidgetPrivate::setWindowTitle_helper(const QString &title) +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created)) + setWindowTitle_sys(qt_setWindowTitle_helperHelper(title, q)); +} + +void QWidgetPrivate::setWindowIconText_helper(const QString &title) +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created)) + setWindowIconText_sys(qt_setWindowTitle_helperHelper(title, q)); +} + +void QWidget::setWindowIconText(const QString &iconText) +{ + if (QWidget::windowIconText() == iconText) + return; + + Q_D(QWidget); + d->topData()->iconText = iconText; + d->setWindowIconText_helper(iconText); + + QEvent e(QEvent::IconTextChange); + QApplication::sendEvent(this, &e); +} + +void QWidget::setWindowTitle(const QString &title) +{ + if (QWidget::windowTitle() == title && !title.isEmpty() && !title.isNull()) + return; + + Q_D(QWidget); + d->topData()->caption = title; + d->setWindowTitle_helper(title); + + QEvent e(QEvent::WindowTitleChange); + QApplication::sendEvent(this, &e); +} + + +/*! + \property QWidget::windowIcon + \brief the widget's icon + + This property only makes sense for windows. If no icon + has been set, windowIcon() returns the application icon + (QApplication::windowIcon()). + + \sa windowIconText, windowTitle +*/ +QIcon QWidget::windowIcon() const +{ + const QWidget *w = this; + while (w) { + const QWidgetPrivate *d = w->d_func(); + if (d->extra && d->extra->topextra && d->extra->topextra->icon) + return *d->extra->topextra->icon; + w = w->parentWidget(); + } + return QApplication::windowIcon(); +} + +void QWidgetPrivate::setWindowIcon_helper() +{ + QEvent e(QEvent::WindowIconChange); + QApplication::sendEvent(q_func(), &e); + for (int i = 0; i < children.size(); ++i) { + QWidget *w = qobject_cast(children.at(i)); + if (w && !w->isWindow()) + QApplication::sendEvent(w, &e); + } +} + +void QWidget::setWindowIcon(const QIcon &icon) +{ + Q_D(QWidget); + + setAttribute(Qt::WA_SetWindowIcon, !icon.isNull()); + d->createTLExtra(); + + if (!d->extra->topextra->icon) + d->extra->topextra->icon = new QIcon(); + *d->extra->topextra->icon = icon; + + delete d->extra->topextra->iconPixmap; + d->extra->topextra->iconPixmap = 0; + + d->setWindowIcon_sys(); + d->setWindowIcon_helper(); +} + + +/*! + \property QWidget::windowIconText + \brief the widget's icon text + + This property only makes sense for windows. If no icon + text has been set, this functions returns an empty string. + + \sa windowIcon, windowTitle +*/ + +QString QWidget::windowIconText() const +{ + Q_D(const QWidget); + return (d->extra && d->extra->topextra) ? d->extra->topextra->iconText : QString(); +} + +/*! + \property QWidget::windowFilePath + \since 4.4 + \brief the file path associated with a widget + + This property only makes sense for windows. It associates a file path with + a window. If you set the file path, but have not set the window title, Qt + sets the window title to contain a string created using the following + components. + + On Mac OS X: + + \list + \o The file name of the specified path, obtained using QFileInfo::fileName(). + \endlist + + On Windows and X11: + + \list + \o The file name of the specified path, obtained using QFileInfo::fileName(). + \o An optional \c{*} character, if the \l windowModified property is set. + \o The \c{0x2014} unicode character, padded either side by spaces. + \o The application name, obtained from the application's + \l{QCoreApplication::}{applicationName} property. + \endlist + + If the window title is set at any point, then the window title takes precedence and + will be shown instead of the file path string. + + Additionally, on Mac OS X, this has an added benefit that it sets the + \l{http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGWindows/chapter_17_section_3.html}{proxy icon} + for the window, assuming that the file path exists. + + If no file path is set, this property contains an empty string. + + By default, this property contains an empty string. + + \sa windowTitle, windowIcon +*/ + +QString QWidget::windowFilePath() const +{ + Q_D(const QWidget); + return (d->extra && d->extra->topextra) ? d->extra->topextra->filePath : QString(); +} + +void QWidget::setWindowFilePath(const QString &filePath) +{ + if (filePath == windowFilePath()) + return; + + Q_D(QWidget); + + d->createTLExtra(); + d->extra->topextra->filePath = filePath; + d->setWindowFilePath_helper(filePath); +} + +void QWidgetPrivate::setWindowFilePath_helper(const QString &filePath) +{ + if (extra->topextra && extra->topextra->caption.isEmpty()) { +#ifdef Q_WS_MAC + setWindowTitle_helper(QFileInfo(filePath).fileName()); +#else + Q_Q(QWidget); + Q_UNUSED(filePath); + setWindowTitle_helper(q->windowTitle()); +#endif + } +#ifdef Q_WS_MAC + setWindowFilePath_sys(filePath); +#endif +} + +/*! + Returns the window's role, or an empty string. + + \sa windowIcon, windowTitle +*/ + +QString QWidget::windowRole() const +{ + Q_D(const QWidget); + return (d->extra && d->extra->topextra) ? d->extra->topextra->role : QString(); +} + +/*! + Sets the window's role to \a role. This only makes sense for + windows on X11. +*/ +void QWidget::setWindowRole(const QString &role) +{ +#if defined(Q_WS_X11) + Q_D(QWidget); + d->topData()->role = role; + d->setWindowRole(); +#else + Q_UNUSED(role) +#endif +} + +/*! + \property QWidget::mouseTracking + \brief whether mouse tracking is enabled for the widget + + If mouse tracking is disabled (the default), the widget only + receives mouse move events when at least one mouse button is + pressed while the mouse is being moved. + + If mouse tracking is enabled, the widget receives mouse move + events even if no buttons are pressed. + + \sa mouseMoveEvent() +*/ + + +/*! + Sets the widget's focus proxy to widget \a w. If \a w is 0, the + function resets this widget to have no focus proxy. + + Some widgets can "have focus", but create a child widget, such as + QLineEdit, to actually handle the focus. In this case, the widget + can set the line edit to be its focus proxy. + + setFocusProxy() sets the widget which will actually get focus when + "this widget" gets it. If there is a focus proxy, setFocus() and + hasFocus() operate on the focus proxy. + + \sa focusProxy() +*/ + +void QWidget::setFocusProxy(QWidget * w) +{ + Q_D(QWidget); + if (!w && !d->extra) + return; + + for (QWidget* fp = w; fp; fp = fp->focusProxy()) { + if (fp == this) { + qWarning("QWidget: %s (%s) already in focus proxy chain", metaObject()->className(), objectName().toLocal8Bit().constData()); + return; + } + } + + d->createExtra(); + d->extra->focus_proxy = w; +} + + +/*! + Returns the focus proxy, or 0 if there is no focus proxy. + + \sa setFocusProxy() +*/ + +QWidget * QWidget::focusProxy() const +{ + Q_D(const QWidget); + return d->extra ? (QWidget *)d->extra->focus_proxy : 0; +} + + +/*! + \property QWidget::focus + \brief whether this widget (or its focus proxy) has the keyboard + input focus + + By default, this property is false. + + \note Obtaining the value of this property for a widget is effectively equivalent + to checking whether QApplication::focusWidget() refers to the widget. + + \sa setFocus(), clearFocus(), setFocusPolicy(), QApplication::focusWidget() +*/ +bool QWidget::hasFocus() const +{ + const QWidget* w = this; + while (w->d_func()->extra && w->d_func()->extra->focus_proxy) + w = w->d_func()->extra->focus_proxy; + if (QWidget *window = w->window()) { +#ifndef QT_NO_GRAPHICSVIEW + QWExtra *e = window->d_func()->extra; + if (e && e->proxyWidget && e->proxyWidget->hasFocus() && window->focusWidget() == w) + return true; +#endif + } + return (QApplication::focusWidget() == w); +} + +/*! + Gives the keyboard input focus to this widget (or its focus + proxy) if this widget or one of its parents is the \link + isActiveWindow() active window\endlink. The \a reason argument will + be passed into any focus event sent from this function, it is used + to give an explanation of what caused the widget to get focus. + If the window is not active, the widget will be given the focus when + the window becomes active. + + First, a focus out event is sent to the focus widget (if any) to + tell it that it is about to lose the focus. Then a focus in event + is sent to this widget to tell it that it just received the focus. + (Nothing happens if the focus in and focus out widgets are the + same.) + + \note On embedded platforms, setFocus() will not cause an input panel + to be opened by the input method. If you want this to happen, you + have to send a QEvent::RequestSoftwareInputPanel event to the + widget yourself. + + setFocus() gives focus to a widget regardless of its focus policy, + but does not clear any keyboard grab (see grabKeyboard()). + + Be aware that if the widget is hidden, it will not accept focus + until it is shown. + + \warning If you call setFocus() in a function which may itself be + called from focusOutEvent() or focusInEvent(), you may get an + infinite recursion. + + \sa hasFocus(), clearFocus(), focusInEvent(), focusOutEvent(), + setFocusPolicy(), focusWidget(), QApplication::focusWidget(), grabKeyboard(), + grabMouse(), {Keyboard Focus}, QEvent::RequestSoftwareInputPanel +*/ + +void QWidget::setFocus(Qt::FocusReason reason) +{ + if (!isEnabled()) + return; + + QWidget *f = this; + while (f->d_func()->extra && f->d_func()->extra->focus_proxy) + f = f->d_func()->extra->focus_proxy; + + if (QApplication::focusWidget() == f +#if defined(Q_WS_WIN) + && GetFocus() == f->internalWinId() +#endif + ) + return; + +#ifndef QT_NO_GRAPHICSVIEW + QWidget *previousProxyFocus = 0; + if (QWExtra *topData = window()->d_func()->extra) { + if (topData->proxyWidget && topData->proxyWidget->hasFocus()) { + previousProxyFocus = topData->proxyWidget->widget()->focusWidget(); + if (previousProxyFocus && previousProxyFocus->focusProxy()) + previousProxyFocus = previousProxyFocus->focusProxy(); + if (previousProxyFocus == this && !topData->proxyWidget->d_func()->proxyIsGivingFocus) + return; + } + } +#endif + + QWidget *w = f; + if (isHidden()) { + while (w && w->isHidden()) { + w->d_func()->focus_child = f; + w = w->isWindow() ? 0 : w->parentWidget(); + } + } else { + while (w) { + w->d_func()->focus_child = f; + w = w->isWindow() ? 0 : w->parentWidget(); + } + } + +#ifndef QT_NO_GRAPHICSVIEW + // Update proxy state + if (QWExtra *topData = window()->d_func()->extra) { + if (topData->proxyWidget && !topData->proxyWidget->hasFocus()) { + topData->proxyWidget->d_func()->focusFromWidgetToProxy = 1; + topData->proxyWidget->setFocus(reason); + topData->proxyWidget->d_func()->focusFromWidgetToProxy = 0; + } + } +#endif + + if (f->isActiveWindow()) { + QApplicationPrivate::setFocusWidget(f, reason); +#ifndef QT_NO_ACCESSIBILITY +# ifdef Q_OS_WIN + // The negation of the condition in setFocus_sys + if (!(testAttribute(Qt::WA_WState_Created) && window()->windowType() != Qt::Popup && internalWinId())) + //setFocusWidget will already post a focus event for us (that the AT client receives) on Windows +# endif + QAccessible::updateAccessibility(f, 0, QAccessible::Focus); +#endif +#ifndef QT_NO_GRAPHICSVIEW + if (QWExtra *topData = window()->d_func()->extra) { + if (topData->proxyWidget) { + if (previousProxyFocus && previousProxyFocus != f) { + // Send event to self + QFocusEvent event(QEvent::FocusOut, reason); + QPointer that = previousProxyFocus; + QApplication::sendEvent(previousProxyFocus, &event); + if (that) + QApplication::sendEvent(that->style(), &event); + } + if (!isHidden()) { +#ifndef QT_NO_GRAPHICSVIEW + // Update proxy state + if (QWExtra *topData = window()->d_func()->extra) + if (topData->proxyWidget && topData->proxyWidget->hasFocus()) + topData->proxyWidget->d_func()->updateProxyInputMethodAcceptanceFromWidget(); +#endif + // Send event to self + QFocusEvent event(QEvent::FocusIn, reason); + QPointer that = f; + QApplication::sendEvent(f, &event); + if (that) + QApplication::sendEvent(that->style(), &event); + } + } + } +#endif + } +} + +/*! + \fn void QWidget::setFocus() + \overload + + Gives the keyboard input focus to this widget (or its focus + proxy) if this widget or one of its parents is the + \l{isActiveWindow()}{active window}. +*/ + +/*! + Takes keyboard input focus from the widget. + + If the widget has active focus, a \link focusOutEvent() focus out + event\endlink is sent to this widget to tell it that it is about + to lose the focus. + + This widget must enable focus setting in order to get the keyboard + input focus, i.e. it must call setFocusPolicy(). + + \sa hasFocus(), setFocus(), focusInEvent(), focusOutEvent(), + setFocusPolicy(), QApplication::focusWidget() +*/ + +void QWidget::clearFocus() +{ + QWidget *w = this; + while (w) { + if (w->d_func()->focus_child == this) + w->d_func()->focus_child = 0; + w = w->parentWidget(); + } +#ifndef QT_NO_GRAPHICSVIEW + QWExtra *topData = d_func()->extra; + if (topData && topData->proxyWidget) + topData->proxyWidget->clearFocus(); +#endif + + if (hasFocus()) { + // Update proxy state + QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason); +#if defined(Q_WS_WIN) + if (!(windowType() == Qt::Popup) && GetFocus() == internalWinId()) + SetFocus(0); + else +#endif + { +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(this, 0, QAccessible::Focus); +#endif + } + } +} + + +/*! + \fn bool QWidget::focusNextChild() + + Finds a new widget to give the keyboard focus to, as appropriate + for \key Tab, and returns true if it can find a new widget, or + false if it can't. + + \sa focusPreviousChild() +*/ + +/*! + \fn bool QWidget::focusPreviousChild() + + Finds a new widget to give the keyboard focus to, as appropriate + for \key Shift+Tab, and returns true if it can find a new widget, + or false if it can't. + + \sa focusNextChild() +*/ + +/*! + Finds a new widget to give the keyboard focus to, as appropriate + for Tab and Shift+Tab, and returns true if it can find a new + widget, or false if it can't. + + If \a next is true, this function searches forward, if \a next + is false, it searches backward. + + Sometimes, you will want to reimplement this function. For + example, a web browser might reimplement it to move its "current + active link" forward or backward, and call + focusNextPrevChild() only when it reaches the last or + first link on the "page". + + Child widgets call focusNextPrevChild() on their parent widgets, + but only the window that contains the child widgets decides where + to redirect focus. By reimplementing this function for an object, + you thus gain control of focus traversal for all child widgets. + + \sa focusNextChild(), focusPreviousChild() +*/ + +bool QWidget::focusNextPrevChild(bool next) +{ + Q_D(QWidget); + QWidget* p = parentWidget(); + bool isSubWindow = (windowType() == Qt::SubWindow); + if (!isWindow() && !isSubWindow && p) + return p->focusNextPrevChild(next); +#ifndef QT_NO_GRAPHICSVIEW + if (d->extra && d->extra->proxyWidget) + return d->extra->proxyWidget->focusNextPrevChild(next); +#endif + QWidget *w = QApplicationPrivate::focusNextPrevChild_helper(this, next); + if (!w) return false; + + w->setFocus(next ? Qt::TabFocusReason : Qt::BacktabFocusReason); + return true; +} + +/*! + Returns the last child of this widget that setFocus had been + called on. For top level widgets this is the widget that will get + focus in case this window gets activated + + This is not the same as QApplication::focusWidget(), which returns + the focus widget in the currently active window. +*/ + +QWidget *QWidget::focusWidget() const +{ + return const_cast(d_func()->focus_child); +} + +/*! + Returns the next widget in this widget's focus chain. + + \sa previousInFocusChain() +*/ +QWidget *QWidget::nextInFocusChain() const +{ + return const_cast(d_func()->focus_next); +} + +/*! + \brief The previousInFocusChain function returns the previous + widget in this widget's focus chain. + + \sa nextInFocusChain() + + \since 4.6 +*/ +QWidget *QWidget::previousInFocusChain() const +{ + return const_cast(d_func()->focus_prev); +} + +/*! + \property QWidget::isActiveWindow + \brief whether this widget's window is the active window + + The active window is the window that contains the widget that has + keyboard focus (The window may still have focus if it has no + widgets or none of its widgets accepts keyboard focus). + + When popup windows are visible, this property is true for both the + active window \e and for the popup. + + By default, this property is false. + + \sa activateWindow(), QApplication::activeWindow() +*/ +bool QWidget::isActiveWindow() const +{ + QWidget *tlw = window(); + if(tlw == QApplication::activeWindow() || (isVisible() && (tlw->windowType() == Qt::Popup))) + return true; + +#ifndef QT_NO_GRAPHICSVIEW + if (QWExtra *tlwExtra = tlw->d_func()->extra) { + if (isVisible() && tlwExtra->proxyWidget) + return tlwExtra->proxyWidget->isActiveWindow(); + } +#endif + +#ifdef Q_WS_MAC + extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp + if(qt_mac_is_macdrawer(tlw) && + tlw->parentWidget() && tlw->parentWidget()->isActiveWindow()) + return true; + + extern bool qt_mac_insideKeyWindow(const QWidget *); //qwidget_mac.cpp + if (QApplication::testAttribute(Qt::AA_MacPluginApplication) && qt_mac_insideKeyWindow(tlw)) + return true; +#endif + if(style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, this)) { + if(tlw->windowType() == Qt::Tool && + !tlw->isModal() && + (!tlw->parentWidget() || tlw->parentWidget()->isActiveWindow())) + return true; + QWidget *w = QApplication::activeWindow(); + while(w && tlw->windowType() == Qt::Tool && + !w->isModal() && w->parentWidget()) { + w = w->parentWidget()->window(); + if(w == tlw) + return true; + } + } +#if defined(Q_WS_WIN32) + HWND active = GetActiveWindow(); + if (!tlw->testAttribute(Qt::WA_WState_Created)) + return false; + return active == tlw->internalWinId() || ::IsChild(active, tlw->internalWinId()); +#else + return false; +#endif +} + +/*! + Puts the \a second widget after the \a first widget in the focus order. + + Note that since the tab order of the \a second widget is changed, you + should order a chain like this: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 9 + + \e not like this: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 10 + + If \a first or \a second has a focus proxy, setTabOrder() + correctly substitutes the proxy. + + \sa setFocusPolicy(), setFocusProxy(), {Keyboard Focus} +*/ +void QWidget::setTabOrder(QWidget* first, QWidget *second) +{ + if (!first || !second || first->focusPolicy() == Qt::NoFocus || second->focusPolicy() == Qt::NoFocus) + return; + + if (first->window() != second->window()) { + qWarning("QWidget::setTabOrder: 'first' and 'second' must be in the same window"); + return; + } + + QWidget *fp = first->focusProxy(); + if (fp) { + // If first is redirected, set first to the last child of first + // that can take keyboard focus so that second is inserted after + // that last child, and the focus order within first is (more + // likely to be) preserved. + QList l = first->findChildren(); + for (int i = l.size()-1; i >= 0; --i) { + QWidget * next = l.at(i); + if (next->window() == fp->window()) { + fp = next; + if (fp->focusPolicy() != Qt::NoFocus) + break; + } + } + first = fp; + } + + if (fp == second) + return; + + if (QWidget *sp = second->focusProxy()) + second = sp; + +// QWidget *fp = first->d_func()->focus_prev; + QWidget *fn = first->d_func()->focus_next; + + if (fn == second || first == second) + return; + + QWidget *sp = second->d_func()->focus_prev; + QWidget *sn = second->d_func()->focus_next; + + fn->d_func()->focus_prev = second; + first->d_func()->focus_next = second; + + second->d_func()->focus_next = fn; + second->d_func()->focus_prev = first; + + sp->d_func()->focus_next = sn; + sn->d_func()->focus_prev = sp; + + + Q_ASSERT(first->d_func()->focus_next->d_func()->focus_prev == first); + Q_ASSERT(first->d_func()->focus_prev->d_func()->focus_next == first); + + Q_ASSERT(second->d_func()->focus_next->d_func()->focus_prev == second); + Q_ASSERT(second->d_func()->focus_prev->d_func()->focus_next == second); +} + +/*!\internal + + Moves the relevant subwidgets of this widget from the \a oldtlw's + tab chain to that of the new parent, if there's anything to move and + we're really moving + + This function is called from QWidget::reparent() *after* the widget + has been reparented. + + \sa reparent() +*/ + +void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw) +{ + Q_Q(QWidget); + if (oldtlw == q->window()) + return; // nothing to do + + if(focus_child) + focus_child->clearFocus(); + + // separate the focus chain into new (children of myself) and old (the rest) + QWidget *firstOld = 0; + //QWidget *firstNew = q; //invariant + QWidget *o = 0; // last in the old list + QWidget *n = q; // last in the new list + + bool prevWasNew = true; + QWidget *w = focus_next; + + //Note: for efficiency, we do not maintain the list invariant inside the loop + //we append items to the relevant list, and we optimize by not changing pointers + //when subsequent items are going into the same list. + while (w != q) { + bool currentIsNew = q->isAncestorOf(w); + if (currentIsNew) { + if (!prevWasNew) { + //prev was old -- append to new list + n->d_func()->focus_next = w; + w->d_func()->focus_prev = n; + } + n = w; + } else { + if (prevWasNew) { + //prev was new -- append to old list, if there is one + if (o) { + o->d_func()->focus_next = w; + w->d_func()->focus_prev = o; + } else { + // "create" the old list + firstOld = w; + } + } + o = w; + } + w = w->d_func()->focus_next; + prevWasNew = currentIsNew; + } + + //repair the old list: + if (firstOld) { + o->d_func()->focus_next = firstOld; + firstOld->d_func()->focus_prev = o; + } + + if (!q->isWindow()) { + QWidget *topLevel = q->window(); + //insert new chain into toplevel's chain + + QWidget *prev = topLevel->d_func()->focus_prev; + + topLevel->d_func()->focus_prev = n; + prev->d_func()->focus_next = q; + + focus_prev = prev; + n->d_func()->focus_next = topLevel; + } else { + //repair the new list + n->d_func()->focus_next = q; + focus_prev = n; + } + +} + +/*!\internal + + Measures the shortest distance from a point to a rect. + + This function is called from QDesktopwidget::screen(QPoint) to find the + closest screen for a point. + In directional KeypadNavigation, it is called to find the closest + widget to the current focus widget center. +*/ +int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r) +{ + int dx = 0; + int dy = 0; + if (p.x() < r.left()) + dx = r.left() - p.x(); + else if (p.x() > r.right()) + dx = p.x() - r.right(); + if (p.y() < r.top()) + dy = r.top() - p.y(); + else if (p.y() > r.bottom()) + dy = p.y() - r.bottom(); + return dx + dy; +} + +/*! + \property QWidget::frameSize + \brief the size of the widget including any window frame + + By default, this property contains a value that depends on the user's + platform and screen geometry. +*/ +QSize QWidget::frameSize() const +{ + Q_D(const QWidget); + if (isWindow() && !(windowType() == Qt::Popup)) { + QRect fs = d->frameStrut(); + return QSize(data->crect.width() + fs.left() + fs.right(), + data->crect.height() + fs.top() + fs.bottom()); + } + return data->crect.size(); +} + +/*! \fn void QWidget::move(int x, int y) + + \overload + + This corresponds to move(QPoint(\a x, \a y)). +*/ + +void QWidget::move(const QPoint &p) +{ + Q_D(QWidget); + setAttribute(Qt::WA_Moved); + if (isWindow()) + d->topData()->posFromMove = true; + if (testAttribute(Qt::WA_WState_Created)) { + d->setGeometry_sys(p.x() + geometry().x() - QWidget::x(), + p.y() + geometry().y() - QWidget::y(), + width(), height(), true); + d->setDirtyOpaqueRegion(); + } else { + data->crect.moveTopLeft(p); // no frame yet + setAttribute(Qt::WA_PendingMoveEvent); + } +} + +/*! \fn void QWidget::resize(int w, int h) + \overload + + This corresponds to resize(QSize(\a w, \a h)). +*/ + +void QWidget::resize(const QSize &s) +{ + Q_D(QWidget); + setAttribute(Qt::WA_Resized); + if (testAttribute(Qt::WA_WState_Created)) { + d->setGeometry_sys(geometry().x(), geometry().y(), s.width(), s.height(), false); + d->setDirtyOpaqueRegion(); + } else { + data->crect.setSize(s.boundedTo(maximumSize()).expandedTo(minimumSize())); + setAttribute(Qt::WA_PendingResizeEvent); + } +} + +void QWidget::setGeometry(const QRect &r) +{ + Q_D(QWidget); + setAttribute(Qt::WA_Resized); + setAttribute(Qt::WA_Moved); + if (isWindow()) + d->topData()->posFromMove = false; + if (testAttribute(Qt::WA_WState_Created)) { + d->setGeometry_sys(r.x(), r.y(), r.width(), r.height(), true); + d->setDirtyOpaqueRegion(); + } else { + data->crect.setTopLeft(r.topLeft()); + data->crect.setSize(r.size().boundedTo(maximumSize()).expandedTo(minimumSize())); + setAttribute(Qt::WA_PendingMoveEvent); + setAttribute(Qt::WA_PendingResizeEvent); + } +} + +/*! + \since 4.2 + Saves the current geometry and state for top-level widgets. + + To save the geometry when the window closes, you can + implement a close event like this: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 11 + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + Use QMainWindow::saveState() to save the geometry and the state of + toolbars and dock widgets. + + \sa restoreGeometry(), QMainWindow::saveState(), QMainWindow::restoreState() +*/ +QByteArray QWidget::saveGeometry() const +{ +#ifdef QT_MAC_USE_COCOA + // We check if the window was maximized during this invocation. If so, we need to record the + // starting position as 0,0. + Q_D(const QWidget); + QRect newFramePosition = frameGeometry(); + QRect newNormalPosition = normalGeometry(); + if(d->topData()->wasMaximized && !(windowState() & Qt::WindowMaximized)) { + // Change the starting position + newFramePosition.moveTo(0, 0); + newNormalPosition.moveTo(0, 0); + } +#endif // QT_MAC_USE_COCOA + QByteArray array; + QDataStream stream(&array, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_4_0); + const quint32 magicNumber = 0x1D9D0CB; + quint16 majorVersion = 1; + quint16 minorVersion = 0; + stream << magicNumber + << majorVersion + << minorVersion +#ifdef QT_MAC_USE_COCOA + << newFramePosition + << newNormalPosition +#else + << frameGeometry() + << normalGeometry() +#endif // QT_MAC_USE_COCOA + << qint32(QApplication::desktop()->screenNumber(this)) + << quint8(windowState() & Qt::WindowMaximized) + << quint8(windowState() & Qt::WindowFullScreen); + return array; +} + +/*! + \since 4.2 + + Restores the geometry and state top-level widgets stored in the + byte array \a geometry. Returns true on success; otherwise + returns false. + + If the restored geometry is off-screen, it will be modified to be + inside the available screen geometry. + + To restore geometry saved using QSettings, you can use code like + this: + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 12 + + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. + + Use QMainWindow::restoreState() to restore the geometry and the + state of toolbars and dock widgets. + + \sa saveGeometry(), QSettings, QMainWindow::saveState(), QMainWindow::restoreState() +*/ +bool QWidget::restoreGeometry(const QByteArray &geometry) +{ + if (geometry.size() < 4) + return false; + QDataStream stream(geometry); + stream.setVersion(QDataStream::Qt_4_0); + + const quint32 magicNumber = 0x1D9D0CB; + quint32 storedMagicNumber; + stream >> storedMagicNumber; + if (storedMagicNumber != magicNumber) + return false; + + const quint16 currentMajorVersion = 1; + quint16 majorVersion = 0; + quint16 minorVersion = 0; + + stream >> majorVersion >> minorVersion; + + if (majorVersion != currentMajorVersion) + return false; + // (Allow all minor versions.) + + QRect restoredFrameGeometry; + QRect restoredNormalGeometry; + qint32 restoredScreenNumber; + quint8 maximized; + quint8 fullScreen; + + stream >> restoredFrameGeometry + >> restoredNormalGeometry + >> restoredScreenNumber + >> maximized + >> fullScreen; + + const int frameHeight = 20; + if (!restoredFrameGeometry.isValid()) + restoredFrameGeometry = QRect(QPoint(0,0), sizeHint()); + + if (!restoredNormalGeometry.isValid()) + restoredNormalGeometry = QRect(QPoint(0, frameHeight), sizeHint()); + if (!restoredNormalGeometry.isValid()) { + // use the widget's adjustedSize if the sizeHint() doesn't help + restoredNormalGeometry.setSize(restoredNormalGeometry + .size() + .expandedTo(d_func()->adjustedSize())); + } + + const QDesktopWidget * const desktop = QApplication::desktop(); + if (restoredScreenNumber >= desktop->numScreens()) + restoredScreenNumber = desktop->primaryScreen(); + + const QRect availableGeometry = desktop->availableGeometry(restoredScreenNumber); + + // Modify the restored geometry if we are about to restore to coordinates + // that would make the window "lost". This happens if: + // - The restored geometry is completely oustside the available geometry + // - The title bar is outside the available geometry. + // - (Mac only) The window is higher than the available geometry. It must + // be possible to bring the size grip on screen by moving the window. +#ifdef Q_WS_MAC + restoredFrameGeometry.setHeight(qMin(restoredFrameGeometry.height(), availableGeometry.height())); + restoredNormalGeometry.setHeight(qMin(restoredNormalGeometry.height(), availableGeometry.height() - frameHeight)); +#endif + + if (!restoredFrameGeometry.intersects(availableGeometry)) { + restoredFrameGeometry.moveBottom(qMin(restoredFrameGeometry.bottom(), availableGeometry.bottom())); + restoredFrameGeometry.moveLeft(qMax(restoredFrameGeometry.left(), availableGeometry.left())); + restoredFrameGeometry.moveRight(qMin(restoredFrameGeometry.right(), availableGeometry.right())); + } + restoredFrameGeometry.moveTop(qMax(restoredFrameGeometry.top(), availableGeometry.top())); + + if (!restoredNormalGeometry.intersects(availableGeometry)) { + restoredNormalGeometry.moveBottom(qMin(restoredNormalGeometry.bottom(), availableGeometry.bottom())); + restoredNormalGeometry.moveLeft(qMax(restoredNormalGeometry.left(), availableGeometry.left())); + restoredNormalGeometry.moveRight(qMin(restoredNormalGeometry.right(), availableGeometry.right())); + } + restoredNormalGeometry.moveTop(qMax(restoredNormalGeometry.top(), availableGeometry.top() + frameHeight)); + + if (maximized || fullScreen) { + // set geomerty before setting the window state to make + // sure the window is maximized to the right screen. + // Skip on windows: the window is restored into a broken + // half-maximized state. +#ifndef Q_WS_WIN + setGeometry(restoredNormalGeometry); +#endif + Qt::WindowStates ws = windowState(); + if (maximized) + ws |= Qt::WindowMaximized; + if (fullScreen) + ws |= Qt::WindowFullScreen; + setWindowState(ws); + d_func()->topData()->normalGeometry = restoredNormalGeometry; + } else { + QPoint offset; +#ifdef Q_WS_X11 + if (isFullScreen()) + offset = d_func()->topData()->fullScreenOffset; +#endif + setWindowState(windowState() & ~(Qt::WindowMaximized | Qt::WindowFullScreen)); + move(restoredFrameGeometry.topLeft() + offset); + resize(restoredNormalGeometry.size()); + } + return true; +} + +/*!\fn void QWidget::setGeometry(int x, int y, int w, int h) + \overload + + This corresponds to setGeometry(QRect(\a x, \a y, \a w, \a h)). +*/ + +/*! + Sets the margins around the contents of the widget to have the sizes + \a left, \a top, \a right, and \a bottom. The margins are used by + the layout system, and may be used by subclasses to specify the area + to draw in (e.g. excluding the frame). + + Changing the margins will trigger a resizeEvent(). + + \sa contentsRect(), getContentsMargins() +*/ +void QWidget::setContentsMargins(int left, int top, int right, int bottom) +{ + Q_D(QWidget); + if (left == d->leftmargin && top == d->topmargin + && right == d->rightmargin && bottom == d->bottommargin) + return; + d->leftmargin = left; + d->topmargin = top; + d->rightmargin = right; + d->bottommargin = bottom; + + if (QLayout *l=d->layout) + l->update(); //force activate; will do updateGeometry + else + updateGeometry(); + + // ### Qt 5: compat, remove + if (isVisible()) { + update(); + QResizeEvent e(data->crect.size(), data->crect.size()); + QApplication::sendEvent(this, &e); + } else { + setAttribute(Qt::WA_PendingResizeEvent, true); + } + + QEvent e(QEvent::ContentsRectChange); + QApplication::sendEvent(this, &e); +} + +/*! + \overload + \since 4.6 + + \brief The setContentsMargins function sets the margins around the + widget's contents. + + Sets the margins around the contents of the widget to have the + sizes determined by \a margins. The margins are + used by the layout system, and may be used by subclasses to + specify the area to draw in (e.g. excluding the frame). + + Changing the margins will trigger a resizeEvent(). + + \sa contentsRect(), getContentsMargins() +*/ +void QWidget::setContentsMargins(const QMargins &margins) +{ + setContentsMargins(margins.left(), margins.top(), + margins.right(), margins.bottom()); +} + +/*! + Returns the widget's contents margins for \a left, \a top, \a + right, and \a bottom. + + \sa setContentsMargins(), contentsRect() + */ +void QWidget::getContentsMargins(int *left, int *top, int *right, int *bottom) const +{ + Q_D(const QWidget); + if (left) + *left = d->leftmargin; + if (top) + *top = d->topmargin; + if (right) + *right = d->rightmargin; + if (bottom) + *bottom = d->bottommargin; +} + +/*! + \since 4.6 + + \brief The contentsMargins function returns the widget's contents margins. + + \sa getContentsMargins(), setContentsMargins(), contentsRect() + */ +QMargins QWidget::contentsMargins() const +{ + Q_D(const QWidget); + return QMargins(d->leftmargin, d->topmargin, d->rightmargin, d->bottommargin); +} + + +/*! + Returns the area inside the widget's margins. + + \sa setContentsMargins(), getContentsMargins() +*/ +QRect QWidget::contentsRect() const +{ + Q_D(const QWidget); + return QRect(QPoint(d->leftmargin, d->topmargin), + QPoint(data->crect.width() - 1 - d->rightmargin, + data->crect.height() - 1 - d->bottommargin)); + +} + + + +/*! + \fn void QWidget::customContextMenuRequested(const QPoint &pos) + + This signal is emitted when the widget's \l contextMenuPolicy is + Qt::CustomContextMenu, and the user has requested a context menu on + the widget. The position \a pos is the position of the context menu + event that the widget receives. Normally this is in widget + coordinates. The exception to this rule is QAbstractScrollArea and + its subclasses that map the context menu event to coordinates of the + \link QAbstractScrollArea::viewport() viewport() \endlink . + + + \sa mapToGlobal() QMenu contextMenuPolicy +*/ + + +/*! + \property QWidget::contextMenuPolicy + \brief how the widget shows a context menu + + The default value of this property is Qt::DefaultContextMenu, + which means the contextMenuEvent() handler is called. Other values + are Qt::NoContextMenu, Qt::PreventContextMenu, + Qt::ActionsContextMenu, and Qt::CustomContextMenu. With + Qt::CustomContextMenu, the signal customContextMenuRequested() is + emitted. + + \sa contextMenuEvent(), customContextMenuRequested(), actions() +*/ + +Qt::ContextMenuPolicy QWidget::contextMenuPolicy() const +{ + return (Qt::ContextMenuPolicy)data->context_menu_policy; +} + +void QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy) +{ + data->context_menu_policy = (uint) policy; +} + +/*! + \property QWidget::focusPolicy + \brief the way the widget accepts keyboard focus + + The policy is Qt::TabFocus if the widget accepts keyboard + focus by tabbing, Qt::ClickFocus if the widget accepts + focus by clicking, Qt::StrongFocus if it accepts both, and + Qt::NoFocus (the default) if it does not accept focus at + all. + + You must enable keyboard focus for a widget if it processes + keyboard events. This is normally done from the widget's + constructor. For instance, the QLineEdit constructor calls + setFocusPolicy(Qt::StrongFocus). + + If the widget has a focus proxy, then the focus policy will + be propagated to it. + + \sa focusInEvent(), focusOutEvent(), keyPressEvent(), keyReleaseEvent(), enabled +*/ + + +Qt::FocusPolicy QWidget::focusPolicy() const +{ + return (Qt::FocusPolicy)data->focus_policy; +} + +void QWidget::setFocusPolicy(Qt::FocusPolicy policy) +{ + data->focus_policy = (uint) policy; + Q_D(QWidget); + if (d->extra && d->extra->focus_proxy) + d->extra->focus_proxy->setFocusPolicy(policy); +} + +/*! + \property QWidget::updatesEnabled + \brief whether updates are enabled + + An updates enabled widget receives paint events and has a system + background; a disabled widget does not. This also implies that + calling update() and repaint() has no effect if updates are + disabled. + + By default, this property is true. + + setUpdatesEnabled() is normally used to disable updates for a + short period of time, for instance to avoid screen flicker during + large changes. In Qt, widgets normally do not generate screen + flicker, but on X11 the server might erase regions on the screen + when widgets get hidden before they can be replaced by other + widgets. Disabling updates solves this. + + Example: + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 13 + + Disabling a widget implicitly disables all its children. Enabling a widget + enables all child widgets \e except top-level widgets or those that + have been explicitly disabled. Re-enabling updates implicitly calls + update() on the widget. + + \sa paintEvent() +*/ +void QWidget::setUpdatesEnabled(bool enable) +{ + Q_D(QWidget); + setAttribute(Qt::WA_ForceUpdatesDisabled, !enable); + d->setUpdatesEnabled_helper(enable); +} + +/*! \fn void QWidget::show() + + Shows the widget and its child widgets. This function is + equivalent to setVisible(true). + + \sa raise(), showEvent(), hide(), setVisible(), showMinimized(), showMaximized(), + showNormal(), isVisible() +*/ + + +/*! \internal + + Makes the widget visible in the isVisible() meaning of the word. + It is only called for toplevels or widgets with visible parents. + */ +void QWidgetPrivate::show_recursive() +{ + Q_Q(QWidget); + // polish if necessary + + if (!q->testAttribute(Qt::WA_WState_Created)) + createRecursively(); + q->ensurePolished(); + +#ifdef QT3_SUPPORT + if(sendChildEvents) + QApplication::sendPostedEvents(q, QEvent::ChildInserted); +#endif + if (!q->isWindow() && q->parentWidget()->d_func()->layout && !q->parentWidget()->data->in_show) + q->parentWidget()->d_func()->layout->activate(); + // activate our layout before we and our children become visible + if (layout) + layout->activate(); + + show_helper(); +} + +void QWidgetPrivate::sendPendingMoveAndResizeEvents(bool recursive, bool disableUpdates) +{ + Q_Q(QWidget); + + disableUpdates = disableUpdates && q->updatesEnabled(); + if (disableUpdates) + q->setAttribute(Qt::WA_UpdatesDisabled); + + if (q->testAttribute(Qt::WA_PendingMoveEvent)) { + QMoveEvent e(data.crect.topLeft(), data.crect.topLeft()); + QApplication::sendEvent(q, &e); + q->setAttribute(Qt::WA_PendingMoveEvent, false); + } + + if (q->testAttribute(Qt::WA_PendingResizeEvent)) { + QResizeEvent e(data.crect.size(), QSize()); + QApplication::sendEvent(q, &e); + q->setAttribute(Qt::WA_PendingResizeEvent, false); + } + + if (disableUpdates) + q->setAttribute(Qt::WA_UpdatesDisabled, false); + + if (!recursive) + return; + + for (int i = 0; i < children.size(); ++i) { + if (QWidget *child = qobject_cast(children.at(i))) + child->d_func()->sendPendingMoveAndResizeEvents(recursive, disableUpdates); + } +} + +void QWidgetPrivate::activateChildLayoutsRecursively() +{ + sendPendingMoveAndResizeEvents(false, true); + + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast(children.at(i)); + if (!child || child->isHidden() || child->isWindow()) + continue; + + child->ensurePolished(); + + // Activate child's layout + QWidgetPrivate *childPrivate = child->d_func(); + if (childPrivate->layout) + childPrivate->layout->activate(); + + // Pretend we're visible. + const bool wasVisible = child->isVisible(); + if (!wasVisible) + child->setAttribute(Qt::WA_WState_Visible); + + // Do the same for all my children. + childPrivate->activateChildLayoutsRecursively(); + + // We're not cheating anymore. + if (!wasVisible) + child->setAttribute(Qt::WA_WState_Visible, false); + } +} + +void QWidgetPrivate::show_helper() +{ + Q_Q(QWidget); + data.in_show = true; // qws optimization + // make sure we receive pending move and resize events + sendPendingMoveAndResizeEvents(); + + // become visible before showing all children + q->setAttribute(Qt::WA_WState_Visible); + + // finally show all children recursively + showChildren(false); + +#ifdef QT3_SUPPORT + if (q->parentWidget() && sendChildEvents) + QApplication::sendPostedEvents(q->parentWidget(), + QEvent::ChildInserted); +#endif + + + // popup handling: new popups and tools need to be raised, and + // existing popups must be closed. Also propagate the current + // windows's KeyboardFocusChange status. + if (q->isWindow()) { + if ((q->windowType() == Qt::Tool) || (q->windowType() == Qt::Popup) || q->windowType() == Qt::ToolTip) { + q->raise(); + if (q->parentWidget() && q->parentWidget()->window()->testAttribute(Qt::WA_KeyboardFocusChange)) + q->setAttribute(Qt::WA_KeyboardFocusChange); + } else { + while (QApplication::activePopupWidget()) { + if (!QApplication::activePopupWidget()->close()) + break; + } + } + } + + // Automatic embedding of child windows of widgets already embedded into + // QGraphicsProxyWidget when they are shown the first time. + bool isEmbedded = false; +#ifndef QT_NO_GRAPHICSVIEW + if (q->isWindow()) { + isEmbedded = q->graphicsProxyWidget() ? true : false; + if (!isEmbedded && !bypassGraphicsProxyWidget(q)) { + QGraphicsProxyWidget *ancestorProxy = nearestGraphicsProxyWidget(q->parentWidget()); + if (ancestorProxy) { + isEmbedded = true; + ancestorProxy->d_func()->embedSubWindow(q); + } + } + } +#else + Q_UNUSED(isEmbedded); +#endif + + // On Windows, show the popup now so that our own focus handling + // stores the correct old focus widget even if it's stolen in the + // showevent +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) + if (!isEmbedded && q->windowType() == Qt::Popup) + qApp->d_func()->openPopup(q); +#endif + + // send the show event before showing the window + QShowEvent showEvent; + QApplication::sendEvent(q, &showEvent); + + if (!isEmbedded && q->isModal() && q->isWindow()) + // QApplicationPrivate::enterModal *before* show, otherwise the initial + // stacking might be wrong + QApplicationPrivate::enterModal(q); + + + show_sys(); + +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN) + if (!isEmbedded && q->windowType() == Qt::Popup) + qApp->d_func()->openPopup(q); +#endif + +#ifndef QT_NO_ACCESSIBILITY + if (q->windowType() != Qt::ToolTip) // Tooltips are read aloud twice in MS narrator. + QAccessible::updateAccessibility(q, 0, QAccessible::ObjectShow); +#endif + + if (QApplicationPrivate::hidden_focus_widget == q) { + QApplicationPrivate::hidden_focus_widget = 0; + q->setFocus(Qt::OtherFocusReason); + } + + // Process events when showing a Qt::SplashScreen widget before the event loop + // is spinnning; otherwise it might not show up on particular platforms. + // This makes QSplashScreen behave the same on all platforms. + if (!qApp->d_func()->in_exec && q->windowType() == Qt::SplashScreen) + QApplication::processEvents(); + + data.in_show = false; // reset qws optimization +} + +/*! \fn void QWidget::hide() + + Hides the widget. This function is equivalent to + setVisible(false). + + + \note If you are working with QDialog or its subclasses and you invoke + the show() function after this function, the dialog will be displayed in + its original position. + + \sa hideEvent(), isHidden(), show(), setVisible(), isVisible(), close() +*/ + +/*!\internal + */ +void QWidgetPrivate::hide_helper() +{ + Q_Q(QWidget); + + bool isEmbedded = false; +#if !defined QT_NO_GRAPHICSVIEW + isEmbedded = q->isWindow() && !bypassGraphicsProxyWidget(q) && nearestGraphicsProxyWidget(q->parentWidget()) != 0; +#else + Q_UNUSED(isEmbedded); +#endif + + if (!isEmbedded && (q->windowType() == Qt::Popup)) + qApp->d_func()->closePopup(q); + + // Move test modal here. Otherwise, a modal dialog could get + // destroyed and we lose all access to its parent because we haven't + // left modality. (Eg. modal Progress Dialog) + if (!isEmbedded && q->isModal() && q->isWindow()) + QApplicationPrivate::leaveModal(q); + +#if defined(Q_WS_WIN) + if (q->isWindow() && !(q->windowType() == Qt::Popup) && q->parentWidget() + && !q->parentWidget()->isHidden() && q->isActiveWindow()) + q->parentWidget()->activateWindow(); // Activate parent +#endif + + q->setAttribute(Qt::WA_Mapped, false); + hide_sys(); + + bool wasVisible = q->testAttribute(Qt::WA_WState_Visible); + + if (wasVisible) { + q->setAttribute(Qt::WA_WState_Visible, false); + + } + + QHideEvent hideEvent; + QApplication::sendEvent(q, &hideEvent); + hideChildren(false); + + // next bit tries to move the focus if the focus widget is now + // hidden. + if (wasVisible) { +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) + qApp->d_func()->sendSyntheticEnterLeave(q); +#endif + + QWidget *fw = QApplication::focusWidget(); + while (fw && !fw->isWindow()) { + if (fw == q) { + q->focusNextPrevChild(true); + break; + } + fw = fw->parentWidget(); + } + } + + if (QWidgetBackingStore *bs = maybeBackingStore()) + bs->removeDirtyWidget(q); + +#ifndef QT_NO_ACCESSIBILITY + if (wasVisible) + QAccessible::updateAccessibility(q, 0, QAccessible::ObjectHide); +#endif +} + +/*! + \fn bool QWidget::isHidden() const + + Returns true if the widget is hidden, otherwise returns false. + + A hidden widget will only become visible when show() is called on + it. It will not be automatically shown when the parent is shown. + + To check visibility, use !isVisible() instead (notice the exclamation mark). + + isHidden() implies !isVisible(), but a widget can be not visible + and not hidden at the same time. This is the case for widgets that are children of + widgets that are not visible. + + + Widgets are hidden if: + \list + \o they were created as independent windows, + \o they were created as children of visible widgets, + \o hide() or setVisible(false) was called. + \endlist +*/ + + +void QWidget::setVisible(bool visible) +{ + if (visible) { // show + if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) + return; + + Q_D(QWidget); + + // Designer uses a trick to make grabWidget work without showing + if (!isWindow() && parentWidget() && parentWidget()->isVisible() + && !parentWidget()->testAttribute(Qt::WA_WState_Created)) + parentWidget()->window()->d_func()->createRecursively(); + + //we have to at least create toplevels before applyX11SpecificCommandLineArguments + //but not children of non-visible parents + QWidget *pw = parentWidget(); + if (!testAttribute(Qt::WA_WState_Created) + && (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { + create(); + } + +#if defined(Q_WS_X11) + if (windowType() == Qt::Window) + QApplicationPrivate::applyX11SpecificCommandLineArguments(this); +#elif defined(Q_WS_QWS) + if (windowType() == Qt::Window) + QApplicationPrivate::applyQWSSpecificCommandLineArguments(this); +#endif + + bool wasResized = testAttribute(Qt::WA_Resized); + Qt::WindowStates initialWindowState = windowState(); + + // polish if necessary + ensurePolished(); + + // remember that show was called explicitly + setAttribute(Qt::WA_WState_ExplicitShowHide); + // whether we need to inform the parent widget immediately + bool needUpdateGeometry = !isWindow() && testAttribute(Qt::WA_WState_Hidden); + // we are no longer hidden + setAttribute(Qt::WA_WState_Hidden, false); + + if (needUpdateGeometry) + d->updateGeometry_helper(true); + +#ifdef QT3_SUPPORT + QApplication::sendPostedEvents(this, QEvent::ChildInserted); +#endif + // activate our layout before we and our children become visible + if (d->layout) + d->layout->activate(); + + if (!isWindow()) { + QWidget *parent = parentWidget(); + while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) { + parent->d_func()->layout->activate(); + if (parent->isWindow()) + break; + parent = parent->parentWidget(); + } + if (parent) + parent->d_func()->setDirtyOpaqueRegion(); + } + + // adjust size if necessary + if (!wasResized + && (isWindow() || !parentWidget()->d_func()->layout)) { + if (isWindow()) { + adjustSize(); + if (windowState() != initialWindowState) + setWindowState(initialWindowState); + } else { + adjustSize(); + } + setAttribute(Qt::WA_Resized, false); + } + + setAttribute(Qt::WA_KeyboardFocusChange, false); + + if (isWindow() || parentWidget()->isVisible()) { + // remove posted quit events when showing a new window + QCoreApplication::removePostedEvents(qApp, QEvent::Quit); + + d->show_helper(); + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) + qApp->d_func()->sendSyntheticEnterLeave(this); +#endif + } + + QEvent showToParentEvent(QEvent::ShowToParent); + QApplication::sendEvent(this, &showToParentEvent); + } else { // hide + if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) + return; +#if defined(Q_WS_WIN) + // reset WS_DISABLED style in a Blocked window + if(isWindow() && testAttribute(Qt::WA_WState_Created) + && QApplicationPrivate::isBlockedByModal(this)) + { + LONG dwStyle = GetWindowLong(winId(), GWL_STYLE); + dwStyle &= ~WS_DISABLED; + SetWindowLong(winId(), GWL_STYLE, dwStyle); + } +#endif + if (QApplicationPrivate::hidden_focus_widget == this) + QApplicationPrivate::hidden_focus_widget = 0; + + Q_D(QWidget); + + // hw: The test on getOpaqueRegion() needs to be more intelligent + // currently it doesn't work if the widget is hidden (the region will + // be clipped). The real check should be testing the cached region + // (and dirty flag) directly. + if (!isWindow() && parentWidget()) // && !d->getOpaqueRegion().isEmpty()) + parentWidget()->d_func()->setDirtyOpaqueRegion(); + + setAttribute(Qt::WA_WState_Hidden); + setAttribute(Qt::WA_WState_ExplicitShowHide); + if (testAttribute(Qt::WA_WState_Created)) + d->hide_helper(); + + // invalidate layout similar to updateGeometry() + if (!isWindow() && parentWidget()) { + if (parentWidget()->d_func()->layout) + parentWidget()->d_func()->layout->invalidate(); + else if (parentWidget()->isVisible()) + QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest)); + } + + QEvent hideToParentEvent(QEvent::HideToParent); + QApplication::sendEvent(this, &hideToParentEvent); + } +} + +/*!\fn void QWidget::setHidden(bool hidden) + + Convenience function, equivalent to setVisible(!\a hidden). +*/ + +/*!\fn void QWidget::setShown(bool shown) + + Use setVisible(\a shown) instead. +*/ + + +void QWidgetPrivate::_q_showIfNotHidden() +{ + Q_Q(QWidget); + if ( !(q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide)) ) + q->setVisible(true); +} + +void QWidgetPrivate::showChildren(bool spontaneous) +{ + QList childList = children; + for (int i = 0; i < childList.size(); ++i) { + QWidget *widget = qobject_cast(childList.at(i)); + if (!widget + || widget->isWindow() + || widget->testAttribute(Qt::WA_WState_Hidden)) + continue; + if (spontaneous) { + widget->setAttribute(Qt::WA_Mapped); + widget->d_func()->showChildren(true); + QShowEvent e; + QApplication::sendSpontaneousEvent(widget, &e); + } else { + if (widget->testAttribute(Qt::WA_WState_ExplicitShowHide)) + widget->d_func()->show_recursive(); + else + widget->show(); + } + } +} + +void QWidgetPrivate::hideChildren(bool spontaneous) +{ + QList childList = children; + for (int i = 0; i < childList.size(); ++i) { + QWidget *widget = qobject_cast(childList.at(i)); + if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden)) + continue; +#ifdef QT_MAC_USE_COCOA + // Before doing anything we need to make sure that we don't leave anything in a non-consistent state. + // When hiding a widget we need to make sure that no mouse_down events are active, because + // the mouse_up event will never be received by a hidden widget or one of its descendants. + // The solution is simple, before going through with this we check if there are any mouse_down events in + // progress, if so we check if it is related to this widget or not. If so, we just reset the mouse_down and + // then we continue. + // In X11 and Windows we send a mouse_release event, however we don't do that here because we were already + // ignoring that from before. I.e. Carbon did not send the mouse release event, so we will not send the + // mouse release event. There are two ways to interpret this: + // 1. If we don't send the mouse release event, the widget might get into an inconsistent state, i.e. it + // might be waiting for a release event that will never arrive. + // 2. If we send the mouse release event, then the widget might decide to trigger an action that is not + // supposed to trigger because it is not visible. + if(widget == qt_button_down) + qt_button_down = 0; +#endif // QT_MAC_USE_COCOA + if (spontaneous) + widget->setAttribute(Qt::WA_Mapped, false); + else + widget->setAttribute(Qt::WA_WState_Visible, false); + widget->d_func()->hideChildren(spontaneous); + QHideEvent e; + if (spontaneous) { + QApplication::sendSpontaneousEvent(widget, &e); + } else { + QApplication::sendEvent(widget, &e); + if (widget->internalWinId() + && widget->testAttribute(Qt::WA_DontCreateNativeAncestors)) { + // hide_sys() on an ancestor won't have any affect on this + // widget, so it needs an explicit hide_sys() of its own + widget->d_func()->hide_sys(); + } + } +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) + qApp->d_func()->sendSyntheticEnterLeave(widget); +#endif +#ifndef QT_NO_ACCESSIBILITY + if (!spontaneous) + QAccessible::updateAccessibility(widget, 0, QAccessible::ObjectHide); +#endif + } +} + +bool QWidgetPrivate::close_helper(CloseMode mode) +{ + if (data.is_closing) + return true; + + Q_Q(QWidget); + data.is_closing = 1; + + QPointer that = q; + QPointer parentWidget = q->parentWidget(); + +#ifdef QT3_SUPPORT + bool isMain = (QApplicationPrivate::main_widget == q); +#endif + bool quitOnClose = q->testAttribute(Qt::WA_QuitOnClose); + if (mode != CloseNoEvent) { + QCloseEvent e; + if (mode == CloseWithSpontaneousEvent) + QApplication::sendSpontaneousEvent(q, &e); + else + QApplication::sendEvent(q, &e); + if (!that.isNull() && !e.isAccepted()) { + data.is_closing = 0; + return false; + } + } + + if (!that.isNull() && !q->isHidden()) + q->hide(); + +#ifdef QT3_SUPPORT + if (isMain) + QApplication::quit(); +#endif + // Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent + quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible()); + + if (quitOnClose) { + /* if there is no non-withdrawn primary window left (except + the ones without QuitOnClose), we emit the lastWindowClosed + signal */ + QWidgetList list = QApplication::topLevelWidgets(); + bool lastWindowClosed = true; + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + if (!w->isVisible() || w->parentWidget() || !w->testAttribute(Qt::WA_QuitOnClose)) + continue; + lastWindowClosed = false; + break; + } + if (lastWindowClosed) + QApplicationPrivate::emitLastWindowClosed(); + } + + if (!that.isNull()) { + data.is_closing = 0; + if (q->testAttribute(Qt::WA_DeleteOnClose)) { + q->setAttribute(Qt::WA_DeleteOnClose, false); + q->deleteLater(); + } + } + return true; +} + + +/*! + Closes this widget. Returns true if the widget was closed; + otherwise returns false. + + First it sends the widget a QCloseEvent. The widget is \link + hide() hidden\endlink if it \link QCloseEvent::accept() + accepts\endlink the close event. If it \link QCloseEvent::ignore() + ignores\endlink the event, nothing happens. The default + implementation of QWidget::closeEvent() accepts the close event. + + If the widget has the Qt::WA_DeleteOnClose flag, the widget + is also deleted. A close events is delivered to the widget no + matter if the widget is visible or not. + + The \l QApplication::lastWindowClosed() signal is emitted when the + last visible primary window (i.e. window with no parent) with the + Qt::WA_QuitOnClose attribute set is closed. By default this + attribute is set for all widgets except transient windows such as + splash screens, tool windows, and popup menus. + +*/ + +bool QWidget::close() +{ + return d_func()->close_helper(QWidgetPrivate::CloseWithEvent); +} + +/*! + \property QWidget::visible + \brief whether the widget is visible + + Calling setVisible(true) or show() sets the widget to visible + status if all its parent widgets up to the window are visible. If + an ancestor is not visible, the widget won't become visible until + all its ancestors are shown. If its size or position has changed, + Qt guarantees that a widget gets move and resize events just + before it is shown. If the widget has not been resized yet, Qt + will adjust the widget's size to a useful default using + adjustSize(). + + Calling setVisible(false) or hide() hides a widget explicitly. An + explicitly hidden widget will never become visible, even if all + its ancestors become visible, unless you show it. + + A widget receives show and hide events when its visibility status + changes. Between a hide and a show event, there is no need to + waste CPU cycles preparing or displaying information to the user. + A video application, for example, might simply stop generating new + frames. + + A widget that happens to be obscured by other windows on the + screen is considered to be visible. The same applies to iconified + windows and windows that exist on another virtual + desktop (on platforms that support this concept). A widget + receives spontaneous show and hide events when its mapping status + is changed by the window system, e.g. a spontaneous hide event + when the user minimizes the window, and a spontaneous show event + when the window is restored again. + + You almost never have to reimplement the setVisible() function. If + you need to change some settings before a widget is shown, use + showEvent() instead. If you need to do some delayed initialization + use the Polish event delivered to the event() function. + + \sa show(), hide(), isHidden(), isVisibleTo(), isMinimized(), + showEvent(), hideEvent() +*/ + + +/*! + Returns true if this widget would become visible if \a ancestor is + shown; otherwise returns false. + + The true case occurs if neither the widget itself nor any parent + up to but excluding \a ancestor has been explicitly hidden. + + This function will still return true if the widget is obscured by + other windows on the screen, but could be physically visible if it + or they were to be moved. + + isVisibleTo(0) is identical to isVisible(). + + \sa show() hide() isVisible() +*/ + +bool QWidget::isVisibleTo(QWidget* ancestor) const +{ + if (!ancestor) + return isVisible(); + const QWidget * w = this; + while (!w->isHidden() + && !w->isWindow() + && w->parentWidget() + && w->parentWidget() != ancestor) + w = w->parentWidget(); + return !w->isHidden(); +} + +#ifdef QT3_SUPPORT +/*! + Use visibleRegion() instead. +*/ +QRect QWidget::visibleRect() const +{ + return d_func()->clipRect(); +} +#endif + +/*! + Returns the unobscured region where paint events can occur. + + For visible widgets, this is an approximation of the area not + covered by other widgets; otherwise, this is an empty region. + + The repaint() function calls this function if necessary, so in + general you do not need to call it. + +*/ +QRegion QWidget::visibleRegion() const +{ + Q_D(const QWidget); + + QRect clipRect = d->clipRect(); + if (clipRect.isEmpty()) + return QRegion(); + QRegion r(clipRect); + d->subtractOpaqueChildren(r, clipRect); + d->subtractOpaqueSiblings(r); +#ifdef Q_WS_QWS + const QWSWindowSurface *surface = static_cast(windowSurface()); + if (surface) { + const QPoint offset = mapTo(surface->window(), QPoint()); + r &= surface->clipRegion().translated(-offset); + } +#endif + return r; +} + + +QSize QWidgetPrivate::adjustedSize() const +{ + Q_Q(const QWidget); + + QSize s = q->sizeHint(); + + if (q->isWindow()) { + Qt::Orientations exp; + if (layout) { + if (layout->hasHeightForWidth()) + s.setHeight(layout->totalHeightForWidth(s.width())); + exp = layout->expandingDirections(); + } else + { + if (q->sizePolicy().hasHeightForWidth()) + s.setHeight(q->heightForWidth(s.width())); + exp = q->sizePolicy().expandingDirections(); + } + if (exp & Qt::Horizontal) + s.setWidth(qMax(s.width(), 200)); + if (exp & Qt::Vertical) + s.setHeight(qMax(s.height(), 100)); +#if defined(Q_WS_X11) + QRect screen = QApplication::desktop()->screenGeometry(q->x11Info().screen()); +#else // all others + QRect screen = QApplication::desktop()->screenGeometry(q->pos()); +#endif +#if defined (Q_WS_WINCE) || defined (Q_OS_SYMBIAN) + s.setWidth(qMin(s.width(), screen.width())); + s.setHeight(qMin(s.height(), screen.height())); +#else + s.setWidth(qMin(s.width(), screen.width()*2/3)); + s.setHeight(qMin(s.height(), screen.height()*2/3)); +#endif + if (QTLWExtra *extra = maybeTopData()) + extra->sizeAdjusted = true; + } + + if (!s.isValid()) { + QRect r = q->childrenRect(); // get children rectangle + if (r.isNull()) + return s; + s = r.size() + QSize(2 * r.x(), 2 * r.y()); + } + + return s; +} + +/*! + Adjusts the size of the widget to fit its contents. + + This function uses sizeHint() if it is valid, i.e., the size hint's width + and height are \>= 0. Otherwise, it sets the size to the children + rectangle that covers all child widgets (the union of all child widget + rectangles). + + For windows, the screen size is also taken into account. If the sizeHint() + is less than (200, 100) and the size policy is \l{QSizePolicy::Expanding} + {expanding}, the window will be at least (200, 100). The maximum size of + a window is 2/3 of the screen's width and height. + + \sa sizeHint(), childrenRect() +*/ + +void QWidget::adjustSize() +{ + Q_D(QWidget); + ensurePolished(); + QSize s = d->adjustedSize(); + + if (d->layout) + d->layout->activate(); + + if (s.isValid()) + resize(s); +} + + +/*! + \property QWidget::sizeHint + \brief the recommended size for the widget + + If the value of this property is an invalid size, no size is + recommended. + + The default implementation of sizeHint() returns an invalid size + if there is no layout for this widget, and returns the layout's + preferred size otherwise. + + \sa QSize::isValid(), minimumSizeHint(), sizePolicy(), + setMinimumSize(), updateGeometry() +*/ + +QSize QWidget::sizeHint() const +{ + Q_D(const QWidget); + if (d->layout) + return d->layout->totalSizeHint(); + return QSize(-1, -1); +} + +/*! + \property QWidget::minimumSizeHint + \brief the recommended minimum size for the widget + + If the value of this property is an invalid size, no minimum size + is recommended. + + The default implementation of minimumSizeHint() returns an invalid + size if there is no layout for this widget, and returns the + layout's minimum size otherwise. Most built-in widgets reimplement + minimumSizeHint(). + + \l QLayout will never resize a widget to a size smaller than the + minimum size hint unless minimumSize() is set or the size policy is + set to QSizePolicy::Ignore. If minimumSize() is set, the minimum + size hint will be ignored. + + \sa QSize::isValid(), resize(), setMinimumSize(), sizePolicy() +*/ +QSize QWidget::minimumSizeHint() const +{ + Q_D(const QWidget); + if (d->layout) + return d->layout->totalMinimumSize(); + return QSize(-1, -1); +} + + +/*! + \fn QWidget *QWidget::parentWidget() const + + Returns the parent of this widget, or 0 if it does not have any + parent widget. +*/ + + +/*! + Returns true if this widget is a parent, (or grandparent and so on + to any level), of the given \a child, and both widgets are within + the same window; otherwise returns false. +*/ + +bool QWidget::isAncestorOf(const QWidget *child) const +{ + while (child) { + if (child == this) + return true; + if (child->isWindow()) + return false; + child = child->parentWidget(); + } + return false; +} + +#if defined(Q_WS_WIN) +inline void setDisabledStyle(QWidget *w, bool setStyle) +{ + // set/reset WS_DISABLED style. + if(w && w->isWindow() && w->isVisible() && w->isEnabled()) { + LONG dwStyle = GetWindowLong(w->winId(), GWL_STYLE); + LONG newStyle = dwStyle; + if (setStyle) + newStyle |= WS_DISABLED; + else + newStyle &= ~WS_DISABLED; + if (newStyle != dwStyle) { + SetWindowLong(w->winId(), GWL_STYLE, newStyle); + // we might need to repaint in some situations (eg. menu) + w->repaint(); + } + } +} +#endif + +/***************************************************************************** + QWidget event handling + *****************************************************************************/ + +/*! + This is the main event handler; it handles event \a event. You can + reimplement this function in a subclass, but we recommend using + one of the specialized event handlers instead. + + Key press and release events are treated differently from other + events. event() checks for Tab and Shift+Tab and tries to move the + focus appropriately. If there is no widget to move the focus to + (or the key press is not Tab or Shift+Tab), event() calls + keyPressEvent(). + + Mouse and tablet event handling is also slightly special: only + when the widget is \l enabled, event() will call the specialized + handlers such as mousePressEvent(); otherwise it will discard the + event. + + This function returns true if the event was recognized, otherwise + it returns false. If the recognized event was accepted (see \l + QEvent::accepted), any further processing such as event + propagation to the parent widget stops. + + \sa closeEvent(), focusInEvent(), focusOutEvent(), enterEvent(), + keyPressEvent(), keyReleaseEvent(), leaveEvent(), + mouseDoubleClickEvent(), mouseMoveEvent(), mousePressEvent(), + mouseReleaseEvent(), moveEvent(), paintEvent(), resizeEvent(), + QObject::event(), QObject::timerEvent() +*/ + +bool QWidget::event(QEvent *event) +{ + Q_D(QWidget); + + // ignore mouse events when disabled + if (!isEnabled()) { + switch(event->type()) { + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::TabletMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::ContextMenu: +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: +#endif + return false; + default: + break; + } + } + switch (event->type()) { + case QEvent::MouseMove: + mouseMoveEvent((QMouseEvent*)event); + break; + + case QEvent::MouseButtonPress: + // Don't reset input context here. Whether reset or not is + // a responsibility of input method. reset() will be + // called by mouseHandler() of input method if necessary + // via mousePressEvent() of text widgets. +#if 0 + resetInputContext(); +#endif + mousePressEvent((QMouseEvent*)event); + break; + + case QEvent::MouseButtonRelease: + mouseReleaseEvent((QMouseEvent*)event); + break; + + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent((QMouseEvent*)event); + break; +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: + wheelEvent((QWheelEvent*)event); + break; +#endif +#ifndef QT_NO_TABLETEVENT + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + tabletEvent((QTabletEvent*)event); + break; +#endif +#ifdef QT3_SUPPORT + case QEvent::Accel: + event->ignore(); + return false; +#endif + case QEvent::KeyPress: { + QKeyEvent *k = (QKeyEvent *)event; + bool res = false; + if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? + if (k->key() == Qt::Key_Backtab + || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) + res = focusNextPrevChild(false); + else if (k->key() == Qt::Key_Tab) + res = focusNextPrevChild(true); + if (res) + break; + } + keyPressEvent(k); +#ifdef QT_KEYPAD_NAVIGATION + if (!k->isAccepted() && QApplication::keypadNavigationEnabled() + && !(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::ShiftModifier))) { + if (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder) { + if (k->key() == Qt::Key_Up) + res = focusNextPrevChild(false); + else if (k->key() == Qt::Key_Down) + res = focusNextPrevChild(true); + } else if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { + if (k->key() == Qt::Key_Up) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionNorth); + else if (k->key() == Qt::Key_Right) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionEast); + else if (k->key() == Qt::Key_Down) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionSouth); + else if (k->key() == Qt::Key_Left) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionWest); + } + if (res) { + k->accept(); + break; + } + } +#endif +#ifndef QT_NO_WHATSTHIS + if (!k->isAccepted() + && k->modifiers() & Qt::ShiftModifier && k->key() == Qt::Key_F1 + && d->whatsThis.size()) { + QWhatsThis::showText(mapToGlobal(inputMethodQuery(Qt::ImMicroFocus).toRect().center()), d->whatsThis, this); + k->accept(); + } +#endif + } + break; + + case QEvent::KeyRelease: + keyReleaseEvent((QKeyEvent*)event); + // fall through + case QEvent::ShortcutOverride: + break; + + case QEvent::InputMethod: + inputMethodEvent((QInputMethodEvent *) event); + break; + + case QEvent::PolishRequest: + ensurePolished(); + break; + + case QEvent::Polish: { + style()->polish(this); + setAttribute(Qt::WA_WState_Polished); + if (!QApplication::font(this).isCopyOf(QApplication::font())) + d->resolveFont(); + if (!QApplication::palette(this).isCopyOf(QApplication::palette())) + d->resolvePalette(); +#ifdef QT3_SUPPORT + if(d->sendChildEvents) + QApplication::sendPostedEvents(this, QEvent::ChildInserted); +#endif + } + break; + + case QEvent::ApplicationWindowIconChange: + if (isWindow() && !testAttribute(Qt::WA_SetWindowIcon)) { + d->setWindowIcon_sys(); + d->setWindowIcon_helper(); + } + break; + case QEvent::FocusIn: +#ifdef QT_SOFTKEYS_ENABLED + QSoftKeyManager::updateSoftKeys(); +#endif + focusInEvent((QFocusEvent*)event); + break; + + case QEvent::FocusOut: + focusOutEvent((QFocusEvent*)event); + break; + + case QEvent::Enter: +#ifndef QT_NO_STATUSTIP + if (d->statusTip.size()) { + QStatusTipEvent tip(d->statusTip); + QApplication::sendEvent(const_cast(this), &tip); + } +#endif + enterEvent(event); + break; + + case QEvent::Leave: +#ifndef QT_NO_STATUSTIP + if (d->statusTip.size()) { + QString empty; + QStatusTipEvent tip(empty); + QApplication::sendEvent(const_cast(this), &tip); + } +#endif + leaveEvent(event); + break; + + case QEvent::HoverEnter: + case QEvent::HoverLeave: + update(); + break; + + case QEvent::Paint: + // At this point the event has to be delivered, regardless + // whether the widget isVisible() or not because it + // already went through the filters + paintEvent((QPaintEvent*)event); + break; + + case QEvent::Move: + moveEvent((QMoveEvent*)event); + break; + + case QEvent::Resize: + resizeEvent((QResizeEvent*)event); + break; + + case QEvent::Close: + closeEvent((QCloseEvent *)event); + break; + +#ifndef QT_NO_CONTEXTMENU + case QEvent::ContextMenu: + switch (data->context_menu_policy) { + case Qt::PreventContextMenu: + break; + case Qt::DefaultContextMenu: + contextMenuEvent(static_cast(event)); + break; + case Qt::CustomContextMenu: + emit customContextMenuRequested(static_cast(event)->pos()); + break; +#ifndef QT_NO_MENU + case Qt::ActionsContextMenu: + if (d->actions.count()) { + QMenu::exec(d->actions, static_cast(event)->globalPos(), + 0, this); + break; + } + // fall through +#endif + default: + event->ignore(); + break; + } + break; +#endif // QT_NO_CONTEXTMENU + +#ifndef QT_NO_DRAGANDDROP + case QEvent::Drop: + dropEvent((QDropEvent*) event); + break; + + case QEvent::DragEnter: + dragEnterEvent((QDragEnterEvent*) event); + break; + + case QEvent::DragMove: + dragMoveEvent((QDragMoveEvent*) event); + break; + + case QEvent::DragLeave: + dragLeaveEvent((QDragLeaveEvent*) event); + break; +#endif + + case QEvent::Show: + showEvent((QShowEvent*) event); + break; + + case QEvent::Hide: + hideEvent((QHideEvent*) event); + break; + + case QEvent::ShowWindowRequest: + if (!isHidden()) + d->show_sys(); + break; + + case QEvent::ApplicationFontChange: + d->resolveFont(); + break; + case QEvent::ApplicationPaletteChange: + if (!(windowType() == Qt::Desktop)) + d->resolvePalette(); + break; + + case QEvent::ToolBarChange: + case QEvent::ActivationChange: + case QEvent::EnabledChange: + case QEvent::FontChange: + case QEvent::StyleChange: + case QEvent::PaletteChange: + case QEvent::WindowTitleChange: + case QEvent::IconTextChange: + case QEvent::ModifiedChange: + case QEvent::MouseTrackingChange: + case QEvent::ParentChange: + case QEvent::WindowStateChange: + case QEvent::LocaleChange: + case QEvent::MacSizeChange: + case QEvent::ContentsRectChange: + changeEvent(event); + break; + + case QEvent::WindowActivate: + case QEvent::WindowDeactivate: { +#ifdef QT3_SUPPORT + windowActivationChange(event->type() != QEvent::WindowActivate); +#endif + if (isVisible() && !palette().isEqual(QPalette::Active, QPalette::Inactive)) + update(); + QList childList = d->children; + for (int i = 0; i < childList.size(); ++i) { + QWidget *w = qobject_cast(childList.at(i)); + if (w && w->isVisible() && !w->isWindow()) + QApplication::sendEvent(w, event); + } + +#ifdef QT_SOFTKEYS_ENABLED + if (isWindow()) + QSoftKeyManager::updateSoftKeys(); +#endif + + break; } + + case QEvent::LanguageChange: +#ifdef QT3_SUPPORT + languageChange(); +#endif + changeEvent(event); + { + QList childList = d->children; + for (int i = 0; i < childList.size(); ++i) { + QObject *o = childList.at(i); + if (o) + QApplication::sendEvent(o, event); + } + } + update(); + break; + + case QEvent::ApplicationLayoutDirectionChange: + d->resolveLayoutDirection(); + break; + + case QEvent::LayoutDirectionChange: + if (d->layout) + d->layout->invalidate(); + update(); + changeEvent(event); + break; + case QEvent::UpdateRequest: + d->syncBackingStore(); + break; + case QEvent::UpdateLater: + update(static_cast(event)->region()); + break; + + case QEvent::WindowBlocked: + case QEvent::WindowUnblocked: + { + QList childList = d->children; + for (int i = 0; i < childList.size(); ++i) { + QObject *o = childList.at(i); + if (o && o != QApplication::activeModalWidget()) { + if (qobject_cast(o) && static_cast(o)->isWindow()) { + // do not forward the event to child windows, + // QApplication does this for us + continue; + } + QApplication::sendEvent(o, event); + } + } +#if defined(Q_WS_WIN) + setDisabledStyle(this, (event->type() == QEvent::WindowBlocked)); +#endif + } + break; +#ifndef QT_NO_TOOLTIP + case QEvent::ToolTip: + if (!d->toolTip.isEmpty()) + QToolTip::showText(static_cast(event)->globalPos(), d->toolTip, this); + else + event->ignore(); + break; +#endif +#ifndef QT_NO_WHATSTHIS + case QEvent::WhatsThis: + if (d->whatsThis.size()) + QWhatsThis::showText(static_cast(event)->globalPos(), d->whatsThis, this); + else + event->ignore(); + break; + case QEvent::QueryWhatsThis: + if (d->whatsThis.isEmpty()) + event->ignore(); + break; +#endif +#ifndef QT_NO_ACCESSIBILITY + case QEvent::AccessibilityDescription: + case QEvent::AccessibilityHelp: { + QAccessibleEvent *ev = static_cast(event); + if (ev->child()) + return false; + switch (ev->type()) { +#ifndef QT_NO_TOOLTIP + case QEvent::AccessibilityDescription: + ev->setValue(d->toolTip); + break; +#endif +#ifndef QT_NO_WHATSTHIS + case QEvent::AccessibilityHelp: + ev->setValue(d->whatsThis); + break; +#endif + default: + return false; + } + break; } +#endif + case QEvent::EmbeddingControl: + d->topData()->frameStrut.setCoords(0 ,0, 0, 0); + data->fstrut_dirty = false; +#if defined(Q_WS_WIN) || defined(Q_WS_X11) + d->topData()->embedded = 1; +#endif + break; +#ifndef QT_NO_ACTION + case QEvent::ActionAdded: + case QEvent::ActionRemoved: + case QEvent::ActionChanged: +#ifdef QT_SOFTKEYS_ENABLED + QSoftKeyManager::updateSoftKeys(); +#endif + actionEvent((QActionEvent*)event); + break; +#endif + + case QEvent::KeyboardLayoutChange: + { + changeEvent(event); + + // inform children of the change + QList childList = d->children; + for (int i = 0; i < childList.size(); ++i) { + QWidget *w = qobject_cast(childList.at(i)); + if (w && w->isVisible() && !w->isWindow()) + QApplication::sendEvent(w, event); + } + break; + } +#ifdef Q_WS_MAC + case QEvent::MacGLWindowChange: + d->needWindowChange = false; + break; +#endif + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { +#ifndef Q_WS_MAC + QTouchEvent *touchEvent = static_cast(event); + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().first(); + if (touchPoint.isPrimary() || touchEvent->deviceType() == QTouchEvent::TouchPad) + break; + + // fake a mouse event! + QEvent::Type eventType = QEvent::None; + switch (touchEvent->type()) { + case QEvent::TouchBegin: + eventType = QEvent::MouseButtonPress; + break; + case QEvent::TouchUpdate: + eventType = QEvent::MouseMove; + break; + case QEvent::TouchEnd: + eventType = QEvent::MouseButtonRelease; + break; + default: + Q_ASSERT(!true); + break; + } + if (eventType == QEvent::None) + break; + + QMouseEvent mouseEvent(eventType, + touchPoint.pos().toPoint(), + touchPoint.screenPos().toPoint(), + Qt::LeftButton, + Qt::LeftButton, + touchEvent->modifiers()); + (void) QApplication::sendEvent(this, &mouseEvent); +#endif // Q_WS_MAC + break; + } +#ifndef QT_NO_GESTURES + case QEvent::Gesture: + event->ignore(); + break; +#endif +#ifndef QT_NO_PROPERTIES + case QEvent::DynamicPropertyChange: { + const QByteArray &propName = static_cast(event)->propertyName(); + if (!qstrncmp(propName, "_q_customDpi", 12) && propName.length() == 13) { + uint value = property(propName.constData()).toUInt(); + if (!d->extra) + d->createExtra(); + const char axis = propName.at(12); + if (axis == 'X') + d->extra->customDpiX = value; + else if (axis == 'Y') + d->extra->customDpiY = value; + d->updateFont(d->data.fnt); + } + // fall through + } +#endif + default: + return QObject::event(event); + } + return true; +} + +/*! + This event handler can be reimplemented to handle state changes. + + The state being changed in this event can be retrieved through the \a event + supplied. + + Change events include: QEvent::ToolBarChange, + QEvent::ActivationChange, QEvent::EnabledChange, QEvent::FontChange, + QEvent::StyleChange, QEvent::PaletteChange, + QEvent::WindowTitleChange, QEvent::IconTextChange, + QEvent::ModifiedChange, QEvent::MouseTrackingChange, + QEvent::ParentChange, QEvent::WindowStateChange, + QEvent::LanguageChange, QEvent::LocaleChange, + QEvent::LayoutDirectionChange. + +*/ +void QWidget::changeEvent(QEvent * event) +{ + switch(event->type()) { + case QEvent::EnabledChange: + update(); +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(this, 0, QAccessible::StateChanged); +#endif + break; + + case QEvent::FontChange: + case QEvent::StyleChange: { + Q_D(QWidget); + update(); + updateGeometry(); + if (d->layout) + d->layout->invalidate(); +#ifdef Q_WS_QWS + if (isWindow()) + d->data.fstrut_dirty = true; +#endif + break; + } + + case QEvent::PaletteChange: + update(); + break; + +#ifdef Q_WS_MAC + case QEvent::MacSizeChange: + updateGeometry(); + break; + case QEvent::ToolTipChange: + case QEvent::MouseTrackingChange: + qt_mac_update_mouseTracking(this); + break; +#endif + + default: + break; + } +} + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive mouse move events for the widget. + + If mouse tracking is switched off, mouse move events only occur if + a mouse button is pressed while the mouse is being moved. If mouse + tracking is switched on, mouse move events occur even if no mouse + button is pressed. + + QMouseEvent::pos() reports the position of the mouse cursor, + relative to this widget. For press and release events, the + position is usually the same as the position of the last mouse + move event, but it might be different if the user's hand shakes. + This is a feature of the underlying window system, not Qt. + + If you want to show a tooltip immediately, while the mouse is + moving (e.g., to get the mouse coordinates with QMouseEvent::pos() + and show them as a tooltip), you must first enable mouse tracking + as described above. Then, to ensure that the tooltip is updated + immediately, you must call QToolTip::showText() instead of + setToolTip() in your implementation of mouseMoveEvent(). + + \sa setMouseTracking(), mousePressEvent(), mouseReleaseEvent(), + mouseDoubleClickEvent(), event(), QMouseEvent, {Scribble Example} +*/ + +void QWidget::mouseMoveEvent(QMouseEvent *event) +{ + event->ignore(); +} + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive mouse press events for the widget. + + If you create new widgets in the mousePressEvent() the + mouseReleaseEvent() may not end up where you expect, depending on + the underlying window system (or X11 window manager), the widgets' + location and maybe more. + + The default implementation implements the closing of popup widgets + when you click outside the window. For other widget types it does + nothing. + + \sa mouseReleaseEvent(), mouseDoubleClickEvent(), + mouseMoveEvent(), event(), QMouseEvent, {Scribble Example} +*/ + +void QWidget::mousePressEvent(QMouseEvent *event) +{ + event->ignore(); + if ((windowType() == Qt::Popup)) { + event->accept(); + QWidget* w; + while ((w = QApplication::activePopupWidget()) && w != this){ + w->close(); + if (QApplication::activePopupWidget() == w) // widget does not want to disappear + w->hide(); // hide at least + } + if (!rect().contains(event->pos())){ + close(); + } + } +} + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive mouse release events for the widget. + + \sa mousePressEvent(), mouseDoubleClickEvent(), + mouseMoveEvent(), event(), QMouseEvent, {Scribble Example} +*/ + +void QWidget::mouseReleaseEvent(QMouseEvent *event) +{ + event->ignore(); +} + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive mouse double click events for the widget. + + The default implementation generates a normal mouse press event. + + \note The widget will also receive mouse press and mouse release + events in addition to the double click event. It is up to the + developer to ensure that the application interprets these events + correctly. + + \sa mousePressEvent(), mouseReleaseEvent() mouseMoveEvent(), + event(), QMouseEvent +*/ + +void QWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + mousePressEvent(event); // try mouse press event +} + +#ifndef QT_NO_WHEELEVENT +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive wheel events for the widget. + + If you reimplement this handler, it is very important that you + \link QWheelEvent ignore()\endlink the event if you do not handle + it, so that the widget's parent can interpret it. + + The default implementation ignores the event. + + \sa QWheelEvent::ignore(), QWheelEvent::accept(), event(), + QWheelEvent +*/ + +void QWidget::wheelEvent(QWheelEvent *event) +{ + event->ignore(); +} +#endif // QT_NO_WHEELEVENT + +#ifndef QT_NO_TABLETEVENT +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive tablet events for the widget. + + If you reimplement this handler, it is very important that you + \link QTabletEvent ignore()\endlink the event if you do not handle + it, so that the widget's parent can interpret it. + + The default implementation ignores the event. + + \sa QTabletEvent::ignore(), QTabletEvent::accept(), event(), + QTabletEvent +*/ + +void QWidget::tabletEvent(QTabletEvent *event) +{ + event->ignore(); +} +#endif // QT_NO_TABLETEVENT + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive key press events for the widget. + + A widget must call setFocusPolicy() to accept focus initially and + have focus in order to receive a key press event. + + If you reimplement this handler, it is very important that you + call the base class implementation if you do not act upon the key. + + The default implementation closes popup widgets if the user + presses Esc. Otherwise the event is ignored, so that the widget's + parent can interpret it. + + Note that QKeyEvent starts with isAccepted() == true, so you do not + need to call QKeyEvent::accept() - just do not call the base class + implementation if you act upon the key. + + \sa keyReleaseEvent(), setFocusPolicy(), + focusInEvent(), focusOutEvent(), event(), QKeyEvent, {Tetrix Example} +*/ + +void QWidget::keyPressEvent(QKeyEvent *event) +{ + if ((windowType() == Qt::Popup) && event->key() == Qt::Key_Escape) { + event->accept(); + close(); + } else { + event->ignore(); + } +} + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive key release events for the widget. + + A widget must \link setFocusPolicy() accept focus\endlink + initially and \link hasFocus() have focus\endlink in order to + receive a key release event. + + If you reimplement this handler, it is very important that you + call the base class implementation if you do not act upon the key. + + The default implementation ignores the event, so that the widget's + parent can interpret it. + + Note that QKeyEvent starts with isAccepted() == true, so you do not + need to call QKeyEvent::accept() - just do not call the base class + implementation if you act upon the key. + + \sa keyPressEvent(), QKeyEvent::ignore(), setFocusPolicy(), + focusInEvent(), focusOutEvent(), event(), QKeyEvent +*/ + +void QWidget::keyReleaseEvent(QKeyEvent *event) +{ + event->ignore(); +} + +/*! + \fn void QWidget::focusInEvent(QFocusEvent *event) + + This event handler can be reimplemented in a subclass to receive + keyboard focus events (focus received) for the widget. The event + is passed in the \a event parameter + + A widget normally must setFocusPolicy() to something other than + Qt::NoFocus in order to receive focus events. (Note that the + application programmer can call setFocus() on any widget, even + those that do not normally accept focus.) + + The default implementation updates the widget (except for windows + that do not specify a focusPolicy()). + + \sa focusOutEvent(), setFocusPolicy(), keyPressEvent(), + keyReleaseEvent(), event(), QFocusEvent +*/ + +void QWidget::focusInEvent(QFocusEvent *) +{ + if (focusPolicy() != Qt::NoFocus || !isWindow()) { + update(); + } +} + +/*! + \fn void QWidget::focusOutEvent(QFocusEvent *event) + + This event handler can be reimplemented in a subclass to receive + keyboard focus events (focus lost) for the widget. The events is + passed in the \a event parameter. + + A widget normally must setFocusPolicy() to something other than + Qt::NoFocus in order to receive focus events. (Note that the + application programmer can call setFocus() on any widget, even + those that do not normally accept focus.) + + The default implementation updates the widget (except for windows + that do not specify a focusPolicy()). + + \sa focusInEvent(), setFocusPolicy(), keyPressEvent(), + keyReleaseEvent(), event(), QFocusEvent +*/ + +void QWidget::focusOutEvent(QFocusEvent *) +{ + if (focusPolicy() != Qt::NoFocus || !isWindow()) + update(); +} + +/*! + \fn void QWidget::enterEvent(QEvent *event) + + This event handler can be reimplemented in a subclass to receive + widget enter events which are passed in the \a event parameter. + + An event is sent to the widget when the mouse cursor enters the + widget. + + \sa leaveEvent(), mouseMoveEvent(), event() +*/ + +void QWidget::enterEvent(QEvent *) +{ +} + +/*! + \fn void QWidget::leaveEvent(QEvent *event) + + This event handler can be reimplemented in a subclass to receive + widget leave events which are passed in the \a event parameter. + + A leave event is sent to the widget when the mouse cursor leaves + the widget. + + \sa enterEvent(), mouseMoveEvent(), event() +*/ + +void QWidget::leaveEvent(QEvent *) +{ +} + +/*! + \fn void QWidget::paintEvent(QPaintEvent *event) + + This event handler can be reimplemented in a subclass to receive paint + events passed in \a event. + + A paint event is a request to repaint all or part of a widget. It can + happen for one of the following reasons: + + \list + \o repaint() or update() was invoked, + \o the widget was obscured and has now been uncovered, or + \o many other reasons. + \endlist + + Many widgets can simply repaint their entire surface when asked to, but + some slow widgets need to optimize by painting only the requested region: + QPaintEvent::region(). This speed optimization does not change the result, + as painting is clipped to that region during event processing. QListView + and QTableView do this, for example. + + Qt also tries to speed up painting by merging multiple paint events into + one. When update() is called several times or the window system sends + several paint events, Qt merges these events into one event with a larger + region (see QRegion::united()). The repaint() function does not permit this + optimization, so we suggest using update() whenever possible. + + When the paint event occurs, the update region has normally been erased, so + you are painting on the widget's background. + + The background can be set using setBackgroundRole() and setPalette(). + + Since Qt 4.0, QWidget automatically double-buffers its painting, so there + is no need to write double-buffering code in paintEvent() to avoid flicker. + + \bold{Note for the X11 platform}: It is possible to toggle global double + buffering by calling \c qt_x11_set_global_double_buffer(). For example, + + \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 14 + + \note Generally, you should refrain from calling update() or repaint() + \bold{inside} a paintEvent(). For example, calling update() or repaint() on + children inside a paintevent() results in undefined behavior; the child may + or may not get a paint event. + + \warning If you are using a custom paint engine without Qt's backingstore, + Qt::WA_PaintOnScreen must be set. Otherwise, QWidget::paintEngine() will + never be called; the backingstore will be used instead. + + \sa event(), repaint(), update(), QPainter, QPixmap, QPaintEvent, + {Analog Clock Example} +*/ + +void QWidget::paintEvent(QPaintEvent *) +{ +} + + +/*! + \fn void QWidget::moveEvent(QMoveEvent *event) + + This event handler can be reimplemented in a subclass to receive + widget move events which are passed in the \a event parameter. + When the widget receives this event, it is already at the new + position. + + The old position is accessible through QMoveEvent::oldPos(). + + \sa resizeEvent(), event(), move(), QMoveEvent +*/ + +void QWidget::moveEvent(QMoveEvent *) +{ +} + + +/*! + This event handler can be reimplemented in a subclass to receive + widget resize events which are passed in the \a event parameter. + When resizeEvent() is called, the widget already has its new + geometry. The old size is accessible through + QResizeEvent::oldSize(). + + The widget will be erased and receive a paint event immediately + after processing the resize event. No drawing need be (or should + be) done inside this handler. + + + \sa moveEvent(), event(), resize(), QResizeEvent, paintEvent(), + {Scribble Example} +*/ + +void QWidget::resizeEvent(QResizeEvent * /* event */) +{ +} + +#ifndef QT_NO_ACTION +/*! + \fn void QWidget::actionEvent(QActionEvent *event) + + This event handler is called with the given \a event whenever the + widget's actions are changed. + + \sa addAction(), insertAction(), removeAction(), actions(), QActionEvent +*/ +void QWidget::actionEvent(QActionEvent *) +{ + +} +#endif + +/*! + This event handler is called with the given \a event when Qt receives a window + close request for a top-level widget from the window system. + + By default, the event is accepted and the widget is closed. You can reimplement + this function to change the way the widget responds to window close requests. + For example, you can prevent the window from closing by calling \l{QEvent::}{ignore()} + on all events. + + Main window applications typically use reimplementations of this function to check + whether the user's work has been saved and ask for permission before closing. + For example, the \l{Application Example} uses a helper function to determine whether + or not to close the window: + + \snippet mainwindows/application/mainwindow.cpp 3 + \snippet mainwindows/application/mainwindow.cpp 4 + + \sa event(), hide(), close(), QCloseEvent, {Application Example} +*/ + +void QWidget::closeEvent(QCloseEvent *event) +{ + event->accept(); +} + +#ifndef QT_NO_CONTEXTMENU +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive widget context menu events. + + The handler is called when the widget's \l contextMenuPolicy is + Qt::DefaultContextMenu. + + The default implementation ignores the context event. + See the \l QContextMenuEvent documentation for more details. + + \sa event(), QContextMenuEvent customContextMenuRequested() +*/ + +void QWidget::contextMenuEvent(QContextMenuEvent *event) +{ + event->ignore(); +} +#endif // QT_NO_CONTEXTMENU + + +/*! + This event handler, for event \a event, can be reimplemented in a + subclass to receive Input Method composition events. This handler + is called when the state of the input method changes. + + Note that when creating custom text editing widgets, the + Qt::WA_InputMethodEnabled window attribute must be set explicitly + (using the setAttribute() function) in order to receive input + method events. + + The default implementation calls event->ignore(), which rejects the + Input Method event. See the \l QInputMethodEvent documentation for more + details. + + \sa event(), QInputMethodEvent +*/ +void QWidget::inputMethodEvent(QInputMethodEvent *event) +{ + event->ignore(); +} + +/*! + This method is only relevant for input widgets. It is used by the + input method to query a set of properties of the widget to be + able to support complex input method operations as support for + surrounding text and reconversions. + + \a query specifies which property is queried. + + \sa inputMethodEvent(), QInputMethodEvent, QInputContext, inputMethodHints +*/ +QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const +{ + switch(query) { + case Qt::ImMicroFocus: + return QRect(width()/2, 0, 1, height()); + case Qt::ImFont: + return font(); + case Qt::ImAnchorPosition: + // Fallback. + return inputMethodQuery(Qt::ImCursorPosition); + default: + return QVariant(); + } +} + +/*! + \property QWidget::inputMethodHints + \brief What input method specific hints the widget has. + + This is only relevant for input widgets. It is used by + the input method to retrieve hints as to how the input method + should operate. For example, if the Qt::ImhFormattedNumbersOnly flag + is set, the input method may change its visual components to reflect + that only numbers can be entered. + + \note The flags are only hints, so the particular input method + implementation is free to ignore them. If you want to be + sure that a certain type of characters are entered, + you should also set a QValidator on the widget. + + The default value is Qt::ImhNone. + + \since 4.6 + + \sa inputMethodQuery(), QInputContext +*/ +Qt::InputMethodHints QWidget::inputMethodHints() const +{ +#ifndef QT_NO_IM + const QWidgetPrivate *priv = d_func(); + while (priv->inheritsInputMethodHints) { + priv = priv->q_func()->parentWidget()->d_func(); + Q_ASSERT(priv); + } + return priv->imHints; +#else //QT_NO_IM + return 0; +#endif //QT_NO_IM +} + +void QWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ +#ifndef QT_NO_IM + Q_D(QWidget); + d->imHints = hints; + // Optimization to update input context only it has already been created. + if (d->ic || qApp->d_func()->inputContext) { + QInputContext *ic = inputContext(); + if (ic) + ic->update(); + } +#endif //QT_NO_IM +} + + +#ifndef QT_NO_DRAGANDDROP + +/*! + \fn void QWidget::dragEnterEvent(QDragEnterEvent *event) + + This event handler is called when a drag is in progress and the + mouse enters this widget. The event is passed in the \a event parameter. + + If the event is ignored, the widget won't receive any \l{dragMoveEvent()}{drag + move events}. + + See the \link dnd.html Drag-and-drop documentation\endlink for an + overview of how to provide drag-and-drop in your application. + + \sa QDrag, QDragEnterEvent +*/ +void QWidget::dragEnterEvent(QDragEnterEvent *) +{ +} + +/*! + \fn void QWidget::dragMoveEvent(QDragMoveEvent *event) + + This event handler is called if a drag is in progress, and when + any of the following conditions occur: the cursor enters this widget, + the cursor moves within this widget, or a modifier key is pressed on + the keyboard while this widget has the focus. The event is passed + in the \a event parameter. + + See the \link dnd.html Drag-and-drop documentation\endlink for an + overview of how to provide drag-and-drop in your application. + + \sa QDrag, QDragMoveEvent +*/ +void QWidget::dragMoveEvent(QDragMoveEvent *) +{ +} + +/*! + \fn void QWidget::dragLeaveEvent(QDragLeaveEvent *event) + + This event handler is called when a drag is in progress and the + mouse leaves this widget. The event is passed in the \a event + parameter. + + See the \link dnd.html Drag-and-drop documentation\endlink for an + overview of how to provide drag-and-drop in your application. + + \sa QDrag, QDragLeaveEvent +*/ +void QWidget::dragLeaveEvent(QDragLeaveEvent *) +{ +} + +/*! + \fn void QWidget::dropEvent(QDropEvent *event) + + This event handler is called when the drag is dropped on this + widget. The event is passed in the \a event parameter. + + See the \link dnd.html Drag-and-drop documentation\endlink for an + overview of how to provide drag-and-drop in your application. + + \sa QDrag, QDropEvent +*/ +void QWidget::dropEvent(QDropEvent *) +{ +} + +#endif // QT_NO_DRAGANDDROP + +/*! + \fn void QWidget::showEvent(QShowEvent *event) + + This event handler can be reimplemented in a subclass to receive + widget show events which are passed in the \a event parameter. + + Non-spontaneous show events are sent to widgets immediately + before they are shown. The spontaneous show events of windows are + delivered afterwards. + + Note: A widget receives spontaneous show and hide events when its + mapping status is changed by the window system, e.g. a spontaneous + hide event when the user minimizes the window, and a spontaneous + show event when the window is restored again. After receiving a + spontaneous hide event, a widget is still considered visible in + the sense of isVisible(). + + \sa visible, event(), QShowEvent +*/ +void QWidget::showEvent(QShowEvent *) +{ +} + +/*! + \fn void QWidget::hideEvent(QHideEvent *event) + + This event handler can be reimplemented in a subclass to receive + widget hide events. The event is passed in the \a event parameter. + + Hide events are sent to widgets immediately after they have been + hidden. + + Note: A widget receives spontaneous show and hide events when its + mapping status is changed by the window system, e.g. a spontaneous + hide event when the user minimizes the window, and a spontaneous + show event when the window is restored again. After receiving a + spontaneous hide event, a widget is still considered visible in + the sense of isVisible(). + + \sa visible, event(), QHideEvent +*/ +void QWidget::hideEvent(QHideEvent *) +{ +} + +/* + \fn QWidget::x11Event(MSG *) + + This special event handler can be reimplemented in a subclass to receive + native X11 events. + + In your reimplementation of this function, if you want to stop Qt from + handling the event, return true. If you return false, this native event + is passed back to Qt, which translates it into a Qt event and sends it to + the widget. + + \note Events are only delivered to this event handler if the widget is + native. + + \warning This function is not portable. + + \sa QApplication::x11EventFilter(), QWidget::winId() +*/ + + +#if defined(Q_WS_MAC) + +/*! + \fn bool QWidget::macEvent(EventHandlerCallRef caller, EventRef event) + + This special event handler can be reimplemented in a subclass to + receive native Macintosh events. + + The parameters are a bit different depending if Qt is build against Carbon + or Cocoa. In Carbon, \a caller and \a event are the corresponding + EventHandlerCallRef and EventRef that correspond to the Carbon event + handlers that are installed. In Cocoa, \a caller is always 0 and the + EventRef is the EventRef generated from the NSEvent. + + In your reimplementation of this function, if you want to stop the + event being handled by Qt, return true. If you return false, this + native event is passed back to Qt, which translates the event into + a Qt event and sends it to the widget. + + \warning This function is not portable. + + \warning This function was not called inside of Qt until Qt 4.4. + If you need compatibility with earlier versions of Qt, consider QApplication::macEventFilter() instead. + + \sa QApplication::macEventFilter() +*/ + +bool QWidget::macEvent(EventHandlerCallRef, EventRef) +{ + return false; +} + +#endif +#if defined(Q_WS_WIN) + +/*! + This special event handler can be reimplemented in a subclass to + receive native Windows events which are passed in the \a message + parameter. + + In your reimplementation of this function, if you want to stop the + event being handled by Qt, return true and set \a result to the value + that the window procedure should return. If you return false, this + native event is passed back to Qt, which translates the event into + a Qt event and sends it to the widget. + + \warning This function is not portable. + + \sa QApplication::winEventFilter() +*/ +bool QWidget::winEvent(MSG *message, long *result) +{ + Q_UNUSED(message); + Q_UNUSED(result); + return false; +} + +#endif +#if defined(Q_WS_X11) + +/*! + \fn bool QWidget::x11Event(XEvent *event) + + This special event handler can be reimplemented in a subclass to receive + native X11 events passed in the \a event parameter. + + In your reimplementation of this function, if you want to stop Qt from + handling the event, return true. If you return false, this native event + is passed back to Qt, which translates it into a Qt event and sends it to + the widget. + + \note Events are only delivered to this event handler if the widget is + native. + + \warning This function is not portable. + + \sa QApplication::x11EventFilter(), QWidget::winId() +*/ +bool QWidget::x11Event(XEvent *) +{ + return false; +} + +#endif +#if defined(Q_WS_QWS) + +/*! + \fn bool QWidget::qwsEvent(QWSEvent *event) + + This special event handler can be reimplemented in a subclass to + receive native Qt for Embedded Linux events which are passed in the + \a event parameter. + + In your reimplementation of this function, if you want to stop the + event being handled by Qt, return true. If you return false, this + native event is passed back to Qt, which translates the event into + a Qt event and sends it to the widget. + + \warning This function is not portable. + + \sa QApplication::qwsEventFilter() +*/ +bool QWidget::qwsEvent(QWSEvent *) +{ + return false; +} + +#endif + + +/*! + Ensures that the widget has been polished by QStyle (i.e., has a + proper font and palette). + + QWidget calls this function after it has been fully constructed + but before it is shown the very first time. You can call this + function if you want to ensure that the widget is polished before + doing an operation, e.g., the correct font size might be needed in + the widget's sizeHint() reimplementation. Note that this function + \e is called from the default implementation of sizeHint(). + + Polishing is useful for final initialization that must happen after + all constructors (from base classes as well as from subclasses) + have been called. + + If you need to change some settings when a widget is polished, + reimplement event() and handle the QEvent::Polish event type. + + \bold{Note:} The function is declared const so that it can be called from + other const functions (e.g., sizeHint()). + + \sa event() +*/ +void QWidget::ensurePolished() const +{ + Q_D(const QWidget); + + const QMetaObject *m = metaObject(); + if (m == d->polished) + return; + d->polished = m; + + QEvent e(QEvent::Polish); + QCoreApplication::sendEvent(const_cast(this), &e); + + // polish children after 'this' + QList children = d->children; + for (int i = 0; i < children.size(); ++i) { + QObject *o = children.at(i); + if(!o->isWidgetType()) + continue; + if (QWidget *w = qobject_cast(o)) + w->ensurePolished(); + } + + if (d->parent && d->sendChildEvents) { + QChildEvent e(QEvent::ChildPolished, const_cast(this)); + QCoreApplication::sendEvent(d->parent, &e); + } +} + +/*! + Returns the mask currently set on a widget. If no mask is set the + return value will be an empty region. + + \sa setMask(), clearMask(), QRegion::isEmpty(), {Shaped Clock Example} +*/ +QRegion QWidget::mask() const +{ + Q_D(const QWidget); + return d->extra ? d->extra->mask : QRegion(); +} + +/*! + Returns the layout manager that is installed on this widget, or 0 + if no layout manager is installed. + + The layout manager sets the geometry of the widget's children + that have been added to the layout. + + \sa setLayout(), sizePolicy(), {Layout Management} +*/ +QLayout *QWidget::layout() const +{ + return d_func()->layout; +} + + +/*! + \fn void QWidget::setLayout(QLayout *layout) + + Sets the layout manager for this widget to \a layout. + + If there already is a layout manager installed on this widget, + QWidget won't let you install another. You must first delete the + existing layout manager (returned by layout()) before you can + call setLayout() with the new layout. + + If \a layout is the layout manger on a different widget, setLayout() + will reparent the layout and make it the layout manager for this widget. + + Example: + + \snippet examples/uitools/textfinder/textfinder.cpp 3b + + An alternative to calling this function is to pass this widget to + the layout's constructor. + + The QWidget will take ownership of \a layout. + + \sa layout(), {Layout Management} +*/ + +void QWidget::setLayout(QLayout *l) +{ + if (!l) { + qWarning("QWidget::setLayout: Cannot set layout to 0"); + return; + } + if (layout()) { + if (layout() != l) + qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", which already has a" + " layout", l->objectName().toLocal8Bit().data(), metaObject()->className(), + objectName().toLocal8Bit().data()); + return; + } + + QObject *oldParent = l->parent(); + if (oldParent && oldParent != this) { + if (oldParent->isWidgetType()) { + // Steal the layout off a widget parent. Takes effect when + // morphing laid-out container widgets in Designer. + QWidget *oldParentWidget = static_cast(oldParent); + oldParentWidget->takeLayout(); + } else { + qWarning("QWidget::setLayout: Attempting to set QLayout \"%s\" on %s \"%s\", when the QLayout already has a parent", + l->objectName().toLocal8Bit().data(), metaObject()->className(), + objectName().toLocal8Bit().data()); + return; + } + } + + Q_D(QWidget); + l->d_func()->topLevel = true; + d->layout = l; + if (oldParent != this) { + l->setParent(this); + l->d_func()->reparentChildWidgets(this); + l->invalidate(); + } + + if (isWindow() && d->maybeTopData()) + d->topData()->sizeAdjusted = false; +} + +/*! + \fn QLayout *QWidget::takeLayout() + + Remove the layout from the widget. + \since 4.5 +*/ + +QLayout *QWidget::takeLayout() +{ + Q_D(QWidget); + QLayout *l = layout(); + if (!l) + return 0; + d->layout = 0; + l->setParent(0); + return l; +} + +/*! + \property QWidget::sizePolicy + \brief the default layout behavior of the widget + + If there is a QLayout that manages this widget's children, the + size policy specified by that layout is used. If there is no such + QLayout, the result of this function is used. + + The default policy is Preferred/Preferred, which means that the + widget can be freely resized, but prefers to be the size + sizeHint() returns. Button-like widgets set the size policy to + specify that they may stretch horizontally, but are fixed + vertically. The same applies to lineedit controls (such as + QLineEdit, QSpinBox or an editable QComboBox) and other + horizontally orientated widgets (such as QProgressBar). + QToolButton's are normally square, so they allow growth in both + directions. Widgets that support different directions (such as + QSlider, QScrollBar or QHeader) specify stretching in the + respective direction only. Widgets that can provide scroll bars + (usually subclasses of QScrollArea) tend to specify that they can + use additional space, and that they can make do with less than + sizeHint(). + + \sa sizeHint() QLayout QSizePolicy updateGeometry() +*/ +QSizePolicy QWidget::sizePolicy() const +{ + Q_D(const QWidget); + return d->size_policy; +} + +void QWidget::setSizePolicy(QSizePolicy policy) +{ + Q_D(QWidget); + setAttribute(Qt::WA_WState_OwnSizePolicy); + if (policy == d->size_policy) + return; + d->size_policy = policy; + +#ifndef QT_NO_GRAPHICSVIEW + if (QWExtra *extra = d->extra) { + if (extra->proxyWidget) + extra->proxyWidget->setSizePolicy(policy); + } +#endif + + updateGeometry(); + + if (isWindow() && d->maybeTopData()) + d->topData()->sizeAdjusted = false; +} + +/*! + \fn void QWidget::setSizePolicy(QSizePolicy::Policy horizontal, QSizePolicy::Policy vertical) + \overload + + Sets the size policy of the widget to \a horizontal and \a + vertical, with standard stretch and no height-for-width. + + \sa QSizePolicy::QSizePolicy() +*/ + +/*! + Returns the preferred height for this widget, given the width \a w. + + If this widget has a layout, the default implementation returns + the layout's preferred height. if there is no layout, the default + implementation returns -1 indicating that the preferred height + does not depend on the width. +*/ + +int QWidget::heightForWidth(int w) const +{ + if (layout() && layout()->hasHeightForWidth()) + return layout()->totalHeightForWidth(w); + return -1; +} + + +/*! + \internal + + *virtual private* + + This is a bit hackish, but ideally we would have created a virtual function + in the public API (however, too late...) so that subclasses could reimplement + their own function. + Instead we add a virtual function to QWidgetPrivate. + ### Qt5: move to public class and make virtual +*/ +bool QWidgetPrivate::hasHeightForWidth() const +{ + return layout ? layout->hasHeightForWidth() : size_policy.hasHeightForWidth(); +} + +/*! + \fn QWidget *QWidget::childAt(int x, int y) const + + Returns the visible child widget at the position (\a{x}, \a{y}) + in the widget's coordinate system. If there is no visible child + widget at the specified position, the function returns 0. +*/ + +/*! + \overload + + Returns the visible child widget at point \a p in the widget's own + coordinate system. +*/ + +QWidget *QWidget::childAt(const QPoint &p) const +{ + return d_func()->childAt_helper(p, false); +} + +QWidget *QWidgetPrivate::childAt_helper(const QPoint &p, bool ignoreChildrenInDestructor) const +{ + if (children.isEmpty()) + return 0; + +#ifdef Q_WS_MAC + Q_Q(const QWidget); + // Unified tool bars on the Mac require special handling since they live outside + // QMainWindow's geometry(). See commit: 35667fd45ada49269a5987c235fdedfc43e92bb8 + bool includeFrame = q->isWindow() && qobject_cast(q) + && static_cast(q)->unifiedTitleAndToolBarOnMac(); + if (includeFrame) + return childAtRecursiveHelper(p, ignoreChildrenInDestructor, includeFrame); +#endif + + if (!pointInsideRectAndMask(p)) + return 0; + return childAtRecursiveHelper(p, ignoreChildrenInDestructor); +} + +QWidget *QWidgetPrivate::childAtRecursiveHelper(const QPoint &p, bool ignoreChildrenInDestructor, bool includeFrame) const +{ +#ifndef Q_WS_MAC + Q_UNUSED(includeFrame); +#endif + for (int i = children.size() - 1; i >= 0; --i) { + QWidget *child = qobject_cast(children.at(i)); + if (!child || child->isWindow() || child->isHidden() || child->testAttribute(Qt::WA_TransparentForMouseEvents) + || (ignoreChildrenInDestructor && child->data->in_destructor)) { + continue; + } + + // Map the point 'p' from parent coordinates to child coordinates. + QPoint childPoint = p; +#ifdef Q_WS_MAC + // 'includeFrame' is true if the child's parent is a top-level QMainWindow with an unified tool bar. + // An unified tool bar on the Mac lives outside QMainWindow's geometry(), so a normal + // QWidget::mapFromParent won't do the trick. + if (includeFrame && qobject_cast(child)) + childPoint = qt_mac_nativeMapFromParent(child, p); + else +#endif + childPoint -= child->data->crect.topLeft(); + + // Check if the point hits the child. + if (!child->d_func()->pointInsideRectAndMask(childPoint)) + continue; + + // Do the same for the child's descendants. + if (QWidget *w = child->d_func()->childAtRecursiveHelper(childPoint, ignoreChildrenInDestructor)) + return w; + + // We have found our target; namely the child at position 'p'. + return child; + } + return 0; +} + +void QWidgetPrivate::updateGeometry_helper(bool forceUpdate) +{ + Q_Q(QWidget); + if (widgetItem) + widgetItem->invalidateSizeCache(); + QWidget *parent; + if (forceUpdate || !extra || extra->minw != extra->maxw || extra->minh != extra->maxh) { + if (!q->isWindow() && !q->isHidden() && (parent = q->parentWidget())) { + if (parent->d_func()->layout) + parent->d_func()->layout->invalidate(); + else if (parent->isVisible()) + QApplication::postEvent(parent, new QEvent(QEvent::LayoutRequest)); + } + } +} + +/*! + Notifies the layout system that this widget has changed and may + need to change geometry. + + Call this function if the sizeHint() or sizePolicy() have changed. + + For explicitly hidden widgets, updateGeometry() is a no-op. The + layout system will be notified as soon as the widget is shown. +*/ + +void QWidget::updateGeometry() +{ + Q_D(QWidget); + d->updateGeometry_helper(false); +} + +/*! \property QWidget::windowFlags + + Window flags are a combination of a type (e.g. Qt::Dialog) and + zero or more hints to the window system (e.g. + Qt::FramelessWindowHint). + + If the widget had type Qt::Widget or Qt::SubWindow and becomes a + window (Qt::Window, Qt::Dialog, etc.), it is put at position (0, + 0) on the desktop. If the widget is a window and becomes a + Qt::Widget or Qt::SubWindow, it is put at position (0, 0) + relative to its parent widget. + + \note This function calls setParent() when changing the flags for + a window, causing the widget to be hidden. You must call show() to make + the widget visible again.. + + \sa windowType(), {Window Flags Example} +*/ +void QWidget::setWindowFlags(Qt::WindowFlags flags) +{ + if (data->window_flags == flags) + return; + + Q_D(QWidget); + + if ((data->window_flags | flags) & Qt::Window) { + // the old type was a window and/or the new type is a window + QPoint oldPos = pos(); + bool visible = isVisible(); + setParent(parentWidget(), flags); + + // if both types are windows or neither of them are, we restore + // the old position + if (!((data->window_flags ^ flags) & Qt::Window) + && (visible || testAttribute(Qt::WA_Moved))) { + move(oldPos); + } + // for backward-compatibility we change Qt::WA_QuitOnClose attribute value only when the window was recreated. + d->adjustQuitOnCloseAttribute(); + } else { + data->window_flags = flags; + } +} + +/*! + Sets the window flags for the widget to \a flags, + \e without telling the window system. + + \warning Do not call this function unless you really know what + you're doing. + + \sa setWindowFlags() +*/ +void QWidget::overrideWindowFlags(Qt::WindowFlags flags) +{ + data->window_flags = flags; +} + +/*! + \fn Qt::WindowType QWidget::windowType() const + + Returns the window type of this widget. This is identical to + windowFlags() & Qt::WindowType_Mask. + + \sa windowFlags +*/ + +/*! + Sets the parent of the widget to \a parent, and resets the window + flags. The widget is moved to position (0, 0) in its new parent. + + If the new parent widget is in a different window, the + reparented widget and its children are appended to the end of the + \l{setFocusPolicy()}{tab chain} of the new parent + widget, in the same internal order as before. If one of the moved + widgets had keyboard focus, setParent() calls clearFocus() for that + widget. + + If the new parent widget is in the same window as the + old parent, setting the parent doesn't change the tab order or + keyboard focus. + + If the "new" parent widget is the old parent widget, this function + does nothing. + + \note The widget becomes invisible as part of changing its parent, + even if it was previously visible. You must call show() to make the + widget visible again. + + \warning It is very unlikely that you will ever need this + function. If you have a widget that changes its content + dynamically, it is far easier to use \l QStackedWidget. + + \sa setWindowFlags() +*/ +void QWidget::setParent(QWidget *parent) +{ + if (parent == parentWidget()) + return; + setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask); +} + +/*! + \overload + + This function also takes widget flags, \a f as an argument. +*/ + +void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) +{ + Q_D(QWidget); + bool resized = testAttribute(Qt::WA_Resized); + bool wasCreated = testAttribute(Qt::WA_WState_Created); + QWidget *oldtlw = window(); + + QWidget *desktopWidget = 0; + if (parent && parent->windowType() == Qt::Desktop) + desktopWidget = parent; + bool newParent = (parent != parentWidget()) || !wasCreated || desktopWidget; + +#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) + if (newParent && parent && !desktopWidget) { + if (testAttribute(Qt::WA_NativeWindow) && !qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + // On Mac, toolbars inside the unified title bar will never overlap with + // siblings in the content view. So we skip enforce native siblings in that case + && !d->isInUnifiedToolbar && parentWidget() && parentWidget()->isWindow() +#endif // Q_WS_MAC && QT_MAC_USE_COCOA + ) + parent->d_func()->enforceNativeChildren(); + else if (parent->d_func()->nativeChildrenForced() || parent->testAttribute(Qt::WA_PaintOnScreen)) + setAttribute(Qt::WA_NativeWindow); + } +#endif + + if (wasCreated) { + if (!testAttribute(Qt::WA_WState_Hidden)) { + hide(); + setAttribute(Qt::WA_WState_ExplicitShowHide, false); + } + if (newParent) { + QEvent e(QEvent::ParentAboutToChange); + QApplication::sendEvent(this, &e); + } + } + if (newParent && isAncestorOf(focusWidget())) + focusWidget()->clearFocus(); + + QTLWExtra *oldTopExtra = window()->d_func()->maybeTopData(); + QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStore : 0; + + d->setParent_sys(parent, f); + + QTLWExtra *topExtra = window()->d_func()->maybeTopData(); + QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStore : 0; + if (oldBsTracker && oldBsTracker != bsTracker) + oldBsTracker->unregisterWidgetSubtree(this); + + if (desktopWidget) + parent = 0; + +#ifdef Q_BACKINGSTORE_SUBSURFACES + QTLWExtra *extra = d->maybeTopData(); + QWindowSurface *windowSurface = (extra ? extra->windowSurface : 0); + if (newParent && windowSurface) { + QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore(); + if (oldBs) + oldBs->subSurfaces.removeAll(windowSurface); + + if (parent) { + QWidgetBackingStore *newBs = parent->d_func()->maybeBackingStore(); + if (newBs) + newBs->subSurfaces.append(windowSurface); + } + } +#endif + + if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) { + if (newParent) + oldBs->removeDirtyWidget(this); + // Move the widget and all its static children from + // the old backing store to the new one. + oldBs->moveStaticWidgets(this); + } + + if ((QApplicationPrivate::app_compile_version < 0x040200 + || QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation)) + && !testAttribute(Qt::WA_WState_Created)) + create(); + + d->reparentFocusWidgets(oldtlw); + setAttribute(Qt::WA_Resized, resized); + if (!testAttribute(Qt::WA_StyleSheet) + && (!parent || !parent->testAttribute(Qt::WA_StyleSheet))) { + d->resolveFont(); + d->resolvePalette(); + } + d->resolveLayoutDirection(); + d->resolveLocale(); + + // Note: GL widgets under WGL or EGL will always need a ParentChange + // event to handle recreation/rebinding of the GL context, hence the + // (f & Qt::MSWindowsOwnDC) clause (which is set on QGLWidgets on all + // platforms). + if (newParent +#if defined(Q_WS_WIN) || defined(QT_OPENGL_ES) + || (f & Qt::MSWindowsOwnDC) +#endif + ) { + // propagate enabled updates enabled state to non-windows + if (!isWindow()) { + if (!testAttribute(Qt::WA_ForceDisabled)) + d->setEnabled_helper(parent ? parent->isEnabled() : true); + if (!testAttribute(Qt::WA_ForceUpdatesDisabled)) + d->setUpdatesEnabled_helper(parent ? parent->updatesEnabled() : true); + } + d->inheritStyle(); + + // send and post remaining QObject events + if (parent && d->sendChildEvents) { + QChildEvent e(QEvent::ChildAdded, this); + QApplication::sendEvent(parent, &e); +#ifdef QT3_SUPPORT + if (parent->d_func()->pendingChildInsertedEvents.isEmpty()) { + QApplication::postEvent(parent, + new QEvent(QEvent::ChildInsertedRequest), + Qt::HighEventPriority); + } + parent->d_func()->pendingChildInsertedEvents.append(this); +#endif + } + +//### already hidden above ---> must probably do something smart on the mac +// #ifdef Q_WS_MAC +// extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp +// if(!qt_mac_is_macdrawer(q)) //special case +// q->setAttribute(Qt::WA_WState_Hidden); +// #else +// q->setAttribute(Qt::WA_WState_Hidden); +//#endif + + if (parent && d->sendChildEvents && d->polished) { + QChildEvent e(QEvent::ChildPolished, this); + QCoreApplication::sendEvent(parent, &e); + } + + QEvent e(QEvent::ParentChange); + QApplication::sendEvent(this, &e); + } + + if (!wasCreated) { + if (isWindow() || parentWidget()->isVisible()) + setAttribute(Qt::WA_WState_Hidden, true); + else if (!testAttribute(Qt::WA_WState_ExplicitShowHide)) + setAttribute(Qt::WA_WState_Hidden, false); + } + + d->updateIsOpaque(); + +#ifndef QT_NO_GRAPHICSVIEW + // Embed the widget into a proxy if the parent is embedded. + // ### Doesn't handle reparenting out of an embedded widget. + if (oldtlw->graphicsProxyWidget()) { + if (QGraphicsProxyWidget *ancestorProxy = d->nearestGraphicsProxyWidget(oldtlw)) + ancestorProxy->d_func()->unembedSubWindow(this); + } + if (isWindow() && parent && !graphicsProxyWidget() && !bypassGraphicsProxyWidget(this)) { + if (QGraphicsProxyWidget *ancestorProxy = d->nearestGraphicsProxyWidget(parent)) + ancestorProxy->d_func()->embedSubWindow(this); + } +#endif +} + +/*! + Scrolls the widget including its children \a dx pixels to the + right and \a dy downward. Both \a dx and \a dy may be negative. + + After scrolling, the widgets will receive paint events for + the areas that need to be repainted. For widgets that Qt knows to + be opaque, this is only the newly exposed parts. + For example, if an opaque widget is scrolled 8 pixels to the left, + only an 8-pixel wide stripe at the right edge needs updating. + + Since widgets propagate the contents of their parents by default, + you need to set the \l autoFillBackground property, or use + setAttribute() to set the Qt::WA_OpaquePaintEvent attribute, to make + a widget opaque. + + For widgets that use contents propagation, a scroll will cause an + update of the entire scroll area. + + \sa {Transparency and Double Buffering} +*/ + +void QWidget::scroll(int dx, int dy) +{ + if ((!updatesEnabled() && children().size() == 0) || !isVisible()) + return; + if (dx == 0 && dy == 0) + return; + Q_D(QWidget); +#ifndef QT_NO_GRAPHICSVIEW + if (QGraphicsProxyWidget *proxy = QWidgetPrivate::nearestGraphicsProxyWidget(this)) { + // Graphics View maintains its own dirty region as a list of rects; + // until we can connect item updates directly to the view, we must + // separately add a translated dirty region. + if (!d->dirty.isEmpty()) { + foreach (const QRect &rect, (d->dirty.translated(dx, dy)).rects()) + proxy->update(rect); + } + proxy->scroll(dx, dy, proxy->subWidgetRect(this)); + return; + } +#endif + d->setDirtyOpaqueRegion(); + d->scroll_sys(dx, dy); +} + +/*! + \overload + + This version only scrolls \a r and does not move the children of + the widget. + + If \a r is empty or invalid, the result is undefined. + + \sa QScrollArea +*/ +void QWidget::scroll(int dx, int dy, const QRect &r) +{ + + if ((!updatesEnabled() && children().size() == 0) || !isVisible()) + return; + if (dx == 0 && dy == 0) + return; + Q_D(QWidget); +#ifndef QT_NO_GRAPHICSVIEW + if (QGraphicsProxyWidget *proxy = QWidgetPrivate::nearestGraphicsProxyWidget(this)) { + // Graphics View maintains its own dirty region as a list of rects; + // until we can connect item updates directly to the view, we must + // separately add a translated dirty region. + if (!d->dirty.isEmpty()) { + foreach (const QRect &rect, (d->dirty.translated(dx, dy) & r).rects()) + proxy->update(rect); + } + proxy->scroll(dx, dy, r.translated(proxy->subWidgetRect(this).topLeft().toPoint())); + return; + } +#endif + d->scroll_sys(dx, dy, r); +} + +/*! + Repaints the widget directly by calling paintEvent() immediately, + unless updates are disabled or the widget is hidden. + + We suggest only using repaint() if you need an immediate repaint, + for example during animation. In almost all circumstances update() + is better, as it permits Qt to optimize for speed and minimize + flicker. + + \warning If you call repaint() in a function which may itself be + called from paintEvent(), you may get infinite recursion. The + update() function never causes recursion. + + \sa update(), paintEvent(), setUpdatesEnabled() +*/ + +void QWidget::repaint() +{ + repaint(rect()); +} + +/*! \overload + + This version repaints a rectangle (\a x, \a y, \a w, \a h) inside + the widget. + + If \a w is negative, it is replaced with \c{width() - x}, and if + \a h is negative, it is replaced width \c{height() - y}. +*/ +void QWidget::repaint(int x, int y, int w, int h) +{ + if (x > data->crect.width() || y > data->crect.height()) + return; + + if (w < 0) + w = data->crect.width() - x; + if (h < 0) + h = data->crect.height() - y; + + repaint(QRect(x, y, w, h)); +} + +/*! \overload + + This version repaints a rectangle \a rect inside the widget. +*/ +void QWidget::repaint(const QRect &rect) +{ + Q_D(QWidget); + + if (testAttribute(Qt::WA_WState_ConfigPending)) { + update(rect); + return; + } + + if (!isVisible() || !updatesEnabled() || rect.isEmpty()) + return; + + if (hasBackingStoreSupport()) { +#ifdef QT_MAC_USE_COCOA + if (qt_widget_private(this)->isInUnifiedToolbar) { + qt_widget_private(this)->unifiedSurface->renderToolbar(this, true); + return; + } +#endif // QT_MAC_USE_COCOA + QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { + tlwExtra->inRepaint = true; + tlwExtra->backingStore->markDirty(rect, this, true); + tlwExtra->inRepaint = false; + } + } else { + d->repaint_sys(rect); + } +} + +/*! + \overload + + This version repaints a region \a rgn inside the widget. +*/ +void QWidget::repaint(const QRegion &rgn) +{ + Q_D(QWidget); + + if (testAttribute(Qt::WA_WState_ConfigPending)) { + update(rgn); + return; + } + + if (!isVisible() || !updatesEnabled() || rgn.isEmpty()) + return; + + if (hasBackingStoreSupport()) { +#ifdef QT_MAC_USE_COCOA + if (qt_widget_private(this)->isInUnifiedToolbar) { + qt_widget_private(this)->unifiedSurface->renderToolbar(this, true); + return; + } +#endif // QT_MAC_USE_COCOA + QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { + tlwExtra->inRepaint = true; + tlwExtra->backingStore->markDirty(rgn, this, true); + tlwExtra->inRepaint = false; + } + } else { + d->repaint_sys(rgn); + } +} + +/*! + Updates the widget unless updates are disabled or the widget is + hidden. + + This function does not cause an immediate repaint; instead it + schedules a paint event for processing when Qt returns to the main + event loop. This permits Qt to optimize for more speed and less + flicker than a call to repaint() does. + + Calling update() several times normally results in just one + paintEvent() call. + + Qt normally erases the widget's area before the paintEvent() call. + If the Qt::WA_OpaquePaintEvent widget attribute is set, the widget is + responsible for painting all its pixels with an opaque color. + + \sa repaint() paintEvent(), setUpdatesEnabled(), {Analog Clock Example} +*/ +void QWidget::update() +{ + update(rect()); +} + +/*! \fn void QWidget::update(int x, int y, int w, int h) + \overload + + This version updates a rectangle (\a x, \a y, \a w, \a h) inside + the widget. +*/ + +/*! + \overload + + This version updates a rectangle \a rect inside the widget. +*/ +void QWidget::update(const QRect &rect) +{ + if (!isVisible() || !updatesEnabled() || rect.isEmpty()) + return; + + if (testAttribute(Qt::WA_WState_InPaintEvent)) { + QApplication::postEvent(this, new QUpdateLaterEvent(rect)); + return; + } + + if (hasBackingStoreSupport()) { +#ifdef QT_MAC_USE_COCOA + if (qt_widget_private(this)->isInUnifiedToolbar) { + qt_widget_private(this)->unifiedSurface->renderToolbar(this, true); + return; + } +#endif // QT_MAC_USE_COCOA + QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) + tlwExtra->backingStore->markDirty(rect, this); + } else { + d_func()->repaint_sys(rect); + } +} + +/*! + \overload + + This version repaints a region \a rgn inside the widget. +*/ +void QWidget::update(const QRegion &rgn) +{ + if (!isVisible() || !updatesEnabled() || rgn.isEmpty()) + return; + + if (testAttribute(Qt::WA_WState_InPaintEvent)) { + QApplication::postEvent(this, new QUpdateLaterEvent(rgn)); + return; + } + + if (hasBackingStoreSupport()) { +#ifdef QT_MAC_USE_COCOA + if (qt_widget_private(this)->isInUnifiedToolbar) { + qt_widget_private(this)->unifiedSurface->renderToolbar(this, true); + return; + } +#endif // QT_MAC_USE_COCOA + QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); + if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) + tlwExtra->backingStore->markDirty(rgn, this); + } else { + d_func()->repaint_sys(rgn); + } +} + +#ifdef QT3_SUPPORT +/*! + Clear the rectangle at point (\a x, \a y) of width \a w and height + \a h. + + \warning This is best done in a paintEvent(). +*/ +void QWidget::erase_helper(int x, int y, int w, int h) +{ + if (testAttribute(Qt::WA_NoSystemBackground) || testAttribute(Qt::WA_UpdatesDisabled) || !testAttribute(Qt::WA_WState_Visible)) + return; + if (w < 0) + w = data->crect.width() - x; + if (h < 0) + h = data->crect.height() - y; + if (w != 0 && h != 0) { + QPainter p(this); + p.eraseRect(QRect(x, y, w, h)); + } +} + +/*! + \overload + + Clear the given region, \a rgn. + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your erasing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ +void QWidget::erase(const QRegion& rgn) +{ + if (testAttribute(Qt::WA_NoSystemBackground) || testAttribute(Qt::WA_UpdatesDisabled) || !testAttribute(Qt::WA_WState_Visible)) + return; + + QPainter p(this); + p.setClipRegion(rgn); + p.eraseRect(rgn.boundingRect()); +} + +void QWidget::drawText_helper(int x, int y, const QString &str) +{ + if(!testAttribute(Qt::WA_WState_Visible)) + return; + QPainter paint(this); + paint.drawText(x, y, str); +} + + +/*! + Closes the widget. + + Use the no-argument overload instead. +*/ +bool QWidget::close(bool alsoDelete) +{ + QPointer that = this; + bool accepted = close(); + if (alsoDelete && accepted && that) + deleteLater(); + return accepted; +} + +void QWidget::setIcon(const QPixmap &i) +{ + setWindowIcon(i); +} + +/*! + Return's the widget's icon. + + Use windowIcon() instead. +*/ +const QPixmap *QWidget::icon() const +{ + Q_D(const QWidget); + return (d->extra && d->extra->topextra) ? d->extra->topextra->iconPixmap : 0; +} + +#endif // QT3_SUPPORT + + /*! + \internal + + This just sets the corresponding attribute bit to 1 or 0 + */ +static void setAttribute_internal(Qt::WidgetAttribute attribute, bool on, QWidgetData *data, + QWidgetPrivate *d) +{ + if (attribute < int(8*sizeof(uint))) { + if (on) + data->widget_attributes |= (1<widget_attributes &= ~(1<high_attributes[int_off] |= (1<<(x-(int_off*8*sizeof(uint)))); + else + d->high_attributes[int_off] &= ~(1<<(x-(int_off*8*sizeof(uint)))); + } +} + +/*! + Sets the attribute \a attribute on this widget if \a on is true; + otherwise clears the attribute. + + \sa testAttribute() +*/ +void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) +{ + if (testAttribute(attribute) == on) + return; + + Q_D(QWidget); + Q_ASSERT_X(sizeof(d->high_attributes)*8 >= (Qt::WA_AttributeCount - sizeof(uint)*8), + "QWidget::setAttribute(WidgetAttribute, bool)", + "QWidgetPrivate::high_attributes[] too small to contain all attributes in WidgetAttribute"); +#ifdef Q_WS_WIN + // ### Don't use PaintOnScreen+paintEngine() to do native painting in 5.0 + if (attribute == Qt::WA_PaintOnScreen && on && !inherits("QGLWidget")) { + // see qwidget_win.cpp, ::paintEngine for details + paintEngine(); + if (d->noPaintOnScreen) + return; + } +#endif + + setAttribute_internal(attribute, on, data, d); + + switch (attribute) { + +#ifndef QT_NO_DRAGANDDROP + case Qt::WA_AcceptDrops: { + if (on && !testAttribute(Qt::WA_DropSiteRegistered)) + setAttribute(Qt::WA_DropSiteRegistered, true); + else if (!on && (isWindow() || !parentWidget() || !parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) + setAttribute(Qt::WA_DropSiteRegistered, false); + QEvent e(QEvent::AcceptDropsChange); + QApplication::sendEvent(this, &e); + break; + } + case Qt::WA_DropSiteRegistered: { + d->registerDropSite(on); + for (int i = 0; i < d->children.size(); ++i) { + QWidget *w = qobject_cast(d->children.at(i)); + if (w && !w->isWindow() && !w->testAttribute(Qt::WA_AcceptDrops) && w->testAttribute(Qt::WA_DropSiteRegistered) != on) + w->setAttribute(Qt::WA_DropSiteRegistered, on); + } + break; + } +#endif + + case Qt::WA_NoChildEventsForParent: + d->sendChildEvents = !on; + break; + case Qt::WA_NoChildEventsFromChildren: + d->receiveChildEvents = !on; + break; + case Qt::WA_MacBrushedMetal: +#ifdef Q_WS_MAC + d->setStyle_helper(style(), false, true); // Make sure things get unpolished/polished correctly. + // fall through since changing the metal attribute affects the opaque size grip. + case Qt::WA_MacOpaqueSizeGrip: + d->macUpdateOpaqueSizeGrip(); + break; + case Qt::WA_MacShowFocusRect: + if (hasFocus()) { + clearFocus(); + setFocus(); + } + break; + case Qt::WA_Hover: + qt_mac_update_mouseTracking(this); + break; +#endif + case Qt::WA_MacAlwaysShowToolWindow: +#ifdef Q_WS_MAC + d->macUpdateHideOnSuspend(); +#endif + break; + case Qt::WA_MacNormalSize: + case Qt::WA_MacSmallSize: + case Qt::WA_MacMiniSize: +#ifdef Q_WS_MAC + { + // We can only have one of these set at a time + const Qt::WidgetAttribute MacSizes[] = { Qt::WA_MacNormalSize, Qt::WA_MacSmallSize, + Qt::WA_MacMiniSize }; + for (int i = 0; i < 3; ++i) { + if (MacSizes[i] != attribute) + setAttribute_internal(MacSizes[i], false, data, d); + } + d->macUpdateSizeAttribute(); + } +#endif + break; + case Qt::WA_ShowModal: + if (!on) { + if (isVisible()) + QApplicationPrivate::leaveModal(this); + // reset modality type to Modeless when clearing WA_ShowModal + data->window_modality = Qt::NonModal; + } else if (data->window_modality == Qt::NonModal) { + // determine the modality type if it hasn't been set prior + // to setting WA_ShowModal. set the default to WindowModal + // if we are the child of a group leader; otherwise use + // ApplicationModal. + QWidget *w = parentWidget(); + if (w) + w = w->window(); + while (w && !w->testAttribute(Qt::WA_GroupLeader)) { + w = w->parentWidget(); + if (w) + w = w->window(); + } + data->window_modality = (w && w->testAttribute(Qt::WA_GroupLeader)) + ? Qt::WindowModal + : Qt::ApplicationModal; + // Some window managers does not allow us to enter modal after the + // window is showing. Therefore, to be consistent, we cannot call + // QApplicationPrivate::enterModal(this) here. The window must be + // hidden before changing modality. + } + if (testAttribute(Qt::WA_WState_Created)) { + // don't call setModal_sys() before create_sys() + d->setModal_sys(); + } + break; + case Qt::WA_MouseTracking: { + QEvent e(QEvent::MouseTrackingChange); + QApplication::sendEvent(this, &e); + break; } + case Qt::WA_NativeWindow: { +#if defined(Q_WS_QPA) + d->createTLExtra(); +#endif +#ifndef QT_NO_IM + QWidget *focusWidget = d->effectiveFocusWidget(); + QInputContext *ic = 0; + if (on && !internalWinId() && hasFocus() + && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { + ic = focusWidget->d_func()->inputContext(); + if (ic) { + ic->reset(); + ic->setFocusWidget(0); + } + } + if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget() +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + // On Mac, toolbars inside the unified title bar will never overlap with + // siblings in the content view. So we skip enforce native siblings in that case + && !d->isInUnifiedToolbar && parentWidget()->isWindow() +#endif // Q_WS_MAC && QT_MAC_USE_COCOA + ) + parentWidget()->d_func()->enforceNativeChildren(); + if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created)) + d->createWinId(); + if (ic && isEnabled() && focusWidget->isEnabled() + && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { + ic->setFocusWidget(focusWidget); + } +#endif //QT_NO_IM + break; + } + case Qt::WA_PaintOnScreen: + d->updateIsOpaque(); +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) + // Recreate the widget if it's already created as an alien widget and + // WA_PaintOnScreen is enabled. Paint on screen widgets must have win id. + // So must their children. + if (on) { + setAttribute(Qt::WA_NativeWindow); + d->enforceNativeChildren(); + } +#endif + // fall through + case Qt::WA_OpaquePaintEvent: + d->updateIsOpaque(); + break; + case Qt::WA_NoSystemBackground: + d->updateIsOpaque(); + // fall through... + case Qt::WA_UpdatesDisabled: + d->updateSystemBackground(); + break; + case Qt::WA_TransparentForMouseEvents: +#ifdef Q_WS_MAC + d->macUpdateIgnoreMouseEvents(); +#endif + break; + case Qt::WA_InputMethodEnabled: { +#ifndef QT_NO_IM + QWidget *focusWidget = d->effectiveFocusWidget(); + QInputContext *ic = focusWidget->d_func()->assignedInputContext(); + if (!ic && (!on || hasFocus())) + ic = focusWidget->d_func()->inputContext(); + if (ic) { + if (on && hasFocus() && ic->focusWidget() != focusWidget && isEnabled() + && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { + ic->setFocusWidget(focusWidget); + } else if (!on && ic->focusWidget() == focusWidget) { + ic->reset(); + ic->setFocusWidget(0); + } + } +#endif //QT_NO_IM + break; + } + case Qt::WA_WindowPropagation: + d->resolvePalette(); + d->resolveFont(); + d->resolveLocale(); + break; +#ifdef Q_WS_X11 + case Qt::WA_NoX11EventCompression: + if (!d->extra) + d->createExtra(); + d->extra->compress_events = on; + break; + case Qt::WA_X11OpenGLOverlay: + d->updateIsOpaque(); + break; + case Qt::WA_X11DoNotAcceptFocus: + if (testAttribute(Qt::WA_WState_Created)) + d->updateX11AcceptFocus(); + break; +#endif + case Qt::WA_DontShowOnScreen: { + if (on && isVisible()) { + // Make sure we keep the current state and only hide the widget + // from the desktop. show_sys will only update platform specific + // attributes at this point. + d->hide_sys(); +#ifdef Q_WS_QWS + // Release the region for this window from qws if the widget has + // been shown before the attribute was set. + if (QWSWindowSurface *surface = static_cast(windowSurface())) { + QWidget::qwsDisplay()->requestRegion(surface->winId(), surface->key(), + surface->permanentState(), QRegion()); + } +#endif + d->show_sys(); + } + break; + } + +#ifdef Q_WS_X11 + case Qt::WA_X11NetWmWindowTypeDesktop: + case Qt::WA_X11NetWmWindowTypeDock: + case Qt::WA_X11NetWmWindowTypeToolBar: + case Qt::WA_X11NetWmWindowTypeMenu: + case Qt::WA_X11NetWmWindowTypeUtility: + case Qt::WA_X11NetWmWindowTypeSplash: + case Qt::WA_X11NetWmWindowTypeDialog: + case Qt::WA_X11NetWmWindowTypeDropDownMenu: + case Qt::WA_X11NetWmWindowTypePopupMenu: + case Qt::WA_X11NetWmWindowTypeToolTip: + case Qt::WA_X11NetWmWindowTypeNotification: + case Qt::WA_X11NetWmWindowTypeCombo: + case Qt::WA_X11NetWmWindowTypeDND: + if (testAttribute(Qt::WA_WState_Created)) + d->setNetWmWindowTypes(); + break; +#endif + + case Qt::WA_StaticContents: + if (QWidgetBackingStore *bs = d->maybeBackingStore()) { + if (on) + bs->addStaticWidget(this); + else + bs->removeStaticWidget(this); + } + break; + case Qt::WA_TranslucentBackground: + if (on) { + setAttribute(Qt::WA_NoSystemBackground); + d->updateIsTranslucent(); + } + + break; + case Qt::WA_AcceptTouchEvents: +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) + if (on) + d->registerTouchWindow(); +#endif + break; + case Qt::WA_LockPortraitOrientation: + case Qt::WA_LockLandscapeOrientation: + case Qt::WA_AutoOrientation: { + const Qt::WidgetAttribute orientations[3] = { + Qt::WA_LockPortraitOrientation, + Qt::WA_LockLandscapeOrientation, + Qt::WA_AutoOrientation + }; + + if (on) { + // We can only have one of these set at a time + for (int i = 0; i < 3; ++i) { + if (orientations[i] != attribute) + setAttribute_internal(orientations[i], false, data, d); + } + } + +#ifdef Q_WS_S60 + CAknAppUiBase* appUi = static_cast(CEikonEnv::Static()->EikAppUi()); + const CAknAppUiBase::TAppUiOrientation s60orientations[] = { + CAknAppUiBase::EAppUiOrientationPortrait, + CAknAppUiBase::EAppUiOrientationLandscape, + CAknAppUiBase::EAppUiOrientationAutomatic + }; + CAknAppUiBase::TAppUiOrientation s60orientation = CAknAppUiBase::EAppUiOrientationUnspecified; + for (int i = 0; i < 3; ++i) { + if (testAttribute(orientations[i])) { + s60orientation = s60orientations[i]; + break; + } + } + QT_TRAP_THROWING(appUi->SetOrientationL(s60orientation)); + S60->orientationSet = true; + QSymbianControl *window = static_cast(internalWinId()); + if (window) + window->ensureFixNativeOrientation(); +#endif + break; + } + default: + break; + } +} + +/*! \fn bool QWidget::testAttribute(Qt::WidgetAttribute attribute) const + + Returns true if attribute \a attribute is set on this widget; + otherwise returns false. + + \sa setAttribute() + */ +bool QWidget::testAttribute_helper(Qt::WidgetAttribute attribute) const +{ + Q_D(const QWidget); + const int x = attribute - 8*sizeof(uint); + const int int_off = x / (8*sizeof(uint)); + return (d->high_attributes[int_off] & (1<<(x-(int_off*8*sizeof(uint))))); +} + +/*! + \property QWidget::windowOpacity + + \brief The level of opacity for the window. + + The valid range of opacity is from 1.0 (completely opaque) to + 0.0 (completely transparent). + + By default the value of this property is 1.0. + + This feature is available on Embedded Linux, Mac OS X, Windows, + and X11 platforms that support the Composite extension. + + This feature is not available on Windows CE. + + Note that under X11 you need to have a composite manager running, + and the X11 specific _NET_WM_WINDOW_OPACITY atom needs to be + supported by the window manager you are using. + + \warning Changing this property from opaque to transparent might issue a + paint event that needs to be processed before the window is displayed + correctly. This affects mainly the use of QPixmap::grabWindow(). Also note + that semi-transparent windows update and resize significantly slower than + opaque windows. + + \sa setMask() +*/ +qreal QWidget::windowOpacity() const +{ + Q_D(const QWidget); + return (isWindow() && d->maybeTopData()) ? d->maybeTopData()->opacity / 255. : 1.0; +} + +void QWidget::setWindowOpacity(qreal opacity) +{ + Q_D(QWidget); + if (!isWindow()) + return; + + opacity = qBound(qreal(0.0), opacity, qreal(1.0)); + QTLWExtra *extra = d->topData(); + extra->opacity = uint(opacity * 255); + setAttribute(Qt::WA_WState_WindowOpacitySet); + +#ifndef Q_WS_QWS + if (!testAttribute(Qt::WA_WState_Created)) + return; +#endif + +#ifndef QT_NO_GRAPHICSVIEW + if (QGraphicsProxyWidget *proxy = graphicsProxyWidget()) { + // Avoid invalidating the cache if set. + if (proxy->cacheMode() == QGraphicsItem::NoCache) + proxy->update(); + else if (QGraphicsScene *scene = proxy->scene()) + scene->update(proxy->sceneBoundingRect()); + return; + } +#endif + + d->setWindowOpacity_sys(opacity); +} + +/*! + \property QWidget::windowModified + \brief whether the document shown in the window has unsaved changes + + A modified window is a window whose content has changed but has + not been saved to disk. This flag will have different effects + varied by the platform. On Mac OS X the close button will have a + modified look; on other platforms, the window title will have an + '*' (asterisk). + + The window title must contain a "[*]" placeholder, which + indicates where the '*' should appear. Normally, it should appear + right after the file name (e.g., "document1.txt[*] - Text + Editor"). If the window isn't modified, the placeholder is simply + removed. + + Note that if a widget is set as modified, all its ancestors will + also be set as modified. However, if you call \c + {setWindowModified(false)} on a widget, this will not propagate to + its parent because other children of the parent might have been + modified. + + \sa windowTitle, {Application Example}, {SDI Example}, {MDI Example} +*/ +bool QWidget::isWindowModified() const +{ + return testAttribute(Qt::WA_WindowModified); +} + +void QWidget::setWindowModified(bool mod) +{ + Q_D(QWidget); + setAttribute(Qt::WA_WindowModified, mod); + +#ifndef Q_WS_MAC + if (!windowTitle().contains(QLatin1String("[*]")) && mod) + qWarning("QWidget::setWindowModified: The window title does not contain a '[*]' placeholder"); +#endif + d->setWindowTitle_helper(windowTitle()); + d->setWindowIconText_helper(windowIconText()); +#ifdef Q_WS_MAC + d->setWindowModified_sys(mod); +#endif + + QEvent e(QEvent::ModifiedChange); + QApplication::sendEvent(this, &e); +} + +#ifndef QT_NO_TOOLTIP +/*! + \property QWidget::toolTip + + \brief the widget's tooltip + + Note that by default tooltips are only shown for widgets that are + children of the active window. You can change this behavior by + setting the attribute Qt::WA_AlwaysShowToolTips on the \e window, + not on the widget with the tooltip. + + If you want to control a tooltip's behavior, you can intercept the + event() function and catch the QEvent::ToolTip event (e.g., if you + want to customize the area for which the tooltip should be shown). + + By default, this property contains an empty string. + + \sa QToolTip statusTip whatsThis +*/ +void QWidget::setToolTip(const QString &s) +{ + Q_D(QWidget); + d->toolTip = s; + + QEvent event(QEvent::ToolTipChange); + QApplication::sendEvent(this, &event); +} + +QString QWidget::toolTip() const +{ + Q_D(const QWidget); + return d->toolTip; +} +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP +/*! + \property QWidget::statusTip + \brief the widget's status tip + + By default, this property contains an empty string. + + \sa toolTip whatsThis +*/ +void QWidget::setStatusTip(const QString &s) +{ + Q_D(QWidget); + d->statusTip = s; +} + +QString QWidget::statusTip() const +{ + Q_D(const QWidget); + return d->statusTip; +} +#endif // QT_NO_STATUSTIP + +#ifndef QT_NO_WHATSTHIS +/*! + \property QWidget::whatsThis + + \brief the widget's What's This help text. + + By default, this property contains an empty string. + + \sa QWhatsThis QWidget::toolTip QWidget::statusTip +*/ +void QWidget::setWhatsThis(const QString &s) +{ + Q_D(QWidget); + d->whatsThis = s; +} + +QString QWidget::whatsThis() const +{ + Q_D(const QWidget); + return d->whatsThis; +} +#endif // QT_NO_WHATSTHIS + +#ifndef QT_NO_ACCESSIBILITY +/*! + \property QWidget::accessibleName + + \brief the widget's name as seen by assistive technologies + + This property is used by accessible clients to identify, find, or announce + the widget for accessible clients. + + By default, this property contains an empty string. + + \sa QAccessibleInterface::text() +*/ +void QWidget::setAccessibleName(const QString &name) +{ + Q_D(QWidget); + d->accessibleName = name; +} + +QString QWidget::accessibleName() const +{ + Q_D(const QWidget); + return d->accessibleName; +} + +/*! + \property QWidget::accessibleDescription + + \brief the widget's description as seen by assistive technologies + + By default, this property contains an empty string. + + \sa QAccessibleInterface::text() +*/ +void QWidget::setAccessibleDescription(const QString &description) +{ + Q_D(QWidget); + d->accessibleDescription = description; +} + +QString QWidget::accessibleDescription() const +{ + Q_D(const QWidget); + return d->accessibleDescription; +} +#endif // QT_NO_ACCESSIBILITY + +#ifndef QT_NO_SHORTCUT +/*! + Adds a shortcut to Qt's shortcut system that watches for the given + \a key sequence in the given \a context. If the \a context is + Qt::ApplicationShortcut, the shortcut applies to the application as a + whole. Otherwise, it is either local to this widget, Qt::WidgetShortcut, + or to the window itself, Qt::WindowShortcut. + + If the same \a key sequence has been grabbed by several widgets, + when the \a key sequence occurs a QEvent::Shortcut event is sent + to all the widgets to which it applies in a non-deterministic + order, but with the ``ambiguous'' flag set to true. + + \warning You should not normally need to use this function; + instead create \l{QAction}s with the shortcut key sequences you + require (if you also want equivalent menu options and toolbar + buttons), or create \l{QShortcut}s if you just need key sequences. + Both QAction and QShortcut handle all the event filtering for you, + and provide signals which are triggered when the user triggers the + key sequence, so are much easier to use than this low-level + function. + + \sa releaseShortcut() setShortcutEnabled() +*/ +int QWidget::grabShortcut(const QKeySequence &key, Qt::ShortcutContext context) +{ + Q_ASSERT(qApp); + if (key.isEmpty()) + return 0; + setAttribute(Qt::WA_GrabbedShortcut); + return qApp->d_func()->shortcutMap.addShortcut(this, key, context); +} + +/*! + Removes the shortcut with the given \a id from Qt's shortcut + system. The widget will no longer receive QEvent::Shortcut events + for the shortcut's key sequence (unless it has other shortcuts + with the same key sequence). + + \warning You should not normally need to use this function since + Qt's shortcut system removes shortcuts automatically when their + parent widget is destroyed. It is best to use QAction or + QShortcut to handle shortcuts, since they are easier to use than + this low-level function. Note also that this is an expensive + operation. + + \sa grabShortcut() setShortcutEnabled() +*/ +void QWidget::releaseShortcut(int id) +{ + Q_ASSERT(qApp); + if (id) + qApp->d_func()->shortcutMap.removeShortcut(id, this, 0); +} + +/*! + If \a enable is true, the shortcut with the given \a id is + enabled; otherwise the shortcut is disabled. + + \warning You should not normally need to use this function since + Qt's shortcut system enables/disables shortcuts automatically as + widgets become hidden/visible and gain or lose focus. It is best + to use QAction or QShortcut to handle shortcuts, since they are + easier to use than this low-level function. + + \sa grabShortcut() releaseShortcut() +*/ +void QWidget::setShortcutEnabled(int id, bool enable) +{ + Q_ASSERT(qApp); + if (id) + qApp->d_func()->shortcutMap.setShortcutEnabled(enable, id, this, 0); +} + +/*! + \since 4.2 + + If \a enable is true, auto repeat of the shortcut with the + given \a id is enabled; otherwise it is disabled. + + \sa grabShortcut() releaseShortcut() +*/ +void QWidget::setShortcutAutoRepeat(int id, bool enable) +{ + Q_ASSERT(qApp); + if (id) + qApp->d_func()->shortcutMap.setShortcutAutoRepeat(enable, id, this, 0); +} +#endif // QT_NO_SHORTCUT +/*! + Updates the widget's micro focus. + + \sa QInputContext +*/ +void QWidget::updateMicroFocus() +{ +#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) + Q_D(QWidget); + // and optimization to update input context only it has already been created. + if (d->assignedInputContext() || qApp->d_func()->inputContext) { + QInputContext *ic = inputContext(); + if (ic) + ic->update(); + } +#endif +#ifndef QT_NO_ACCESSIBILITY + // ##### is this correct + QAccessible::updateAccessibility(this, 0, QAccessible::StateChanged); +#endif +} + + +#if defined (Q_WS_WIN) +/*! + Returns the window system handle of the widget, for low-level + access. Using this function is not portable. + + An HDC acquired with getDC() has to be released with releaseDC(). + + \warning Using this function is not portable. +*/ +HDC QWidget::getDC() const +{ + Q_D(const QWidget); + if (d->hd) + return (HDC) d->hd; + return GetDC(winId()); +} + +/*! + Releases the HDC \a hdc acquired by a previous call to getDC(). + + \warning Using this function is not portable. +*/ +void QWidget::releaseDC(HDC hdc) const +{ + Q_D(const QWidget); + // If its the widgets own dc, it will be released elsewhere. If + // its a different HDC we release it and issue a warning if it + // fails. + if (hdc != d->hd && !ReleaseDC(winId(), hdc)) + qErrnoWarning("QWidget::releaseDC(): failed to release HDC"); +} +#else +/*! + Returns the window system handle of the widget, for low-level + access. Using this function is not portable. + + The HANDLE type varies with platform; see \c qwindowdefs.h for + details. +*/ +Qt::HANDLE QWidget::handle() const +{ + Q_D(const QWidget); + if (!internalWinId() && testAttribute(Qt::WA_WState_Created)) + (void)winId(); // enforce native window + return d->hd; +} +#endif + + +/*! + Raises this widget to the top of the parent widget's stack. + + After this call the widget will be visually in front of any + overlapping sibling widgets. + + \note When using activateWindow(), you can call this function to + ensure that the window is stacked on top. + + \sa lower(), stackUnder() +*/ + +void QWidget::raise() +{ + Q_D(QWidget); + if (!isWindow()) { + QWidget *p = parentWidget(); + const int parentChildCount = p->d_func()->children.size(); + if (parentChildCount < 2) + return; + const int from = p->d_func()->children.indexOf(this); + Q_ASSERT(from >= 0); + // Do nothing if the widget is already in correct stacking order _and_ created. + if (from != parentChildCount -1) + p->d_func()->children.move(from, parentChildCount - 1); + if (!testAttribute(Qt::WA_WState_Created) && p->testAttribute(Qt::WA_WState_Created)) + create(); + else if (from == parentChildCount - 1) + return; + + QRegion region(rect()); + d->subtractOpaqueSiblings(region); + d->invalidateBuffer(region); + } + if (testAttribute(Qt::WA_WState_Created)) + d->raise_sys(); + + QEvent e(QEvent::ZOrderChange); + QApplication::sendEvent(this, &e); +} + +/*! + Lowers the widget to the bottom of the parent widget's stack. + + After this call the widget will be visually behind (and therefore + obscured by) any overlapping sibling widgets. + + \sa raise(), stackUnder() +*/ + +void QWidget::lower() +{ + Q_D(QWidget); + if (!isWindow()) { + QWidget *p = parentWidget(); + const int parentChildCount = p->d_func()->children.size(); + if (parentChildCount < 2) + return; + const int from = p->d_func()->children.indexOf(this); + Q_ASSERT(from >= 0); + // Do nothing if the widget is already in correct stacking order _and_ created. + if (from != 0) + p->d_func()->children.move(from, 0); + if (!testAttribute(Qt::WA_WState_Created) && p->testAttribute(Qt::WA_WState_Created)) + create(); + else if (from == 0) + return; + } + if (testAttribute(Qt::WA_WState_Created)) + d->lower_sys(); + + QEvent e(QEvent::ZOrderChange); + QApplication::sendEvent(this, &e); +} + + +/*! + Places the widget under \a w in the parent widget's stack. + + To make this work, the widget itself and \a w must be siblings. + + \sa raise(), lower() +*/ +void QWidget::stackUnder(QWidget* w) +{ + Q_D(QWidget); + QWidget *p = parentWidget(); + if (!w || isWindow() || p != w->parentWidget() || this == w) + return; + if (p) { + int from = p->d_func()->children.indexOf(this); + int to = p->d_func()->children.indexOf(w); + Q_ASSERT(from >= 0); + Q_ASSERT(to >= 0); + if (from < to) + --to; + // Do nothing if the widget is already in correct stacking order _and_ created. + if (from != to) + p->d_func()->children.move(from, to); + if (!testAttribute(Qt::WA_WState_Created) && p->testAttribute(Qt::WA_WState_Created)) + create(); + else if (from == to) + return; + } + if (testAttribute(Qt::WA_WState_Created)) + d->stackUnder_sys(w); + + QEvent e(QEvent::ZOrderChange); + QApplication::sendEvent(this, &e); +} + +void QWidget::styleChange(QStyle&) { } +void QWidget::enabledChange(bool) { } // compat +void QWidget::paletteChange(const QPalette &) { } // compat +void QWidget::fontChange(const QFont &) { } // compat +void QWidget::windowActivationChange(bool) { } // compat +void QWidget::languageChange() { } // compat + + +/*! + \enum QWidget::BackgroundOrigin + + \compat + + \value WidgetOrigin + \value ParentOrigin + \value WindowOrigin + \value AncestorOrigin + +*/ + +/*! + \fn bool QWidget::isVisibleToTLW() const + + Use isVisible() instead. +*/ + +/*! + \fn void QWidget::iconify() + + Use showMinimized() instead. +*/ + +/*! + \fn void QWidget::constPolish() const + + Use ensurePolished() instead. +*/ + +/*! + \fn void QWidget::reparent(QWidget *parent, Qt::WindowFlags f, const QPoint &p, bool showIt) + + Use setParent() to change the parent or the widget's widget flags; + use move() to move the widget, and use show() to show the widget. +*/ + +/*! + \fn void QWidget::reparent(QWidget *parent, const QPoint &p, bool showIt) + + Use setParent() to change the parent; use move() to move the + widget, and use show() to show the widget. +*/ + +/*! + \fn void QWidget::recreate(QWidget *parent, Qt::WindowFlags f, const QPoint & p, bool showIt) + + Use setParent() to change the parent or the widget's widget flags; + use move() to move the widget, and use show() to show the widget. +*/ + +/*! + \fn bool QWidget::hasMouse() const + + Use testAttribute(Qt::WA_UnderMouse) instead. +*/ + +/*! + \fn bool QWidget::ownCursor() const + + Use testAttribute(Qt::WA_SetCursor) instead. +*/ + +/*! + \fn bool QWidget::ownFont() const + + Use testAttribute(Qt::WA_SetFont) instead. +*/ + +/*! + \fn void QWidget::unsetFont() + + Use setFont(QFont()) instead. +*/ + +/*! + \fn bool QWidget::ownPalette() const + + Use testAttribute(Qt::WA_SetPalette) instead. +*/ + +/*! + \fn void QWidget::unsetPalette() + + Use setPalette(QPalette()) instead. +*/ + +/*! + \fn void QWidget::setEraseColor(const QColor &color) + + Use the palette instead. + + \oldcode + widget->setEraseColor(color); + \newcode + QPalette palette; + palette.setColor(widget->backgroundRole(), color); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setErasePixmap(const QPixmap &pixmap) + + Use the palette instead. + + \oldcode + widget->setErasePixmap(pixmap); + \newcode + QPalette palette; + palette.setBrush(widget->backgroundRole(), QBrush(pixmap)); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setPaletteForegroundColor(const QColor &color) + + Use the palette directly. + + \oldcode + widget->setPaletteForegroundColor(color); + \newcode + QPalette palette; + palette.setColor(widget->foregroundRole(), color); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setPaletteBackgroundColor(const QColor &color) + + Use the palette directly. + + \oldcode + widget->setPaletteBackgroundColor(color); + \newcode + QPalette palette; + palette.setColor(widget->backgroundRole(), color); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setPaletteBackgroundPixmap(const QPixmap &pixmap) + + Use the palette directly. + + \oldcode + widget->setPaletteBackgroundPixmap(pixmap); + \newcode + QPalette palette; + palette.setBrush(widget->backgroundRole(), QBrush(pixmap)); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setBackgroundPixmap(const QPixmap &pixmap) + + Use the palette instead. + + \oldcode + widget->setBackgroundPixmap(pixmap); + \newcode + QPalette palette; + palette.setBrush(widget->backgroundRole(), QBrush(pixmap)); + widget->setPalette(palette); + \endcode +*/ + +/*! + \fn void QWidget::setBackgroundColor(const QColor &color) + + Use the palette instead. + + \oldcode + widget->setBackgroundColor(color); + \newcode + QPalette palette; + palette.setColor(widget->backgroundRole(), color); + widget->setPalette(palette); + \endcode +*/ + + +/*! + \fn QWidget *QWidget::parentWidget(bool sameWindow) const + + Use the no-argument overload instead. +*/ + +/*! + \fn void QWidget::setKeyCompression(bool b) + + Use setAttribute(Qt::WA_KeyCompression, b) instead. +*/ + +/*! + \fn void QWidget::setFont(const QFont &f, bool b) + + Use the single-argument overload instead. +*/ + +/*! + \fn void QWidget::setPalette(const QPalette &p, bool b) + + Use the single-argument overload instead. +*/ + +/*! + \fn void QWidget::setBackgroundOrigin(BackgroundOrigin background) + + \obsolete +*/ + +/*! + \fn BackgroundOrigin QWidget::backgroundOrigin() const + + \obsolete + + Always returns \c WindowOrigin. +*/ + +/*! + \fn QPoint QWidget::backgroundOffset() const + + \obsolete + + Always returns QPoint(). +*/ + +/*! + \fn void QWidget::repaint(bool b) + + The boolean parameter \a b is ignored. Use the no-argument overload instead. +*/ + +/*! + \fn void QWidget::repaint(int x, int y, int w, int h, bool b) + + The boolean parameter \a b is ignored. Use the four-argument overload instead. +*/ + +/*! + \fn void QWidget::repaint(const QRect &r, bool b) + + The boolean parameter \a b is ignored. Use the single rect-argument overload instead. +*/ + +/*! + \fn void QWidget::repaint(const QRegion &rgn, bool b) + + The boolean parameter \a b is ignored. Use the single region-argument overload instead. +*/ + +/*! + \fn void QWidget::erase() + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your erasing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ + +/*! + \fn void QWidget::erase(int x, int y, int w, int h) + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your erasing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ + +/*! + \fn void QWidget::erase(const QRect &rect) + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your erasing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ + +/*! + \fn void QWidget::drawText(const QPoint &p, const QString &s) + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your drawing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ + +/*! + \fn void QWidget::drawText(int x, int y, const QString &s) + + Drawing may only take place in a QPaintEvent. Overload + paintEvent() to do your drawing and call update() to schedule a + replaint whenever necessary. See also QPainter. +*/ + +/*! + \fn QWidget *QWidget::childAt(const QPoint &p, bool includeThis) const + + Use the single point argument overload instead. +*/ + +/*! + \fn void QWidget::setCaption(const QString &c) + + Use setWindowTitle() instead. +*/ + +/*! + \fn void QWidget::setIcon(const QPixmap &i) + + Use setWindowIcon() instead. +*/ + +/*! + \fn void QWidget::setIconText(const QString &it) + + Use setWindowIconText() instead. +*/ + +/*! + \fn QString QWidget::caption() const + + Use windowTitle() instead. +*/ + +/*! + \fn QString QWidget::iconText() const + + Use windowIconText() instead. +*/ + +/*! + \fn bool QWidget::isTopLevel() const + \obsolete + + Use isWindow() instead. +*/ + +/*! + \fn bool QWidget::isRightToLeft() const + \internal +*/ + +/*! + \fn bool QWidget::isLeftToRight() const + \internal +*/ + +/*! + \fn void QWidget::setInputMethodEnabled(bool enabled) + + Use setAttribute(Qt::WA_InputMethodEnabled, \a enabled) instead. +*/ + +/*! + \fn bool QWidget::isInputMethodEnabled() const + + Use testAttribute(Qt::WA_InputMethodEnabled) instead. +*/ + +/*! + \fn void QWidget::setActiveWindow() + + Use activateWindow() instead. +*/ + +/*! + \fn bool QWidget::isShown() const + + Use !isHidden() instead (notice the exclamation mark), or use isVisible() to check whether the widget is visible. +*/ + +/*! + \fn bool QWidget::isDialog() const + + Use windowType() == Qt::Dialog instead. +*/ + +/*! + \fn bool QWidget::isPopup() const + + Use windowType() == Qt::Popup instead. +*/ + +/*! + \fn bool QWidget::isDesktop() const + + Use windowType() == Qt::Desktop instead. +*/ + +/*! + \fn void QWidget::polish() + + Use ensurePolished() instead. +*/ + +/*! + \fn QWidget *QWidget::childAt(int x, int y, bool includeThis) const + + Use the childAt() overload that doesn't have an \a includeThis parameter. + + \oldcode + return widget->childAt(x, y, true); + \newcode + QWidget *child = widget->childAt(x, y, true); + if (child) + return child; + if (widget->rect().contains(x, y)) + return widget; + \endcode +*/ + +/*! + \fn void QWidget::setSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver, bool hfw) + \compat + + Use the \l sizePolicy property and heightForWidth() function instead. +*/ + +/*! + \fn bool QWidget::isUpdatesEnabled() const + \compat + + Use the \l updatesEnabled property instead. +*/ + +/*! + \macro QWIDGETSIZE_MAX + \relates QWidget + + Defines the maximum size for a QWidget object. + + The largest allowed size for a widget is QSize(QWIDGETSIZE_MAX, + QWIDGETSIZE_MAX), i.e. QSize (16777215,16777215). + + \sa QWidget::setMaximumSize() +*/ + +/*! + \fn QWidget::setupUi(QWidget *widget) + + Sets up the user interface for the specified \a widget. + + \note This function is available with widgets that derive from user + interface descriptions created using \l{uic}. + + \sa {Using a Designer UI File in Your Application} +*/ + +QRect QWidgetPrivate::frameStrut() const +{ + Q_Q(const QWidget); + if (!q->isWindow() || (q->windowType() == Qt::Desktop) || q->testAttribute(Qt::WA_DontShowOnScreen)) { + // x2 = x1 + w - 1, so w/h = 1 + return QRect(0, 0, 1, 1); + } + + if (data.fstrut_dirty +#ifndef Q_WS_WIN + // ### Fix properly for 4.3 + && q->isVisible() +#endif + && q->testAttribute(Qt::WA_WState_Created)) + const_cast(this)->updateFrameStrut(); + + return maybeTopData() ? maybeTopData()->frameStrut : QRect(); +} + +#ifdef QT_KEYPAD_NAVIGATION +/*! + \internal + + Changes the focus from the current focusWidget to a widget in + the \a direction. + + Returns true, if there was a widget in that direction +*/ +bool QWidgetPrivate::navigateToDirection(Direction direction) +{ + QWidget *targetWidget = widgetInNavigationDirection(direction); + if (targetWidget) + targetWidget->setFocus(); + return (targetWidget != 0); +} + +/*! + \internal + + Searches for a widget that is positioned in the \a direction, starting + from the current focusWidget. + + Returns the pointer to a found widget or 0, if there was no widget in + that direction. +*/ +QWidget *QWidgetPrivate::widgetInNavigationDirection(Direction direction) +{ + const QWidget *sourceWidget = QApplication::focusWidget(); + if (!sourceWidget) + return 0; + const QRect sourceRect = sourceWidget->rect().translated(sourceWidget->mapToGlobal(QPoint())); + const int sourceX = + (direction == DirectionNorth || direction == DirectionSouth) ? + (sourceRect.left() + (sourceRect.right() - sourceRect.left()) / 2) + :(direction == DirectionEast ? sourceRect.right() : sourceRect.left()); + const int sourceY = + (direction == DirectionEast || direction == DirectionWest) ? + (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2) + :(direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top()); + const QPoint sourcePoint(sourceX, sourceY); + const QPoint sourceCenter = sourceRect.center(); + const QWidget *sourceWindow = sourceWidget->window(); + + QWidget *targetWidget = 0; + int shortestDistance = INT_MAX; + foreach(QWidget *targetCandidate, QApplication::allWidgets()) { + + const QRect targetCandidateRect = targetCandidate->rect().translated(targetCandidate->mapToGlobal(QPoint())); + + // For focus proxies, the child widget handling the focus can have keypad navigation focus, + // but the owner of the proxy cannot. + // Additionally, empty widgets should be ignored. + if (targetCandidate->focusProxy() || targetCandidateRect.isEmpty()) + continue; + + // Only navigate to a target widget that... + if ( targetCandidate != sourceWidget + // ...takes the focus, + && targetCandidate->focusPolicy() & Qt::TabFocus + // ...is above if DirectionNorth, + && !(direction == DirectionNorth && targetCandidateRect.bottom() > sourceRect.top()) + // ...is on the right if DirectionEast, + && !(direction == DirectionEast && targetCandidateRect.left() < sourceRect.right()) + // ...is below if DirectionSouth, + && !(direction == DirectionSouth && targetCandidateRect.top() < sourceRect.bottom()) + // ...is on the left if DirectionWest, + && !(direction == DirectionWest && targetCandidateRect.right() > sourceRect.left()) + // ...is enabled, + && targetCandidate->isEnabled() + // ...is visible, + && targetCandidate->isVisible() + // ...is in the same window, + && targetCandidate->window() == sourceWindow) { + const int targetCandidateDistance = pointToRect(sourcePoint, targetCandidateRect); + if (targetCandidateDistance < shortestDistance) { + shortestDistance = targetCandidateDistance; + targetWidget = targetCandidate; + } + } + } + return targetWidget; +} + +/*! + \internal + + Tells us if it there is currently a reachable widget by keypad navigation in + a certain \a orientation. + If no navigation is possible, occurring key events in that \a orientation may + be used to interact with the value in the focused widget, even though it + currently has not the editFocus. + + \sa QWidgetPrivate::widgetInNavigationDirection(), QWidget::hasEditFocus() +*/ +bool QWidgetPrivate::canKeypadNavigate(Qt::Orientation orientation) +{ + return orientation == Qt::Horizontal? + (QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionEast) + || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionWest)) + :(QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionNorth) + || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionSouth)); +} +/*! + \internal + + Checks, if the \a widget is inside a QTabWidget. If is is inside + one, left/right key events will be used to switch between tabs in keypad + navigation. If there is no QTabWidget, the horizontal key events can be used +to + interact with the value in the focused widget, even though it currently has + not the editFocus. + + \sa QWidget::hasEditFocus() +*/ +bool QWidgetPrivate::inTabWidget(QWidget *widget) +{ + for (QWidget *tabWidget = widget; tabWidget; tabWidget = tabWidget->parentWidget()) + if (qobject_cast(tabWidget)) + return true; + return false; +} +#endif + +/*! + \preliminary + \since 4.2 + \obsolete + + Sets the window surface to be the \a surface specified. + The QWidget takes will ownership of the \a surface. + widget itself is deleted. +*/ +void QWidget::setWindowSurface(QWindowSurface *surface) +{ + // ### createWinId() ?? + +#ifndef Q_BACKINGSTORE_SUBSURFACES + if (!isTopLevel()) + return; +#endif + + Q_D(QWidget); + + QTLWExtra *topData = d->topData(); + if (topData->windowSurface == surface) + return; + + QWindowSurface *oldSurface = topData->windowSurface; + delete topData->windowSurface; + topData->windowSurface = surface; + + QWidgetBackingStore *bs = d->maybeBackingStore(); + if (!bs) + return; + + if (isTopLevel()) { + if (bs->windowSurface != oldSurface && bs->windowSurface != surface) + delete bs->windowSurface; + bs->windowSurface = surface; + } +#ifdef Q_BACKINGSTORE_SUBSURFACES + else { + bs->subSurfaces.append(surface); + } + bs->subSurfaces.removeOne(oldSurface); +#endif +} + +/*! + \preliminary + \since 4.2 + + Returns the QWindowSurface this widget will be drawn into. +*/ +QWindowSurface *QWidget::windowSurface() const +{ + Q_D(const QWidget); + QTLWExtra *extra = d->maybeTopData(); + if (extra && extra->windowSurface) + return extra->windowSurface; + + QWidgetBackingStore *bs = d->maybeBackingStore(); + +#ifdef Q_BACKINGSTORE_SUBSURFACES + if (bs && bs->subSurfaces.isEmpty()) + return bs->windowSurface; + + if (!isTopLevel()) { + const QWidget *w = parentWidget(); + while (w) { + QTLWExtra *extra = w->d_func()->maybeTopData(); + if (extra && extra->windowSurface) + return extra->windowSurface; + if (w->isTopLevel()) + break; + w = w->parentWidget(); + } + } +#endif // Q_BACKINGSTORE_SUBSURFACES + + return bs ? bs->windowSurface : 0; +} + +void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const +{ + if (left) + *left = (int)leftLayoutItemMargin; + if (top) + *top = (int)topLayoutItemMargin; + if (right) + *right = (int)rightLayoutItemMargin; + if (bottom) + *bottom = (int)bottomLayoutItemMargin; +} + +void QWidgetPrivate::setLayoutItemMargins(int left, int top, int right, int bottom) +{ + if (leftLayoutItemMargin == left + && topLayoutItemMargin == top + && rightLayoutItemMargin == right + && bottomLayoutItemMargin == bottom) + return; + + Q_Q(QWidget); + leftLayoutItemMargin = (signed char)left; + topLayoutItemMargin = (signed char)top; + rightLayoutItemMargin = (signed char)right; + bottomLayoutItemMargin = (signed char)bottom; + q->updateGeometry(); +} + +void QWidgetPrivate::setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt) +{ + Q_Q(QWidget); + QStyleOption myOpt; + if (!opt) { + myOpt.initFrom(q); + myOpt.rect.setRect(0, 0, 32768, 32768); // arbitrary + opt = &myOpt; + } + + QRect liRect = q->style()->subElementRect(element, opt, q); + if (liRect.isValid()) { + leftLayoutItemMargin = (signed char)(opt->rect.left() - liRect.left()); + topLayoutItemMargin = (signed char)(opt->rect.top() - liRect.top()); + rightLayoutItemMargin = (signed char)(liRect.right() - opt->rect.right()); + bottomLayoutItemMargin = (signed char)(liRect.bottom() - opt->rect.bottom()); + } else { + leftLayoutItemMargin = 0; + topLayoutItemMargin = 0; + rightLayoutItemMargin = 0; + bottomLayoutItemMargin = 0; + } +} +// resets the Qt::WA_QuitOnClose attribute to the default value for transient widgets. +void QWidgetPrivate::adjustQuitOnCloseAttribute() +{ + Q_Q(QWidget); + + if (!q->parentWidget()) { + Qt::WindowType type = q->windowType(); + if (type == Qt::Widget || type == Qt::SubWindow) + type = Qt::Window; + if (type != Qt::Widget && type != Qt::Window && type != Qt::Dialog) + q->setAttribute(Qt::WA_QuitOnClose, false); + } +} + + + +Q_GUI_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget) +{ + return widget->data; +} + +Q_GUI_EXPORT QWidgetPrivate *qt_widget_private(QWidget *widget) +{ + return widget->d_func(); +} + + +#ifndef QT_NO_GRAPHICSVIEW +/*! + \since 4.5 + + Returns the proxy widget for the corresponding embedded widget in a graphics + view; otherwise returns 0. + + \sa QGraphicsProxyWidget::createProxyForChildWidget(), + QGraphicsScene::addWidget() + */ +QGraphicsProxyWidget *QWidget::graphicsProxyWidget() const +{ + Q_D(const QWidget); + if (d->extra) { + return d->extra->proxyWidget; + } + return 0; +} +#endif + + +/*! + \typedef QWidgetList + \relates QWidget + + Synonym for QList. +*/ + +#ifndef QT_NO_GESTURES +/*! + Subscribes the widget to a given \a gesture with specific \a flags. + + \sa ungrabGesture(), QGestureEvent + \since 4.6 +*/ +void QWidget::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags) +{ + Q_D(QWidget); + d->gestureContext.insert(gesture, flags); + (void)QGestureManager::instance(); // create a gesture manager +} + +/*! + Unsubscribes the widget from a given \a gesture type + + \sa grabGesture(), QGestureEvent + \since 4.6 +*/ +void QWidget::ungrabGesture(Qt::GestureType gesture) +{ + Q_D(QWidget); + if (d->gestureContext.remove(gesture)) { + if (QGestureManager *manager = QGestureManager::instance()) + manager->cleanupCachedGestures(this, gesture); + } +} +#endif // QT_NO_GESTURES + +/*! + \typedef WId + \relates QWidget + + Platform dependent window identifier. +*/ + +/*! + \fn void QWidget::destroy(bool destroyWindow, bool destroySubWindows) + + Frees up window system resources. Destroys the widget window if \a + destroyWindow is true. + + destroy() calls itself recursively for all the child widgets, + passing \a destroySubWindows for the \a destroyWindow parameter. + To have more control over destruction of subwidgets, destroy + subwidgets selectively first. + + This function is usually called from the QWidget destructor. +*/ + +/*! + \fn QPaintEngine *QWidget::paintEngine() const + + Returns the widget's paint engine. + + Note that this function should not be called explicitly by the + user, since it's meant for reimplementation purposes only. The + function is called by Qt internally, and the default + implementation may not always return a valid pointer. +*/ + +/*! + \fn QPoint QWidget::mapToGlobal(const QPoint &pos) const + + Translates the widget coordinate \a pos to global screen + coordinates. For example, \c{mapToGlobal(QPoint(0,0))} would give + the global coordinates of the top-left pixel of the widget. + + \sa mapFromGlobal() mapTo() mapToParent() +*/ + +/*! + \fn QPoint QWidget::mapFromGlobal(const QPoint &pos) const + + Translates the global screen coordinate \a pos to widget + coordinates. + + \sa mapToGlobal() mapFrom() mapFromParent() +*/ + +/*! + \fn void QWidget::grabMouse() + + Grabs the mouse input. + + This widget receives all mouse events until releaseMouse() is + called; other widgets get no mouse events at all. Keyboard + events are not affected. Use grabKeyboard() if you want to grab + that. + + \warning Bugs in mouse-grabbing applications very often lock the + terminal. Use this function with extreme caution, and consider + using the \c -nograb command line option while debugging. + + It is almost never necessary to grab the mouse when using Qt, as + Qt grabs and releases it sensibly. In particular, Qt grabs the + mouse when a mouse button is pressed and keeps it until the last + button is released. + + \note Only visible widgets can grab mouse input. If isVisible() + returns false for a widget, that widget cannot call grabMouse(). + + \note \bold{(Mac OS X developers)} For \e Cocoa, calling + grabMouse() on a widget only works when the mouse is inside the + frame of that widget. For \e Carbon, it works outside the widget's + frame as well, like for Windows and X11. + + \sa releaseMouse() grabKeyboard() releaseKeyboard() +*/ + +/*! + \fn void QWidget::grabMouse(const QCursor &cursor) + \overload grabMouse() + + Grabs the mouse input and changes the cursor shape. + + The cursor will assume shape \a cursor (for as long as the mouse + focus is grabbed) and this widget will be the only one to receive + mouse events until releaseMouse() is called(). + + \warning Grabbing the mouse might lock the terminal. + + \note \bold{(Mac OS X developers)} See the note in QWidget::grabMouse(). + + \sa releaseMouse(), grabKeyboard(), releaseKeyboard(), setCursor() +*/ + +/*! + \fn void QWidget::releaseMouse() + + Releases the mouse grab. + + \sa grabMouse(), grabKeyboard(), releaseKeyboard() +*/ + +/*! + \fn void QWidget::grabKeyboard() + + Grabs the keyboard input. + + This widget receives all keyboard events until releaseKeyboard() + is called; other widgets get no keyboard events at all. Mouse + events are not affected. Use grabMouse() if you want to grab that. + + The focus widget is not affected, except that it doesn't receive + any keyboard events. setFocus() moves the focus as usual, but the + new focus widget receives keyboard events only after + releaseKeyboard() is called. + + If a different widget is currently grabbing keyboard input, that + widget's grab is released first. + + \sa releaseKeyboard() grabMouse() releaseMouse() focusWidget() +*/ + +/*! + \fn void QWidget::releaseKeyboard() + + Releases the keyboard grab. + + \sa grabKeyboard(), grabMouse(), releaseMouse() +*/ + +/*! + \fn QWidget *QWidget::mouseGrabber() + + Returns the widget that is currently grabbing the mouse input. + + If no widget in this application is currently grabbing the mouse, + 0 is returned. + + \sa grabMouse(), keyboardGrabber() +*/ + +/*! + \fn QWidget *QWidget::keyboardGrabber() + + Returns the widget that is currently grabbing the keyboard input. + + If no widget in this application is currently grabbing the + keyboard, 0 is returned. + + \sa grabMouse(), mouseGrabber() +*/ + +/*! + \fn void QWidget::activateWindow() + + Sets the top-level widget containing this widget to be the active + window. + + An active window is a visible top-level window that has the + keyboard input focus. + + This function performs the same operation as clicking the mouse on + the title bar of a top-level window. On X11, the result depends on + the Window Manager. If you want to ensure that the window is + stacked on top as well you should also call raise(). Note that the + window must be visible, otherwise activateWindow() has no effect. + + On Windows, if you are calling this when the application is not + currently the active one then it will not make it the active + window. It will change the color of the taskbar entry to indicate + that the window has changed in some way. This is because Microsoft + does not allow an application to interrupt what the user is currently + doing in another application. + + \sa isActiveWindow(), window(), show() +*/ + +/*! + \fn int QWidget::metric(PaintDeviceMetric m) const + + Internal implementation of the virtual QPaintDevice::metric() + function. + + \a m is the metric to get. +*/ + +void QWidget::init(QPainter *painter) const +{ + const QPalette &pal = palette(); + painter->d_func()->state->pen = QPen(pal.brush(foregroundRole()), 0); + painter->d_func()->state->bgBrush = pal.brush(backgroundRole()); + QFont f(font(), const_cast(this)); + painter->d_func()->state->deviceFont = f; + painter->d_func()->state->font = f; +} + +QPaintDevice *QWidget::redirected(QPoint *offset) const +{ + return d_func()->redirected(offset); +} + +QPainter *QWidget::sharedPainter() const +{ + // Someone sent a paint event directly to the widget + if (!d_func()->redirectDev) + return 0; + + QPainter *sp = d_func()->sharedPainter(); + if (!sp || !sp->isActive()) + return 0; + + if (sp->paintEngine()->paintDevice() != d_func()->redirectDev) + return 0; + + return sp; +} + +/*! + \fn void QWidget::setMask(const QRegion ®ion) + \overload + + Causes only the parts of the widget which overlap \a region to be + visible. If the region includes pixels outside the rect() of the + widget, window system controls in that area may or may not be + visible, depending on the platform. + + Note that this effect can be slow if the region is particularly + complex. + + \sa windowOpacity +*/ +void QWidget::setMask(const QRegion &newMask) +{ + Q_D(QWidget); + + d->createExtra(); + if (newMask == d->extra->mask) + return; + +#ifndef QT_NO_BACKINGSTORE + const QRegion oldMask(d->extra->mask); +#endif + + d->extra->mask = newMask; + d->extra->hasMask = !newMask.isEmpty(); + +#ifndef QT_MAC_USE_COCOA + if (!testAttribute(Qt::WA_WState_Created)) + return; +#endif + + d->setMask_sys(newMask); + +#ifndef QT_NO_BACKINGSTORE + if (!isVisible()) + return; + + if (!d->extra->hasMask) { + // Mask was cleared; update newly exposed area. + QRegion expose(rect()); + expose -= oldMask; + if (!expose.isEmpty()) { + d->setDirtyOpaqueRegion(); + update(expose); + } + return; + } + + if (!isWindow()) { + // Update newly exposed area on the parent widget. + QRegion parentExpose(rect()); + parentExpose -= newMask; + if (!parentExpose.isEmpty()) { + d->setDirtyOpaqueRegion(); + parentExpose.translate(data->crect.topLeft()); + parentWidget()->update(parentExpose); + } + + // Update newly exposed area on this widget + if (!oldMask.isEmpty()) + update(newMask - oldMask); + } +#endif +} + +/*! + \fn void QWidget::setMask(const QBitmap &bitmap) + + Causes only the pixels of the widget for which \a bitmap has a + corresponding 1 bit to be visible. If the region includes pixels + outside the rect() of the widget, window system controls in that + area may or may not be visible, depending on the platform. + + Note that this effect can be slow if the region is particularly + complex. + + The following code shows how an image with an alpha channel can be + used to generate a mask for a widget: + + \snippet doc/src/snippets/widget-mask/main.cpp 0 + + The label shown by this code is masked using the image it contains, + giving the appearance that an irregularly-shaped image is being drawn + directly onto the screen. + + Masked widgets receive mouse events only on their visible + portions. + + \sa clearMask(), windowOpacity(), {Shaped Clock Example} +*/ +void QWidget::setMask(const QBitmap &bitmap) +{ + setMask(QRegion(bitmap)); +} + +/*! + \fn void QWidget::clearMask() + + Removes any mask set by setMask(). + + \sa setMask() +*/ +void QWidget::clearMask() +{ + setMask(QRegion()); +} + +/*! \fn const QX11Info &QWidget::x11Info() const + Returns information about the configuration of the X display used to display + the widget. + + \warning This function is only available on X11. +*/ + +/*! \fn Qt::HANDLE QWidget::x11PictureHandle() const + Returns the X11 Picture handle of the widget for XRender + support. Use of this function is not portable. This function will + return 0 if XRender support is not compiled into Qt, if the + XRender extension is not supported on the X11 display, or if the + handle could not be created. +*/ + +#ifdef Q_OS_SYMBIAN +void QWidgetPrivate::_q_delayedDestroy(WId winId) +{ + delete winId; +} +#endif + +#if QT_MAC_USE_COCOA +void QWidgetPrivate::syncUnifiedMode() { + // The whole purpose of this method is to keep the unifiedToolbar in sync. + // That means making sure we either exchange the drawing methods or we let + // the toolbar know that it does not require to draw the baseline. + Q_Q(QWidget); + // This function makes sense only if this is a top level + if(!q->isWindow()) + return; + OSWindowRef window = qt_mac_window_for(q); + if(changeMethods) { + // Ok, we are in documentMode. + if(originalDrawMethod) + qt_mac_replaceDrawRect(window, this); + } else { + if(!originalDrawMethod) + qt_mac_replaceDrawRectOriginal(window, this); + } +} + +#endif // QT_MAC_USE_COCOA + +QT_END_NAMESPACE + +#include "moc_qwidget.cpp" + diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h new file mode 100644 index 0000000000..d14e8652be --- /dev/null +++ b/src/widgets/kernel/qwidget.h @@ -0,0 +1,1091 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGET_H +#define QWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_QPA //should this go somewhere else? +#include +#include +#endif + +#ifdef QT_INCLUDE_COMPAT +#include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QLayout; +class QWSRegionManager; +class QStyle; +class QAction; +class QVariant; + +class QActionEvent; +class QMouseEvent; +class QWheelEvent; +class QHoverEvent; +class QKeyEvent; +class QFocusEvent; +class QPaintEvent; +class QMoveEvent; +class QResizeEvent; +class QCloseEvent; +class QContextMenuEvent; +class QInputMethodEvent; +class QTabletEvent; +class QDragEnterEvent; +class QDragMoveEvent; +class QDragLeaveEvent; +class QDropEvent; +class QShowEvent; +class QHideEvent; +class QInputContext; +class QIcon; +class QWindowSurface; +class QPlatformWindow; +class QLocale; +class QGraphicsProxyWidget; +class QGraphicsEffect; +class QRasterWindowSurface; +class QUnifiedToolbarSurface; +#if defined(Q_WS_X11) +class QX11Info; +#endif + +class QWidgetData +{ +public: + WId winid; + uint widget_attributes; + Qt::WindowFlags window_flags; + uint window_state : 4; + uint focus_policy : 4; + uint sizehint_forced :1; + uint is_closing :1; + uint in_show : 1; + uint in_set_window_state : 1; + mutable uint fstrut_dirty : 1; + uint context_menu_policy : 3; + uint window_modality : 2; + uint in_destructor : 1; + uint unused : 13; + QRect crect; + mutable QPalette pal; + QFont fnt; +#if defined(Q_WS_QWS) +// QRegion req_region; // Requested region +// mutable QRegion paintable_region; // Paintable region +// mutable bool paintable_region_dirty;// needs to be recalculated +// mutable QRegion alloc_region; // Allocated region +// mutable bool alloc_region_dirty; // needs to be recalculated +// mutable int overlapping_children; // Handle overlapping children + + int alloc_region_index; +// int alloc_region_revision; +#endif + QRect wrect; +}; + +class QWidgetPrivate; + +class Q_GUI_EXPORT QWidget : public QObject, public QPaintDevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWidget) + + Q_PROPERTY(bool modal READ isModal) + Q_PROPERTY(Qt::WindowModality windowModality READ windowModality WRITE setWindowModality) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(QRect geometry READ geometry WRITE setGeometry) + Q_PROPERTY(QRect frameGeometry READ frameGeometry) + Q_PROPERTY(QRect normalGeometry READ normalGeometry) + Q_PROPERTY(int x READ x) + Q_PROPERTY(int y READ y) + Q_PROPERTY(QPoint pos READ pos WRITE move DESIGNABLE false STORED false) + Q_PROPERTY(QSize frameSize READ frameSize) + Q_PROPERTY(QSize size READ size WRITE resize DESIGNABLE false STORED false) + Q_PROPERTY(int width READ width) + Q_PROPERTY(int height READ height) + Q_PROPERTY(QRect rect READ rect) + Q_PROPERTY(QRect childrenRect READ childrenRect) + Q_PROPERTY(QRegion childrenRegion READ childrenRegion) + Q_PROPERTY(QSizePolicy sizePolicy READ sizePolicy WRITE setSizePolicy) + Q_PROPERTY(QSize minimumSize READ minimumSize WRITE setMinimumSize) + Q_PROPERTY(QSize maximumSize READ maximumSize WRITE setMaximumSize) + Q_PROPERTY(int minimumWidth READ minimumWidth WRITE setMinimumWidth STORED false DESIGNABLE false) + Q_PROPERTY(int minimumHeight READ minimumHeight WRITE setMinimumHeight STORED false DESIGNABLE false) + Q_PROPERTY(int maximumWidth READ maximumWidth WRITE setMaximumWidth STORED false DESIGNABLE false) + Q_PROPERTY(int maximumHeight READ maximumHeight WRITE setMaximumHeight STORED false DESIGNABLE false) + Q_PROPERTY(QSize sizeIncrement READ sizeIncrement WRITE setSizeIncrement) + Q_PROPERTY(QSize baseSize READ baseSize WRITE setBaseSize) + Q_PROPERTY(QPalette palette READ palette WRITE setPalette) + Q_PROPERTY(QFont font READ font WRITE setFont) +#ifndef QT_NO_CURSOR + Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor) +#endif + Q_PROPERTY(bool mouseTracking READ hasMouseTracking WRITE setMouseTracking) + Q_PROPERTY(bool isActiveWindow READ isActiveWindow) + Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy) + Q_PROPERTY(bool focus READ hasFocus) + Q_PROPERTY(Qt::ContextMenuPolicy contextMenuPolicy READ contextMenuPolicy WRITE setContextMenuPolicy) + Q_PROPERTY(bool updatesEnabled READ updatesEnabled WRITE setUpdatesEnabled DESIGNABLE false) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible DESIGNABLE false) + Q_PROPERTY(bool minimized READ isMinimized) + Q_PROPERTY(bool maximized READ isMaximized) + Q_PROPERTY(bool fullScreen READ isFullScreen) + Q_PROPERTY(QSize sizeHint READ sizeHint) + Q_PROPERTY(QSize minimumSizeHint READ minimumSizeHint) + Q_PROPERTY(bool acceptDrops READ acceptDrops WRITE setAcceptDrops) + Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle DESIGNABLE isWindow) + Q_PROPERTY(QIcon windowIcon READ windowIcon WRITE setWindowIcon DESIGNABLE isWindow) + Q_PROPERTY(QString windowIconText READ windowIconText WRITE setWindowIconText DESIGNABLE isWindow) + Q_PROPERTY(double windowOpacity READ windowOpacity WRITE setWindowOpacity DESIGNABLE isWindow) + Q_PROPERTY(bool windowModified READ isWindowModified WRITE setWindowModified DESIGNABLE isWindow) +#ifndef QT_NO_TOOLTIP + Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip) +#endif +#ifndef QT_NO_STATUSTIP + Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip) +#endif +#ifndef QT_NO_WHATSTHIS + Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis) +#endif +#ifndef QT_NO_ACCESSIBILITY + Q_PROPERTY(QString accessibleName READ accessibleName WRITE setAccessibleName) + Q_PROPERTY(QString accessibleDescription READ accessibleDescription WRITE setAccessibleDescription) +#endif + Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection RESET unsetLayoutDirection) + QDOC_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags) + Q_PROPERTY(bool autoFillBackground READ autoFillBackground WRITE setAutoFillBackground) +#ifndef QT_NO_STYLE_STYLESHEET + Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet) +#endif + Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET unsetLocale) + Q_PROPERTY(QString windowFilePath READ windowFilePath WRITE setWindowFilePath DESIGNABLE isWindow) + Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) + +public: + enum RenderFlag { + DrawWindowBackground = 0x1, + DrawChildren = 0x2, + IgnoreMask = 0x4 + }; + Q_DECLARE_FLAGS(RenderFlags, RenderFlag) + + explicit QWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QWidget(QWidget* parent, const char *name, Qt::WindowFlags f = 0); +#endif + ~QWidget(); + + int devType() const; + + WId winId() const; + void createWinId(); // internal, going away + inline WId internalWinId() const { return data->winid; } + WId effectiveWinId() const; + + // GUI style setting + QStyle *style() const; + void setStyle(QStyle *); + // Widget types and states + + bool isTopLevel() const; + bool isWindow() const; + + bool isModal() const; + Qt::WindowModality windowModality() const; + void setWindowModality(Qt::WindowModality windowModality); + + bool isEnabled() const; + bool isEnabledTo(QWidget*) const; + bool isEnabledToTLW() const; + +public Q_SLOTS: + void setEnabled(bool); + void setDisabled(bool); + void setWindowModified(bool); + + // Widget coordinates + +public: + QRect frameGeometry() const; + const QRect &geometry() const; + QRect normalGeometry() const; + + int x() const; + int y() const; + QPoint pos() const; + QSize frameSize() const; + QSize size() const; + inline int width() const; + inline int height() const; + inline QRect rect() const; + QRect childrenRect() const; + QRegion childrenRegion() const; + + QSize minimumSize() const; + QSize maximumSize() const; + int minimumWidth() const; + int minimumHeight() const; + int maximumWidth() const; + int maximumHeight() const; + void setMinimumSize(const QSize &); + void setMinimumSize(int minw, int minh); + void setMaximumSize(const QSize &); + void setMaximumSize(int maxw, int maxh); + void setMinimumWidth(int minw); + void setMinimumHeight(int minh); + void setMaximumWidth(int maxw); + void setMaximumHeight(int maxh); + +#ifdef Q_QDOC + void setupUi(QWidget *widget); +#endif + + QSize sizeIncrement() const; + void setSizeIncrement(const QSize &); + void setSizeIncrement(int w, int h); + QSize baseSize() const; + void setBaseSize(const QSize &); + void setBaseSize(int basew, int baseh); + + void setFixedSize(const QSize &); + void setFixedSize(int w, int h); + void setFixedWidth(int w); + void setFixedHeight(int h); + + // Widget coordinate mapping + + QPoint mapToGlobal(const QPoint &) const; + QPoint mapFromGlobal(const QPoint &) const; + QPoint mapToParent(const QPoint &) const; + QPoint mapFromParent(const QPoint &) const; + QPoint mapTo(QWidget *, const QPoint &) const; + QPoint mapFrom(QWidget *, const QPoint &) const; + + QWidget *window() const; + QWidget *nativeParentWidget() const; + inline QWidget *topLevelWidget() const { return window(); } + + // Widget appearance functions + const QPalette &palette() const; + void setPalette(const QPalette &); + + void setBackgroundRole(QPalette::ColorRole); + QPalette::ColorRole backgroundRole() const; + + void setForegroundRole(QPalette::ColorRole); + QPalette::ColorRole foregroundRole() const; + + const QFont &font() const; + void setFont(const QFont &); + QFontMetrics fontMetrics() const; + QFontInfo fontInfo() const; + +#ifndef QT_NO_CURSOR + QCursor cursor() const; + void setCursor(const QCursor &); + void unsetCursor(); +#endif + + void setMouseTracking(bool enable); + bool hasMouseTracking() const; + bool underMouse() const; + + void setMask(const QBitmap &); + void setMask(const QRegion &); + QRegion mask() const; + void clearMask(); + + void render(QPaintDevice *target, const QPoint &targetOffset = QPoint(), + const QRegion &sourceRegion = QRegion(), + RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren)); + + void render(QPainter *painter, const QPoint &targetOffset = QPoint(), + const QRegion &sourceRegion = QRegion(), + RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren)); + +#ifndef QT_NO_GRAPHICSEFFECT + QGraphicsEffect *graphicsEffect() const; + void setGraphicsEffect(QGraphicsEffect *effect); +#endif //QT_NO_GRAPHICSEFFECT + +#ifndef QT_NO_GESTURES + void grabGesture(Qt::GestureType type, Qt::GestureFlags flags = Qt::GestureFlags()); + void ungrabGesture(Qt::GestureType type); +#endif + +public Q_SLOTS: + void setWindowTitle(const QString &); +#ifndef QT_NO_STYLE_STYLESHEET + void setStyleSheet(const QString& styleSheet); +#endif +public: +#ifndef QT_NO_STYLE_STYLESHEET + QString styleSheet() const; +#endif + QString windowTitle() const; + void setWindowIcon(const QIcon &icon); + QIcon windowIcon() const; + void setWindowIconText(const QString &); + QString windowIconText() const; + void setWindowRole(const QString &); + QString windowRole() const; + void setWindowFilePath(const QString &filePath); + QString windowFilePath() const; + + void setWindowOpacity(qreal level); + qreal windowOpacity() const; + + bool isWindowModified() const; +#ifndef QT_NO_TOOLTIP + void setToolTip(const QString &); + QString toolTip() const; +#endif +#ifndef QT_NO_STATUSTIP + void setStatusTip(const QString &); + QString statusTip() const; +#endif +#ifndef QT_NO_WHATSTHIS + void setWhatsThis(const QString &); + QString whatsThis() const; +#endif +#ifndef QT_NO_ACCESSIBILITY + QString accessibleName() const; + void setAccessibleName(const QString &name); + QString accessibleDescription() const; + void setAccessibleDescription(const QString &description); +#endif + + void setLayoutDirection(Qt::LayoutDirection direction); + Qt::LayoutDirection layoutDirection() const; + void unsetLayoutDirection(); + + void setLocale(const QLocale &locale); + QLocale locale() const; + void unsetLocale(); + + inline bool isRightToLeft() const { return layoutDirection() == Qt::RightToLeft; } + inline bool isLeftToRight() const { return layoutDirection() == Qt::LeftToRight; } + +public Q_SLOTS: + inline void setFocus() { setFocus(Qt::OtherFocusReason); } + +public: + bool isActiveWindow() const; + void activateWindow(); + void clearFocus(); + + void setFocus(Qt::FocusReason reason); + Qt::FocusPolicy focusPolicy() const; + void setFocusPolicy(Qt::FocusPolicy policy); + bool hasFocus() const; + static void setTabOrder(QWidget *, QWidget *); + void setFocusProxy(QWidget *); + QWidget *focusProxy() const; + Qt::ContextMenuPolicy contextMenuPolicy() const; + void setContextMenuPolicy(Qt::ContextMenuPolicy policy); + + // Grab functions + void grabMouse(); +#ifndef QT_NO_CURSOR + void grabMouse(const QCursor &); +#endif + void releaseMouse(); + void grabKeyboard(); + void releaseKeyboard(); +#ifndef QT_NO_SHORTCUT + int grabShortcut(const QKeySequence &key, Qt::ShortcutContext context = Qt::WindowShortcut); + void releaseShortcut(int id); + void setShortcutEnabled(int id, bool enable = true); + void setShortcutAutoRepeat(int id, bool enable = true); +#endif + static QWidget *mouseGrabber(); + static QWidget *keyboardGrabber(); + + // Update/refresh functions + inline bool updatesEnabled() const; + void setUpdatesEnabled(bool enable); + +#if 0 //def Q_WS_QWS + void repaintUnclipped(const QRegion &, bool erase = true); +#endif + +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsProxyWidget *graphicsProxyWidget() const; +#endif + +public Q_SLOTS: + void update(); + void repaint(); + +public: + inline void update(int x, int y, int w, int h); + void update(const QRect&); + void update(const QRegion&); + + void repaint(int x, int y, int w, int h); + void repaint(const QRect &); + void repaint(const QRegion &); + +public Q_SLOTS: + // Widget management functions + + virtual void setVisible(bool visible); + inline void setHidden(bool hidden) { setVisible(!hidden); } +#ifndef Q_WS_WINCE + inline void show() { setVisible(true); } +#else + void show(); +#endif + inline void hide() { setVisible(false); } + inline QT_MOC_COMPAT void setShown(bool shown) { setVisible(shown); } + + void showMinimized(); + void showMaximized(); + void showFullScreen(); + void showNormal(); + + bool close(); + void raise(); + void lower(); + +public: + void stackUnder(QWidget*); + void move(int x, int y); + void move(const QPoint &); + void resize(int w, int h); + void resize(const QSize &); + inline void setGeometry(int x, int y, int w, int h); + void setGeometry(const QRect &); + QByteArray saveGeometry() const; + bool restoreGeometry(const QByteArray &geometry); + void adjustSize(); + bool isVisible() const; + bool isVisibleTo(QWidget*) const; + // ### Qt 5: bool isVisibleTo(_const_ QWidget *) const + inline bool isHidden() const; + + bool isMinimized() const; + bool isMaximized() const; + bool isFullScreen() const; + + Qt::WindowStates windowState() const; + void setWindowState(Qt::WindowStates state); + void overrideWindowState(Qt::WindowStates state); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + QSizePolicy sizePolicy() const; + void setSizePolicy(QSizePolicy); + inline void setSizePolicy(QSizePolicy::Policy horizontal, QSizePolicy::Policy vertical); + virtual int heightForWidth(int) const; + + QRegion visibleRegion() const; + + void setContentsMargins(int left, int top, int right, int bottom); + void setContentsMargins(const QMargins &margins); + void getContentsMargins(int *left, int *top, int *right, int *bottom) const; + QMargins contentsMargins() const; + + QRect contentsRect() const; + +public: + QLayout *layout() const; + void setLayout(QLayout *); + void updateGeometry(); + + void setParent(QWidget *parent); + void setParent(QWidget *parent, Qt::WindowFlags f); + + void scroll(int dx, int dy); + void scroll(int dx, int dy, const QRect&); + + // Misc. functions + + QWidget *focusWidget() const; + QWidget *nextInFocusChain() const; + QWidget *previousInFocusChain() const; + + // drag and drop + bool acceptDrops() const; + void setAcceptDrops(bool on); + +#ifndef QT_NO_ACTION + //actions + void addAction(QAction *action); + void addActions(QList actions); + void insertAction(QAction *before, QAction *action); + void insertActions(QAction *before, QList actions); + void removeAction(QAction *action); + QList actions() const; +#endif + + QWidget *parentWidget() const; + + void setWindowFlags(Qt::WindowFlags type); + inline Qt::WindowFlags windowFlags() const; + void overrideWindowFlags(Qt::WindowFlags type); + + inline Qt::WindowType windowType() const; + + static QWidget *find(WId); +#ifdef QT3_SUPPORT + static QT3_SUPPORT QWidgetMapper *wmapper(); +#endif + inline QWidget *childAt(int x, int y) const; + QWidget *childAt(const QPoint &p) const; + +#if defined(Q_WS_X11) + const QX11Info &x11Info() const; + Qt::HANDLE x11PictureHandle() const; +#endif + +#if defined(Q_WS_MAC) + Qt::HANDLE macQDHandle() const; + Qt::HANDLE macCGHandle() const; +#endif + +#if defined(Q_WS_WIN) + HDC getDC() const; + void releaseDC(HDC) const; +#else + Qt::HANDLE handle() const; +#endif + + void setAttribute(Qt::WidgetAttribute, bool on = true); + inline bool testAttribute(Qt::WidgetAttribute) const; + + QPaintEngine *paintEngine() const; + + void ensurePolished() const; + + QInputContext *inputContext(); + void setInputContext(QInputContext *); + + bool isAncestorOf(const QWidget *child) const; + +#ifdef QT_KEYPAD_NAVIGATION + bool hasEditFocus() const; + void setEditFocus(bool on); +#endif + + bool autoFillBackground() const; + void setAutoFillBackground(bool enabled); + + void setWindowSurface(QWindowSurface *surface); + QWindowSurface *windowSurface() const; + +#if defined(Q_WS_QPA) + void setWindowHandle(QWindow *window); + QWindow *windowHandle() const; + + friend class QDesktopScreenWidget; +#endif + +Q_SIGNALS: + void customContextMenuRequested(const QPoint &pos); + +protected: + // Event handlers + bool event(QEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void mouseDoubleClickEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); +#ifndef QT_NO_WHEELEVENT + virtual void wheelEvent(QWheelEvent *); +#endif + virtual void keyPressEvent(QKeyEvent *); + virtual void keyReleaseEvent(QKeyEvent *); + virtual void focusInEvent(QFocusEvent *); + virtual void focusOutEvent(QFocusEvent *); + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + virtual void paintEvent(QPaintEvent *); + virtual void moveEvent(QMoveEvent *); + virtual void resizeEvent(QResizeEvent *); + virtual void closeEvent(QCloseEvent *); +#ifndef QT_NO_CONTEXTMENU + virtual void contextMenuEvent(QContextMenuEvent *); +#endif +#ifndef QT_NO_TABLETEVENT + virtual void tabletEvent(QTabletEvent *); +#endif +#ifndef QT_NO_ACTION + virtual void actionEvent(QActionEvent *); +#endif + +#ifndef QT_NO_DRAGANDDROP + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragMoveEvent(QDragMoveEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + virtual void dropEvent(QDropEvent *); +#endif + + virtual void showEvent(QShowEvent *); + virtual void hideEvent(QHideEvent *); + +#if defined(Q_WS_MAC) + virtual bool macEvent(EventHandlerCallRef, EventRef); +#endif +#if defined(Q_WS_WIN) + virtual bool winEvent(MSG *message, long *result); +#endif +#if defined(Q_WS_X11) + virtual bool x11Event(XEvent *); +#endif +#if defined(Q_WS_QWS) + virtual bool qwsEvent(QWSEvent *); +#endif + + // Misc. protected functions + virtual void changeEvent(QEvent *); + + int metric(PaintDeviceMetric) const; + void init(QPainter *painter) const; + QPaintDevice *redirected(QPoint *offset) const; + QPainter *sharedPainter() const; + + virtual void inputMethodEvent(QInputMethodEvent *); +public: + virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const; + + Qt::InputMethodHints inputMethodHints() const; + void setInputMethodHints(Qt::InputMethodHints hints); + +protected: + void resetInputContext(); +protected Q_SLOTS: + void updateMicroFocus(); +protected: + + void create(WId = 0, bool initializeWindow = true, + bool destroyOldWindow = true); + void destroy(bool destroyWindow = true, + bool destroySubWindows = true); + + virtual bool focusNextPrevChild(bool next); + inline bool focusNextChild() { return focusNextPrevChild(true); } + inline bool focusPreviousChild() { return focusNextPrevChild(false); } + +protected: + QWidget(QWidgetPrivate &d, QWidget* parent, Qt::WindowFlags f); +private: + + bool testAttribute_helper(Qt::WidgetAttribute) const; + + QLayout *takeLayout(); + + friend class QBackingStoreDevice; + friend class QWidgetBackingStore; + friend class QApplication; + friend class QApplicationPrivate; + friend class QGuiApplication; + friend class QGuiApplicationPrivate; + friend class QBaseApplication; + friend class QPainter; + friend class QPainterPrivate; + friend class QPixmap; // for QPixmap::fill() + friend class QFontMetrics; + friend class QFontInfo; + friend class QETWidget; + friend class QLayout; + friend class QWidgetItem; + friend class QWidgetItemV2; + friend class QGLContext; + friend class QGLWidget; + friend class QGLWindowSurface; + friend class QX11PaintEngine; + friend class QWin32PaintEngine; + friend class QShortcutPrivate; + friend class QShortcutMap; + friend class QWindowSurface; + friend class QGraphicsProxyWidget; + friend class QGraphicsProxyWidgetPrivate; + friend class QStyleSheetStyle; + friend struct QWidgetExceptionCleaner; + friend class QWidgetWindow; +#ifndef QT_NO_GESTURES + friend class QGestureManager; + friend class QWinNativePanGestureRecognizer; +#endif // QT_NO_GESTURES + friend class QWidgetEffectSourcePrivate; + +#ifdef Q_WS_MAC + friend class QCoreGraphicsPaintEnginePrivate; + friend QPoint qt_mac_posInWindow(const QWidget *w); + friend OSWindowRef qt_mac_window_for(const QWidget *w); + friend bool qt_mac_is_metal(const QWidget *w); + friend OSViewRef qt_mac_nativeview_for(const QWidget *w); + friend void qt_event_request_window_change(QWidget *widget); + friend bool qt_mac_sendMacEventToWidget(QWidget *widget, EventRef ref); + friend class QRasterWindowSurface; + friend class QUnifiedToolbarSurface; +#endif +#ifdef Q_WS_QWS + friend class QWSBackingStore; + friend class QWSManager; + friend class QWSManagerPrivate; + friend class QDecoration; + friend class QWSWindowSurface; + friend class QScreen; + friend class QVNCScreen; + friend bool isWidgetOpaque(const QWidget *); + friend class QGLWidgetPrivate; +#endif +#ifdef Q_OS_SYMBIAN + friend class QSymbianControl; + friend class QS60WindowSurface; +#endif +#ifdef Q_WS_X11 + friend void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp); + friend void qt_net_remove_user_time(QWidget *tlw); + friend void qt_set_winid_on_widget(QWidget*, Qt::HANDLE); +#endif + + friend Q_GUI_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget); + friend Q_GUI_EXPORT QWidgetPrivate *qt_widget_private(QWidget *widget); + +private: + Q_DISABLE_COPY(QWidget) + Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden()) +#ifdef Q_OS_SYMBIAN + Q_PRIVATE_SLOT(d_func(), void _q_delayedDestroy(WId winId)) +#endif + + QWidgetData *data; + +#ifdef QT3_SUPPORT +public: + inline QT3_SUPPORT bool isUpdatesEnabled() const { return updatesEnabled(); } + QT3_SUPPORT QStyle *setStyle(const QString&); + inline QT3_SUPPORT bool isVisibleToTLW() const; + QT3_SUPPORT QRect visibleRect() const; + inline QT3_SUPPORT void iconify() { showMinimized(); } + inline QT3_SUPPORT void constPolish() const { ensurePolished(); } + inline QT3_SUPPORT void polish() { ensurePolished(); } + inline QT3_SUPPORT void reparent(QWidget *parent, Qt::WindowFlags f, const QPoint &p, bool showIt=false) + { setParent(parent, f); setGeometry(p.x(),p.y(),width(),height()); if (showIt) show(); } + inline QT3_SUPPORT void reparent(QWidget *parent, const QPoint &p, bool showIt=false) + { setParent(parent, windowFlags() & ~Qt::WindowType_Mask); setGeometry(p.x(),p.y(),width(),height()); if (showIt) show(); } + inline QT3_SUPPORT void recreate(QWidget *parent, Qt::WindowFlags f, const QPoint & p, bool showIt=false) + { setParent(parent, f); setGeometry(p.x(),p.y(),width(),height()); if (showIt) show(); } + inline QT3_SUPPORT void setSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver, bool hfw) + { QSizePolicy sp(hor, ver); sp.setHeightForWidth(hfw); setSizePolicy(sp);} + inline QT3_SUPPORT bool hasMouse() const { return testAttribute(Qt::WA_UnderMouse); } +#ifndef QT_NO_CURSOR + inline QT3_SUPPORT bool ownCursor() const { return testAttribute(Qt::WA_SetCursor); } +#endif + inline QT3_SUPPORT bool ownFont() const { return testAttribute(Qt::WA_SetFont); } + inline QT3_SUPPORT void unsetFont() { setFont(QFont()); } + inline QT3_SUPPORT bool ownPalette() const { return testAttribute(Qt::WA_SetPalette); } + inline QT3_SUPPORT void unsetPalette() { setPalette(QPalette()); } + Qt::BackgroundMode QT3_SUPPORT backgroundMode() const; + void QT3_SUPPORT setBackgroundMode(Qt::BackgroundMode, Qt::BackgroundMode = Qt::PaletteBackground); + const QT3_SUPPORT QColor &eraseColor() const; + void QT3_SUPPORT setEraseColor(const QColor &); + const QT3_SUPPORT QColor &foregroundColor() const; + const QT3_SUPPORT QPixmap *erasePixmap() const; + void QT3_SUPPORT setErasePixmap(const QPixmap &); + const QT3_SUPPORT QColor &paletteForegroundColor() const; + void QT3_SUPPORT setPaletteForegroundColor(const QColor &); + const QT3_SUPPORT QColor &paletteBackgroundColor() const; + void QT3_SUPPORT setPaletteBackgroundColor(const QColor &); + const QT3_SUPPORT QPixmap *paletteBackgroundPixmap() const; + void QT3_SUPPORT setPaletteBackgroundPixmap(const QPixmap &); + const QT3_SUPPORT QBrush& backgroundBrush() const; + const QT3_SUPPORT QColor &backgroundColor() const; + const QT3_SUPPORT QPixmap *backgroundPixmap() const; + void QT3_SUPPORT setBackgroundPixmap(const QPixmap &); + QT3_SUPPORT void setBackgroundColor(const QColor &); + QT3_SUPPORT QWidget *parentWidget(bool sameWindow) const; + inline QT3_SUPPORT void setKeyCompression(bool b) { setAttribute(Qt::WA_KeyCompression, b); } + inline QT3_SUPPORT void setFont(const QFont &f, bool) { setFont(f); } + inline QT3_SUPPORT void setPalette(const QPalette &p, bool) { setPalette(p); } + enum BackgroundOrigin { WidgetOrigin, ParentOrigin, WindowOrigin, AncestorOrigin }; + inline QT3_SUPPORT void setBackgroundOrigin(BackgroundOrigin) {} + inline QT3_SUPPORT BackgroundOrigin backgroundOrigin() const { return WindowOrigin; } + inline QT3_SUPPORT QPoint backgroundOffset() const { return QPoint(); } + inline QT3_SUPPORT void repaint(bool) { repaint(); } + inline QT3_SUPPORT void repaint(int x, int y, int w, int h, bool) { repaint(x,y,w,h); } + inline QT3_SUPPORT void repaint(const QRect &r, bool) { repaint(r); } + inline QT3_SUPPORT void repaint(const QRegion &rgn, bool) { repaint(rgn); } + QT3_SUPPORT void erase(); + inline QT3_SUPPORT void erase(int x, int y, int w, int h) { erase_helper(x, y, w, h); } + QT3_SUPPORT void erase(const QRect &); + QT3_SUPPORT void erase(const QRegion &); + QT3_SUPPORT void drawText(const QPoint &p, const QString &s) + { drawText_helper(p.x(), p.y(), s); } + inline QT3_SUPPORT void drawText(int x, int y, const QString &s) + { drawText_helper(x, y, s); } + QT3_SUPPORT bool close(bool); + inline QT3_SUPPORT QWidget *childAt(int x, int y, bool includeThis) const + { + QWidget *w = childAt(x, y); + return w ? w : ((includeThis && rect().contains(x,y))?const_cast(this):0); + } + inline QT3_SUPPORT QWidget *childAt(const QPoint &p, bool includeThis) const + { + QWidget *w = childAt(p); + return w ? w : ((includeThis && rect().contains(p))?const_cast(this):0); + } + inline QT3_SUPPORT void setCaption(const QString &c) { setWindowTitle(c); } + QT3_SUPPORT void setIcon(const QPixmap &i); + inline QT3_SUPPORT void setIconText(const QString &it) { setWindowIconText(it); } + inline QT3_SUPPORT QString caption() const { return windowTitle(); } + QT3_SUPPORT const QPixmap *icon() const; + inline QT3_SUPPORT QString iconText() const { return windowIconText(); } + inline QT3_SUPPORT void setInputMethodEnabled(bool b) { setAttribute(Qt::WA_InputMethodEnabled, b); } + inline QT3_SUPPORT bool isInputMethodEnabled() const { return testAttribute(Qt::WA_InputMethodEnabled); } + inline QT3_SUPPORT void setActiveWindow() { activateWindow(); } + inline QT3_SUPPORT bool isShown() const { return !isHidden(); } + inline QT3_SUPPORT bool isDialog() const { return windowType() == Qt::Dialog; } + inline QT3_SUPPORT bool isPopup() const { return windowType() == Qt::Popup; } + inline QT3_SUPPORT bool isDesktop() const { return windowType() == Qt::Desktop; } + + +private: + void drawText_helper(int x, int y, const QString &); + void erase_helper(int x, int y, int w, int h); +#endif // QT3_SUPPORT + +protected: + virtual void styleChange(QStyle&); // compat + virtual void enabledChange(bool); // compat + virtual void paletteChange(const QPalette &); // compat + virtual void fontChange(const QFont &); // compat + virtual void windowActivationChange(bool); // compat + virtual void languageChange(); // compat +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QWidget::RenderFlags) + +template <> inline QWidget *qobject_cast(QObject *o) +{ + if (!o || !o->isWidgetType()) return 0; + return static_cast(o); +} +template <> inline const QWidget *qobject_cast(const QObject *o) +{ + if (!o || !o->isWidgetType()) return 0; + return static_cast(o); +} + +inline QWidget *QWidget::childAt(int ax, int ay) const +{ return childAt(QPoint(ax, ay)); } + +inline Qt::WindowType QWidget::windowType() const +{ return static_cast(int(data->window_flags & Qt::WindowType_Mask)); } +inline Qt::WindowFlags QWidget::windowFlags() const +{ return data->window_flags; } + +inline bool QWidget::isTopLevel() const +{ return (windowType() & Qt::Window); } + +inline bool QWidget::isWindow() const +{ return (windowType() & Qt::Window); } + +inline bool QWidget::isEnabled() const +{ return !testAttribute(Qt::WA_Disabled); } + +inline bool QWidget::isModal() const +{ return data->window_modality != Qt::NonModal; } + +inline bool QWidget::isEnabledToTLW() const +{ return isEnabled(); } + +inline int QWidget::minimumWidth() const +{ return minimumSize().width(); } + +inline int QWidget::minimumHeight() const +{ return minimumSize().height(); } + +inline int QWidget::maximumWidth() const +{ return maximumSize().width(); } + +inline int QWidget::maximumHeight() const +{ return maximumSize().height(); } + +inline void QWidget::setMinimumSize(const QSize &s) +{ setMinimumSize(s.width(),s.height()); } + +inline void QWidget::setMaximumSize(const QSize &s) +{ setMaximumSize(s.width(),s.height()); } + +inline void QWidget::setSizeIncrement(const QSize &s) +{ setSizeIncrement(s.width(),s.height()); } + +inline void QWidget::setBaseSize(const QSize &s) +{ setBaseSize(s.width(),s.height()); } + +inline const QFont &QWidget::font() const +{ return data->fnt; } + +inline QFontMetrics QWidget::fontMetrics() const +{ return QFontMetrics(data->fnt); } + +inline QFontInfo QWidget::fontInfo() const +{ return QFontInfo(data->fnt); } + +inline void QWidget::setMouseTracking(bool enable) +{ setAttribute(Qt::WA_MouseTracking, enable); } + +inline bool QWidget::hasMouseTracking() const +{ return testAttribute(Qt::WA_MouseTracking); } + +inline bool QWidget::underMouse() const +{ return testAttribute(Qt::WA_UnderMouse); } + +inline bool QWidget::updatesEnabled() const +{ return !testAttribute(Qt::WA_UpdatesDisabled); } + +inline void QWidget::update(int ax, int ay, int aw, int ah) +{ update(QRect(ax, ay, aw, ah)); } + +inline bool QWidget::isVisible() const +{ return testAttribute(Qt::WA_WState_Visible); } + +inline bool QWidget::isHidden() const +{ return testAttribute(Qt::WA_WState_Hidden); } + +inline void QWidget::move(int ax, int ay) +{ move(QPoint(ax, ay)); } + +inline void QWidget::resize(int w, int h) +{ resize(QSize(w, h)); } + +inline void QWidget::setGeometry(int ax, int ay, int aw, int ah) +{ setGeometry(QRect(ax, ay, aw, ah)); } + +inline QRect QWidget::rect() const +{ return QRect(0,0,data->crect.width(),data->crect.height()); } + +inline const QRect &QWidget::geometry() const +{ return data->crect; } + +inline QSize QWidget::size() const +{ return data->crect.size(); } + +inline int QWidget::width() const +{ return data->crect.width(); } + +inline int QWidget::height() const +{ return data->crect.height(); } + +inline QWidget *QWidget::parentWidget() const +{ return static_cast(QObject::parent()); } + +inline void QWidget::setSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver) +{ setSizePolicy(QSizePolicy(hor, ver)); } + +inline bool QWidget::testAttribute(Qt::WidgetAttribute attribute) const +{ + if (attribute < int(8*sizeof(uint))) + return data->widget_attributes & (1<(QObject::parent()); +} +inline void QWidget::setPaletteForegroundColor(const QColor &c) +{ QPalette p = palette(); p.setColor(foregroundRole(), c); setPalette(p); } +inline const QBrush& QWidget::backgroundBrush() const { return palette().brush(backgroundRole()); } +inline void QWidget::setBackgroundPixmap(const QPixmap &pm) +{ QPalette p = palette(); p.setBrush(backgroundRole(), QBrush(pm)); setPalette(p); } +inline const QPixmap *QWidget::backgroundPixmap() const { return 0; } +inline void QWidget::setBackgroundColor(const QColor &c) +{ QPalette p = palette(); p.setColor(backgroundRole(), c); setPalette(p); } +inline const QColor & QWidget::backgroundColor() const { return palette().color(backgroundRole()); } +inline const QColor &QWidget::foregroundColor() const { return palette().color(foregroundRole());} +inline const QColor &QWidget::eraseColor() const { return palette().color(backgroundRole()); } +inline void QWidget::setEraseColor(const QColor &c) +{ QPalette p = palette(); p.setColor(backgroundRole(), c); setPalette(p); } +inline const QPixmap *QWidget::erasePixmap() const { return 0; } +inline void QWidget::setErasePixmap(const QPixmap &pm) +{ QPalette p = palette(); p.setBrush(backgroundRole(), QBrush(pm)); setPalette(p); } +inline const QColor &QWidget::paletteForegroundColor() const { return palette().color(foregroundRole());} +inline const QColor &QWidget::paletteBackgroundColor() const { return palette().color(backgroundRole()); } +inline void QWidget::setPaletteBackgroundColor(const QColor &c) +{ QPalette p = palette(); p.setColor(backgroundRole(), c); setPalette(p); } +inline const QPixmap *QWidget::paletteBackgroundPixmap() const +{ return 0; } +inline void QWidget::setPaletteBackgroundPixmap(const QPixmap &pm) +{ QPalette p = palette(); p.setBrush(backgroundRole(), QBrush(pm)); setPalette(p); } +inline QT3_SUPPORT void QWidget::erase() { erase_helper(0, 0, data->crect.width(), data->crect.height()); } +inline QT3_SUPPORT void QWidget::erase(const QRect &r) { erase_helper(r.x(), r.y(), r.width(), r.height()); } +#endif + +#define QWIDGETSIZE_MAX ((1<<24)-1) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QWIDGET_H diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h new file mode 100644 index 0000000000..7826cab795 --- /dev/null +++ b/src/widgets/kernel/qwidget_p.h @@ -0,0 +1,1034 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGET_P_H +#define QWIDGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qwidget.h" +#include "private/qobject_p.h" +#include "QtCore/qrect.h" +#include "QtCore/qlocale.h" +#include "QtCore/qset.h" +#include "QtGui/qregion.h" +#include "QtGui/qsizepolicy.h" +#include "QtGui/qstyle.h" +#include "QtGui/qapplication.h" +#include +#include "QtGui/qgraphicsproxywidget.h" +#include "QtGui/qgraphicsscene.h" +#include "QtGui/qgraphicsview.h" +#include + +#ifdef Q_WS_WIN +#include "QtCore/qt_windows.h" +#include +#endif // Q_WS_WIN + +#ifdef Q_WS_X11 +#include "QtGui/qx11info_x11.h" +#endif + +#ifdef Q_WS_MAC +#include +#endif + +#if defined(Q_WS_QWS) +#include "QtGui/qinputcontext.h" +#include "QtGui/qscreen_qws.h" +#endif + +#if defined(Q_OS_SYMBIAN) +class RDrawableWindow; +class CCoeControl; +#endif + +QT_BEGIN_NAMESPACE + +// Extra QWidget data +// - to minimize memory usage for members that are seldom used. +// - top-level widgets have extra extra data to reduce cost further +#if defined(Q_WS_QWS) +class QWSManager; +#endif +#if defined(Q_WS_MAC) +class QCoreGraphicsPaintEnginePrivate; +#endif +#if defined(Q_WS_QPA) +class QWidgetWindow; +#endif +class QPaintEngine; +class QPixmap; +class QWidgetBackingStore; +class QGraphicsProxyWidget; +class QWidgetItemV2; + +class QStyle; + +class QUnifiedToolbarSurface; + +class Q_AUTOTEST_EXPORT QWidgetBackingStoreTracker +{ + +public: + QWidgetBackingStoreTracker(); + ~QWidgetBackingStoreTracker(); + + void create(QWidget *tlw); + void destroy(); + + void registerWidget(QWidget *w); + void unregisterWidget(QWidget *w); + void unregisterWidgetSubtree(QWidget *w); + + inline QWidgetBackingStore* data() + { + return m_ptr; + } + + inline QWidgetBackingStore* operator->() + { + return m_ptr; + } + + inline QWidgetBackingStore& operator*() + { + return *m_ptr; + } + + inline operator bool() const + { + return (0 != m_ptr); + } + +private: + Q_DISABLE_COPY(QWidgetBackingStoreTracker) + +private: + QWidgetBackingStore* m_ptr; + QSet m_widgets; +}; + +struct QTLWExtra { + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + QIcon *icon; // widget icon + QPixmap *iconPixmap; + QWidgetBackingStoreTracker backingStore; + QWindowSurface *windowSurface; + QPainter *sharedPainter; + + // Implicit pointers (shared_null). + QString caption; // widget caption + QString iconText; // widget icon text + QString role; // widget role + QString filePath; // widget file path + + // Other variables. + short incw, inch; // size increments + short basew, baseh; // base sizes + // frame strut, don't use these directly, use QWidgetPrivate::frameStrut() instead. + QRect frameStrut; + QRect normalGeometry; // used by showMin/maximized/FullScreen + Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + + // *************************** Cross-platform bit fields **************************** + uint opacity : 8; + uint posFromMove : 1; + uint sizeAdjusted : 1; + uint inTopLevelResize : 1; + uint inRepaint : 1; + uint embedded : 1; + + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 + uint spont_unmapped: 1; // window was spontaneously unmapped + uint dnd : 1; // DND properties installed + uint validWMState : 1; // is WM_STATE valid? + uint waitingForMapNotify : 1; // show() has been called, haven't got the MapNotify yet + WId parentWinId; // parent window Id (valid after reparenting) + WId userTimeWindow; // window id that contains user-time timestamp when WM supports a _NET_WM_USER_TIME_WINDOW atom + QPoint fullScreenOffset; +#ifndef QT_NO_XSYNC + WId syncUpdateCounter; + ulong syncRequestTimestamp; + qint32 newCounterValueHi; + quint32 newCounterValueLo; +#endif +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint hotkeyRegistered: 1; // Hot key from the STARTUPINFO has been registered. + HICON winIconBig; // internal big Windows icon + HICON winIconSmall; // internal small Windows icon +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + uint resizer : 4; + uint isSetGeometry : 1; + uint isMove : 1; + quint32 wattr; + quint32 wclass; + WindowGroupRef group; + IconRef windowIcon; // the current window icon, if set with setWindowIcon_sys. + quint32 savedWindowAttributesFromMaximized; // Saved attributes from when the calling updateMaximizeButton_sys() +#ifdef QT_MAC_USE_COCOA + // This value is just to make sure we maximize and restore to the right location, yet we allow apps to be maximized and + // manually resized. + // The name is misleading, since this is set when maximizing the window. It is a hint to saveGeometry(..) to record the + // starting position as 0,0 instead of the normal starting position. + bool wasMaximized; +#endif // QT_MAC_USE_COCOA + +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS +#ifndef QT_NO_QWS_MANAGER + QWSManager *qwsManager; +#endif +#elif defined(Q_OS_SYMBIAN) + uint inExpose : 1; // Prevents drawing recursion + uint nativeWindowTransparencyEnabled : 1; // Tracks native window transparency +#elif defined(Q_WS_QPA) + QWidgetWindow *window; + quint32 screenIndex; // index in qplatformscreenlist +#endif +}; + +struct QWExtra { + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + void *glContext; // if the widget is hijacked by QGLWindowSurface + QTLWExtra *topextra; // only useful for TLWs +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsProxyWidget *proxyWidget; // if the widget is embedded +#endif +#ifndef QT_NO_CURSOR + QCursor *curs; +#endif + QPointer style; + QPointer focus_proxy; + + // Implicit pointers (shared_empty/shared_null). + QRegion mask; // widget mask + QString styleSheet; + + // Other variables. + qint32 minw; + qint32 minh; // minimum size + qint32 maxw; + qint32 maxh; // maximum size + quint16 customDpiX; + quint16 customDpiY; + QSize staticContentsSize; + + // *************************** Cross-platform bit fields **************************** + uint explicitMinSize : 2; + uint explicitMaxSize : 2; + uint autoFillBackground : 1; + uint nativeChildrenForced : 1; + uint inRenderWithPainter : 1; + uint hasMask : 1; + + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_WIN) // <----------------------------------------------------------- WIN +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *dropTarget; // drop target + QList > oleDropWidgets; +#endif +#elif defined(Q_WS_X11) // <--------------------------------------------------------- X11 + uint compress_events : 1; + WId xDndProxy; // XDND forwarding to embedded windows +#elif defined(Q_WS_MAC) // <------------------------------------------------------ MAC +#ifdef QT_MAC_USE_COCOA + // Cocoa Mask stuff + QImage maskBits; + CGImageRef imageMask; +#endif +#elif defined(Q_OS_SYMBIAN) // <----------------------------------------------------- Symbian + uint activated : 1; // RWindowBase::Activated has been called + + /** + * If this bit is set, each native widget receives the signals from the + * Symbian control immediately before and immediately after draw ops are + * sent to the window server for this control: + * void beginNativePaintEvent(const QRect &paintRect); + * void endNativePaintEvent(const QRect &paintRect); + */ + uint receiveNativePaintEvents : 1; + + /** + * Defines the behaviour of QSymbianControl::Draw. + */ + enum NativePaintMode { + /** + * Normal drawing mode: blits the required region of the backing store + * via WSERV. + */ + Blit, + + /** + * Disable drawing for this widget. + */ + Disable, + + /** + * Paint zeros into the WSERV framebuffer, using BitGDI APIs. For windows + * with an EColor16MU display mode, zero is written only into the R, G and B + * channels of the pixel. + */ + ZeroFill, + + /** + * Blit backing store, propagating alpha channel into the framebuffer. + */ + BlitWriteAlpha, + + Default = Blit + }; + + NativePaintMode nativePaintMode; + +#endif +}; + +/*! + \internal + + Returns true if \a p or any of its parents enable the + Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and + QWidget::setParent() to determine whether it's necessary to embed the + widget into a QGraphicsProxyWidget or not. +*/ +static inline bool bypassGraphicsProxyWidget(const QWidget *p) +{ + while (p) { + if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) + return true; + p = p->parentWidget(); + } + return false; +} + +class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QWidget) + +public: + // *************************** Cross-platform *************************************** + enum DrawWidgetFlags { + DrawAsRoot = 0x01, + DrawPaintOnScreen = 0x02, + DrawRecursive = 0x04, + DrawInvisible = 0x08, + DontSubtractOpaqueChildren = 0x10, + DontSetCompositionMode = 0x20, + DontDrawOpaqueChildren = 0x40, + DontDrawNativeChildren = 0x80 + }; + + enum CloseMode { + CloseNoEvent, + CloseWithEvent, + CloseWithSpontaneousEvent + }; + + enum Direction { + DirectionNorth = 0x01, + DirectionEast = 0x10, + DirectionSouth = 0x02, + DirectionWest = 0x20 + }; + + // Functions. + explicit QWidgetPrivate(int version = QObjectPrivateVersion); + ~QWidgetPrivate(); + + QWExtra *extraData() const; + QTLWExtra *topData() const; + QTLWExtra *maybeTopData() const; + QPainter *sharedPainter() const; + void setSharedPainter(QPainter *painter); + QWidgetBackingStore *maybeBackingStore() const; + void init(QWidget *desktopWidget, Qt::WindowFlags f); + void create_sys(WId window, bool initializeWindow, bool destroyOldWindow); + void createRecursively(); + void createWinId(WId id = 0); + + void createTLExtra(); + void createExtra(); + void deleteExtra(); + void createSysExtra(); + void deleteSysExtra(); + void createTLSysExtra(); + void deleteTLSysExtra(); + void updateSystemBackground(); + void propagatePaletteChange(); + + void setPalette_helper(const QPalette &); + void resolvePalette(); + QPalette naturalWidgetPalette(uint inheritedMask) const; + + void setMask_sys(const QRegion &); +#ifdef Q_OS_SYMBIAN + void setSoftKeys_sys(const QList &softkeys); + void activateSymbianWindow(WId wid = 0); + void _q_delayedDestroy(WId winId); +#endif + + void raise_sys(); + void lower_sys(); + void stackUnder_sys(QWidget *); + + void setFocus_sys(); + + void updateFont(const QFont &); + inline void setFont_helper(const QFont &font) { + if (data.fnt == font && data.fnt.resolve() == font.resolve()) + return; + updateFont(font); + } + void resolveFont(); + QFont naturalWidgetFont(uint inheritedMask) const; + + void setLayoutDirection_helper(Qt::LayoutDirection); + void resolveLayoutDirection(); + + void setLocale_helper(const QLocale &l, bool forceUpdate = false); + void resolveLocale(); + + void setStyle_helper(QStyle *newStyle, bool propagate, bool metalHack = false); + void inheritStyle(); + + void setUpdatesEnabled_helper(bool ); + + void paintBackground(QPainter *, const QRegion &, int flags = DrawAsRoot) const; + bool isAboutToShow() const; + QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); + void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, + QWidget::RenderFlags renderFlags); + void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, + QWidget::RenderFlags renderFlags, bool readyToRender); + void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, + QPainter *sharedPainter = 0, QWidgetBackingStore *backingStore = 0); + + + void paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& children, int index, + const QRegion &rgn, const QPoint &offset, int flags +#ifdef Q_BACKINGSTORE_SUBSURFACES + , const QWindowSurface *currentSurface +#endif + , QPainter *sharedPainter, QWidgetBackingStore *backingStore); + + + QPainter *beginSharedPainter(); + bool endSharedPainter(); +#ifndef QT_NO_GRAPHICSVIEW + static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin); +#endif + QWindowSurface *createDefaultWindowSurface(); + QWindowSurface *createDefaultWindowSurface_sys(); + void repaint_sys(const QRegion &rgn); + + QRect clipRect() const; + QRegion clipRegion() const; + void subtractOpaqueChildren(QRegion &rgn, const QRect &clipRect) const; + void subtractOpaqueSiblings(QRegion &source, bool *hasDirtySiblingsAbove = 0, + bool alsoNonOpaque = false) const; + void clipToEffectiveMask(QRegion ®ion) const; + void updateIsOpaque(); + void setOpaque(bool opaque); + void updateIsTranslucent(); + bool paintOnScreen() const; +#ifndef QT_NO_GRAPHICSEFFECT + void invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + const QRegion &getOpaqueChildren() const; + void setDirtyOpaqueRegion(); + + bool close_helper(CloseMode mode); + + void setWindowIcon_helper(); + void setWindowIcon_sys(bool forceReset = false); + void setWindowOpacity_sys(qreal opacity); + void adjustQuitOnCloseAttribute(); + + void scrollChildren(int dx, int dy); + void moveRect(const QRect &, int dx, int dy); + void scrollRect(const QRect &, int dx, int dy); + void invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize); + // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). + void invalidateBuffer(const QRegion &); + void invalidateBuffer(const QRect &); + bool isOverlapped(const QRect&) const; + void syncBackingStore(); + void syncBackingStore(const QRegion ®ion); + + void reparentFocusWidgets(QWidget *oldtlw); + + static int pointToRect(const QPoint &p, const QRect &r); + + void setWinId(WId); + void showChildren(bool spontaneous); + void hideChildren(bool spontaneous); + void setParent_sys(QWidget *parent, Qt::WindowFlags); + void scroll_sys(int dx, int dy); + void scroll_sys(int dx, int dy, const QRect &r); + void deactivateWidgetCleanup(); + void setGeometry_sys(int, int, int, int, bool); + void sendPendingMoveAndResizeEvents(bool recursive = false, bool disableUpdates = false); + void activateChildLayoutsRecursively(); + void show_recursive(); + void show_helper(); + void show_sys(); + void hide_sys(); + void hide_helper(); + void _q_showIfNotHidden(); + + void setEnabled_helper(bool); + void registerDropSite(bool); + static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); + + void updateFrameStrut(); + QRect frameStrut() const; + +#ifdef QT_KEYPAD_NAVIGATION + static bool navigateToDirection(Direction direction); + static QWidget *widgetInNavigationDirection(Direction direction); + static bool canKeypadNavigate(Qt::Orientation orientation); + static bool inTabWidget(QWidget *widget); +#endif + + void setWindowIconText_sys(const QString &cap); + void setWindowIconText_helper(const QString &cap); + void setWindowTitle_sys(const QString &cap); + +#ifndef QT_NO_CURSOR + void setCursor_sys(const QCursor &cursor); + void unsetCursor_sys(); +#endif + + void setWindowTitle_helper(const QString &cap); + void setWindowFilePath_helper(const QString &filePath); + + bool setMinimumSize_helper(int &minw, int &minh); + bool setMaximumSize_helper(int &maxw, int &maxh); + virtual bool hasHeightForWidth() const; + void setConstraints_sys(); + bool pointInsideRectAndMask(const QPoint &) const; + QWidget *childAt_helper(const QPoint &, bool) const; + QWidget *childAtRecursiveHelper(const QPoint &p, bool, bool includeFrame = false) const; + void updateGeometry_helper(bool forceUpdate); + + void getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const; + void setLayoutItemMargins(int left, int top, int right, int bottom); + void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = 0); + + // aboutToDestroy() is called just before the contents of + // QWidget::destroy() is executed. It's used to signal QWidget + // sub-classes that their internals are about to be released. + virtual void aboutToDestroy() {} + + QInputContext *assignedInputContext() const; + QInputContext *inputContext() const; + inline QWidget *effectiveFocusWidget() { + QWidget *w = q_func(); + while (w->focusProxy()) + w = w->focusProxy(); + return w; + } + + void setModal_sys(); + + // This is an helper function that return the available geometry for + // a widget and takes care is this one is in QGraphicsView. + // If the widget is not embed in a scene then the geometry available is + // null, we let QDesktopWidget decide for us. + static QRect screenGeometry(const QWidget *widget) + { + QRect screen; +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsProxyWidget *ancestorProxy = widget->d_func()->nearestGraphicsProxyWidget(widget); + //It's embedded if it has an ancestor + if (ancestorProxy) { + if (!bypassGraphicsProxyWidget(widget) && ancestorProxy->scene() != 0) { + // One view, let be smart and return the viewport rect then the popup is aligned + if (ancestorProxy->scene()->views().size() == 1) { + QGraphicsView *view = ancestorProxy->scene()->views().at(0); + screen = view->mapToScene(view->viewport()->rect()).boundingRect().toRect(); + } else { + screen = ancestorProxy->scene()->sceneRect().toRect(); + } + } + } +#endif + return screen; + } + + inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) + { + Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); + redirectDev = replacement; + redirectOffset = offset; + } + + inline QPaintDevice *redirected(QPoint *offset) const + { + if (offset) + *offset = redirectDev ? redirectOffset : QPoint(); + return redirectDev; + } + + inline void restoreRedirected() + { redirectDev = 0; } + + inline void enforceNativeChildren() + { + if (!extra) + createExtra(); + + if (extra->nativeChildrenForced) + return; + extra->nativeChildrenForced = 1; + + for (int i = 0; i < children.size(); ++i) { + if (QWidget *child = qobject_cast(children.at(i))) + child->setAttribute(Qt::WA_NativeWindow); + } + } + + inline bool nativeChildrenForced() const + { + return extra ? extra->nativeChildrenForced : false; + } + + inline QRect effectiveRectFor(const QRect &rect) const + { +#ifndef QT_NO_GRAPHICSEFFECT + if (graphicsEffect && graphicsEffect->isEnabled()) + return graphicsEffect->boundingRectFor(rect).toAlignedRect(); +#endif //QT_NO_GRAPHICSEFFECT + return rect; + } + + QSize adjustedSize() const; + + inline void handleSoftwareInputPanel(Qt::MouseButton button, bool clickCausedFocus) + { + Q_Q(QWidget); + if (button == Qt::LeftButton && qApp->autoSipEnabled()) { + QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel( + q->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel)); + if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(q, &event); + } + } + } + +#ifndef Q_WS_QWS // Almost cross-platform :-) + void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + + inline QPoint mapToWS(const QPoint &p) const + { return p - data.wrect.topLeft(); } + + inline QPoint mapFromWS(const QPoint &p) const + { return p + data.wrect.topLeft(); } + + inline QRect mapToWS(const QRect &r) const + { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } + + inline QRect mapFromWS(const QRect &r) const + { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } +#endif + + // Variables. + // Regular pointers (keep them together to avoid gaps on 64 bit architectures). + QWExtra *extra; + QWidget *focus_next; + QWidget *focus_prev; + QWidget *focus_child; + QLayout *layout; + QRegion *needsFlush; + QPaintDevice *redirectDev; + QWidgetItemV2 *widgetItem; + QPaintEngine *extraPaintEngine; + mutable const QMetaObject *polished; + QGraphicsEffect *graphicsEffect; + // All widgets are added into the allWidgets set. Once + // they receive a window id they are also added to the mapper. + // This should just ensure that all widgets are deleted by QApplication + static QWidgetMapper *mapper; + static QWidgetSet *allWidgets; +#if !defined(QT_NO_IM) + QPointer ic; + Qt::InputMethodHints imHints; +#endif +#ifdef QT_KEYPAD_NAVIGATION + static QPointer editingWidget; +#endif + + // Implicit pointers (shared_null/shared_empty). + QRegion opaqueChildren; + QRegion dirty; +#ifndef QT_NO_TOOLTIP + QString toolTip; +#endif +#ifndef QT_NO_STATUSTIP + QString statusTip; +#endif +#ifndef QT_NO_WHATSTHIS + QString whatsThis; +#endif +#ifndef QT_NO_ACCESSIBILITY + QString accessibleName; + QString accessibleDescription; +#endif + + // Other variables. + uint inheritedFontResolveMask; + uint inheritedPaletteResolveMask; + short leftmargin; + short topmargin; + short rightmargin; + short bottommargin; + signed char leftLayoutItemMargin; + signed char topLayoutItemMargin; + signed char rightLayoutItemMargin; + signed char bottomLayoutItemMargin; + static int instanceCounter; // Current number of widget instances + static int maxInstances; // Maximum number of widget instances + Qt::HANDLE hd; + QWidgetData data; + QSizePolicy size_policy; + QLocale locale; + QPoint redirectOffset; +#ifndef QT_NO_ACTION + QList actions; +#endif +#ifndef QT_NO_GESTURES + QMap gestureContext; +#endif + + // Bit fields. + uint high_attributes[4]; // the low ones are in QWidget::widget_attributes + QPalette::ColorRole fg_role : 8; + QPalette::ColorRole bg_role : 8; + uint dirtyOpaqueChildren : 1; + uint isOpaque : 1; + uint inDirtyList : 1; + uint isScrolled : 1; + uint isMoved : 1; + uint isGLWidget : 1; + uint usesDoubleBufferedGLContext : 1; +#ifndef QT_NO_IM + uint inheritsInputMethodHints : 1; +#endif + + // *************************** Platform specific ************************************ +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 + QX11Info xinfo; + Qt::HANDLE picture; + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + + void setWindowRole(); + void sendStartupMessage(const char *message) const; + void setNetWmWindowTypes(); + void x11UpdateIsOpaque(); + bool isBackgroundInherited() const; + void updateX11AcceptFocus(); + QPoint mapToGlobal(const QPoint &pos) const; + QPoint mapFromGlobal(const QPoint &pos) const; +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() +#ifndef QT_NO_GESTURES + uint nativeGesturePanEnabled : 1; +#endif + bool shouldShowMaximizeButton(); + void winUpdateIsOpaque(); + void reparentChildren(); +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *registerOleDnd(QWidget *widget); + void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); +#endif + void grabMouseWhileInWindow(); + void registerTouchWindow(); + void winSetupGestures(); +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + // This is new stuff + uint needWindowChange : 1; + + // Each wiget keeps a list of all its child and grandchild OpenGL widgets. + // This list is used to update the gl context whenever a parent and a granparent + // moves, and also to check for intersections with gl widgets within the window + // when a widget moves. + struct GlWidgetInfo + { + GlWidgetInfo(QWidget *widget) : widget(widget), lastUpdateWidget(0) { } + bool operator==(const GlWidgetInfo &other) const { return (widget == other.widget); } + QWidget * widget; + QWidget * lastUpdateWidget; + }; + + // dirtyOnWidget contains the areas in the widget that needs to be repained, + // in the same way as dirtyOnScreen does for the window. Areas are added in + // dirtyWidget_sys and cleared in the paint event. In scroll_sys we then use + // this information repaint invalid areas when widgets are scrolled. + QRegion dirtyOnWidget; + EventHandlerRef window_event; + QList glWidgets; + + //these are here just for code compat (HIViews) + Qt::HANDLE qd_hd; + + void macUpdateSizeAttribute(); + void macUpdateHideOnSuspend(); + void macUpdateOpaqueSizeGrip(); + void macUpdateIgnoreMouseEvents(); + void macUpdateMetalAttribute(); + void macUpdateIsOpaque(); + void macSetNeedsDisplay(QRegion region); + void setEnabled_helper_sys(bool enable); + bool isRealWindow() const; + void adjustWithinMaxAndMinSize(int &w, int &h); + void applyMaxAndMinSizeOnWindow(); + void update_sys(const QRect &rect); + void update_sys(const QRegion &rgn); + void setGeometry_sys_helper(int, int, int, int, bool); + void setWindowModified_sys(bool b); + void updateMaximizeButton_sys(); + void setWindowFilePath_sys(const QString &filePath); + void createWindow_sys(); + void recreateMacWindow(); +#ifndef QT_MAC_USE_COCOA + void initWindowPtr(); + void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); +#else + void setSubWindowStacking(bool set); + void setWindowLevel(); + void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); + void syncCocoaMask(); + void finishCocoaMaskSetup(); + void syncUnifiedMode(); + // Did we add the drawRectOriginal method? + bool drawRectOriginalAdded; + // Is the original drawRect method available? + bool originalDrawMethod; + // Do we need to change the methods? + bool changeMethods; + + // Unified toolbar variables + bool isInUnifiedToolbar; + QUnifiedToolbarSurface *unifiedSurface; + QPoint toolbar_offset; + QWidget *toolbar_ancestor; + bool flushRequested; + bool touchEventsEnabled; +#endif // QT_MAC_USE_COCOA + void determineWindowClass(); + void transferChildren(); + bool qt_mac_dnd_event(uint, DragRef); + void toggleDrawers(bool); + //mac event functions + static bool qt_create_root_win(); + static void qt_clean_root_win(); + static bool qt_mac_update_sizer(QWidget *, int up = 0); + static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); + static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); + static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); + void registerTouchWindow(bool enable = true); +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS + void setMaxWindowState_helper(); + void setFullScreenSize_helper(); + void moveSurface(QWindowSurface *surface, const QPoint &offset); + QRegion localRequestedRegion() const; + QRegion localAllocatedRegion() const; + + friend class QWSManager; + friend class QWSManagerPrivate; + friend class QDecoration; +#ifndef QT_NO_CURSOR + void updateCursor() const; +#endif + QScreen* getScreen() const; +#elif defined(Q_WS_QPA) // <--------------------------------------------------------- QPA + void setMaxWindowState_helper(); + void setFullScreenSize_helper(); +#ifndef QT_NO_CURSOR + void updateCursor() const; +#endif +#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + int symbianScreenNumber; // only valid for desktop widget and top-levels + bool fixNativeOrientationCalled; + void s60UpdateIsOpaque(); + void reparentChildren(); + void registerTouchWindow(); +#endif + +}; + +struct QWidgetPaintContext +{ + inline QWidgetPaintContext(QPaintDevice *d, const QRegion &r, const QPoint &o, int f, + QPainter *p, QWidgetBackingStore *b) + : pdev(d), rgn(r), offset(o), flags(f), sharedPainter(p), backingStore(b), painter(0) {} + + QPaintDevice *pdev; + QRegion rgn; + QPoint offset; + int flags; + QPainter *sharedPainter; + QWidgetBackingStore *backingStore; + QPainter *painter; +}; + +#ifndef QT_NO_GRAPHICSEFFECT +class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate +{ +public: + QWidgetEffectSourcePrivate(QWidget *widget) + : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0), updateDueToGraphicsEffect(false) + {} + + inline void detach() + { m_widget->d_func()->graphicsEffect = 0; } + + inline const QGraphicsItem *graphicsItem() const + { return 0; } + + inline const QWidget *widget() const + { return m_widget; } + + inline void update() + { + updateDueToGraphicsEffect = true; + m_widget->update(); + updateDueToGraphicsEffect = false; + } + + inline bool isPixmap() const + { return false; } + + inline void effectBoundingRectChanged() + { + // ### This function should take a rect parameter; then we can avoid + // updating too much on the parent widget. + if (QWidget *parent = m_widget->parentWidget()) + parent->update(); + else + update(); + } + + inline const QStyleOption *styleOption() const + { return 0; } + + inline QRect deviceRect() const + { return m_widget->window()->rect(); } + + QRectF boundingRect(Qt::CoordinateSystem system) const; + void draw(QPainter *p); + QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset, + QGraphicsEffect::PixmapPadMode mode) const; + + QWidget *m_widget; + QWidgetPaintContext *context; + QTransform lastEffectTransform; + bool updateDueToGraphicsEffect; +}; +#endif //QT_NO_GRAPHICSEFFECT + +inline QWExtra *QWidgetPrivate::extraData() const +{ + return extra; +} + +inline QTLWExtra *QWidgetPrivate::topData() const +{ + const_cast(this)->createTLExtra(); + return extra->topextra; +} + +inline QTLWExtra *QWidgetPrivate::maybeTopData() const +{ + return extra ? extra->topextra : 0; +} + +inline QPainter *QWidgetPrivate::sharedPainter() const +{ + Q_Q(const QWidget); + QTLWExtra *x = q->window()->d_func()->maybeTopData(); + return x ? x->sharedPainter : 0; +} + +inline void QWidgetPrivate::setSharedPainter(QPainter *painter) +{ + Q_Q(QWidget); + QTLWExtra *x = q->window()->d_func()->topData(); + x->sharedPainter = painter; +} + +inline bool QWidgetPrivate::pointInsideRectAndMask(const QPoint &p) const +{ + Q_Q(const QWidget); + return q->rect().contains(p) && (!extra || !extra->hasMask || q->testAttribute(Qt::WA_MouseNoMask) + || extra->mask.contains(p)); +} + +inline QWidgetBackingStore *QWidgetPrivate::maybeBackingStore() const +{ + Q_Q(const QWidget); + QTLWExtra *x = q->window()->d_func()->maybeTopData(); + return x ? x->backingStore.data() : 0; +} + +QT_END_NAMESPACE + +#endif // QWIDGET_P_H diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp new file mode 100644 index 0000000000..d239e6d652 --- /dev/null +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -0,0 +1,824 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "QtGui/qwidget.h" +#include "QtGui/qevent.h" +#include "QtGui/qapplication.h" +#include "QtGui/private/qbackingstore_p.h" +#include "QtGui/private/qwidget_p.h" +#include "QtGui/private/qwidgetwindow_qpa_p.h" +#include "QtGui/private/qapplication_p.h" +#include "QtGui/qdesktopwidget.h" +#include "QtGui/qplatformwindow_qpa.h" +#include "QtGui/qplatformglcontext_qpa.h" + +#include + +QT_BEGIN_NAMESPACE + +void q_createNativeChildrenAndSetParent(QWindow *parentWindow, const QWidget *parentWidget) +{ + QObjectList children = parentWidget->children(); + for (int i = 0; i < children.size(); i++) { + if (children.at(i)->isWidgetType()) { + const QWidget *childWidget = qobject_cast(children.at(i)); + if (childWidget) { // should not be necessary + if (childWidget->testAttribute(Qt::WA_NativeWindow)) { + if (!childWidget->windowHandle()) + childWidget->winId(); + if (childWidget->windowHandle()) + childWidget->windowHandle()->setParent(parentWindow); + } else { + q_createNativeChildrenAndSetParent(parentWindow,childWidget); + } + } + } + } + +} + +void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) +{ + Q_Q(QWidget); + + Q_UNUSED(window); + Q_UNUSED(initializeWindow); + Q_UNUSED(destroyOldWindow); + + Qt::WindowFlags flags = data.window_flags; + + if ((!q->testAttribute(Qt::WA_NativeWindow) && !q->isWindow()) || q->windowType() == Qt::Desktop ) + return; // we only care about real toplevels + + QWindowSurface *surface = q->windowSurface(); + + QWindow *win = topData()->window; + + if (!q->isWindow()) { + if (QWidget *nativeParent = q->nativeParentWidget()) { + if (nativeParent->windowHandle()) + win->setParent(nativeParent->windowHandle()); + } + } + + win->setWindowFlags(data.window_flags); + win->setGeometry(q->geometry()); + win->create(); + + data.window_flags = win->windowFlags(); + + if (!surface ) { + if (win) { + surface = QGuiApplicationPrivate::platformIntegration()->createWindowSurface(win, win->winId()); + q->setWindowSurface(surface); + } else { + q->setAttribute(Qt::WA_PaintOnScreen,true); + } + } + + setWinId(win->winId()); + +// first check children. and create them if necessary +// q_createNativeChildrenAndSetParent(q->windowHandle(),q); + + QGuiApplicationPrivate::platformIntegration()->moveToScreen(win, topData()->screenIndex); +// qDebug() << "create_sys" << q << q->internalWinId(); +} + +void QWidget::destroy(bool destroyWindow, bool destroySubWindows) +{ + Q_D(QWidget); + + if ((windowType() == Qt::Popup)) + qApp->d_func()->closePopup(this); + + //### we don't have proper focus event handling yet + if (this == QApplicationPrivate::active_window) + QApplication::setActiveWindow(0); + + if (windowType() != Qt::Desktop) { + if (destroySubWindows) { + QObjectList childList(children()); + for (int i = 0; i < childList.size(); i++) { + QWidget *widget = qobject_cast(childList.at(i)); + if (widget && widget->testAttribute(Qt::WA_NativeWindow)) { + if (widget->windowHandle()) { + widget->destroy(); + } + } + } + } + if (destroyWindow) { + d->deleteTLSysExtra(); + } else { + if (parentWidget() && parentWidget()->testAttribute(Qt::WA_WState_Created)) { + d->hide_sys(); + } + } + } +} + +void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) +{ + Q_Q(QWidget); + + Qt::WindowFlags oldFlags = data.window_flags; + + int targetScreen = -1; + // Handle a request to move the widget to a particular screen + if (newparent && newparent->windowType() == Qt::Desktop) { + // make sure the widget is created on the same screen as the + // programmer specified desktop widget + + // get the desktop's screen number + targetScreen = newparent->window()->d_func()->topData()->screenIndex; + newparent = 0; + } + + if (parent != newparent) { + QObjectPrivate::setParent_helper(newparent); //### why does this have to be done in the _sys function??? + if (q->windowHandle() && newparent) { + QWidget * parentWithWindow = newparent->windowHandle()? newparent : newparent->nativeParentWidget(); + if (parentWithWindow && parentWithWindow->windowHandle()) { + q->windowHandle()->setParent(parentWithWindow->windowHandle()); + } + } + + } + + if (!newparent) { + f |= Qt::Window; + if (targetScreen == -1) { + if (parent) + targetScreen = q->parentWidget()->window()->d_func()->topData()->screenIndex; + } + } + + bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); + + // Reparenting toplevel to child + if (!(f&Qt::Window) && (oldFlags&Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) { + //qDebug() << "setParent_sys() change from toplevel"; + q->destroy(); + } + + data.window_flags = f; + q->setAttribute(Qt::WA_WState_Created, false); + q->setAttribute(Qt::WA_WState_Visible, false); + q->setAttribute(Qt::WA_WState_Hidden, false); + + if (q->isWindow() || (!newparent || newparent->isVisible()) || explicitlyHidden) + q->setAttribute(Qt::WA_WState_Hidden); + q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); + + // move the window to the selected screen + if (!newparent && targetScreen != -1) { + if (maybeTopData()) + maybeTopData()->screenIndex = targetScreen; + // only if it is already created + if (q->testAttribute(Qt::WA_WState_Created)) { + QPlatformIntegration *platform = QGuiApplicationPrivate::platformIntegration(); + platform->moveToScreen(q->windowHandle(), targetScreen); + } + } +} + +QPoint QWidget::mapToGlobal(const QPoint &pos) const +{ + int x=pos.x(), y=pos.y(); + const QWidget* w = this; + while (w) { + x += w->data->crect.x(); + y += w->data->crect.y(); + w = w->isWindow() ? 0 : w->parentWidget(); + } + return QPoint(x, y); +} + +QPoint QWidget::mapFromGlobal(const QPoint &pos) const +{ + int x=pos.x(), y=pos.y(); + const QWidget* w = this; + while (w) { + x -= w->data->crect.x(); + y -= w->data->crect.y(); + w = w->isWindow() ? 0 : w->parentWidget(); + } + return QPoint(x, y); +} + +void QWidgetPrivate::updateSystemBackground() {} + +#ifndef QT_NO_CURSOR +void QWidgetPrivate::setCursor_sys(const QCursor &cursor) +{ + Q_UNUSED(cursor); + Q_Q(QWidget); + if (q->isVisible()) + qt_qpa_set_cursor(q, false); +} + +void QWidgetPrivate::unsetCursor_sys() +{ + Q_Q(QWidget); + if (q->isVisible()) + qt_qpa_set_cursor(q, false); +} + +void QWidgetPrivate::updateCursor() const +{ + // XXX +} + +#endif //QT_NO_CURSOR + +void QWidgetPrivate::setWindowTitle_sys(const QString &caption) +{ + Q_Q(QWidget); + if (!q->isWindow()) + return; + + if (QWindow *window = q->windowHandle()) + window->setWindowTitle(caption); + +} + +void QWidgetPrivate::setWindowIcon_sys(bool /*forceReset*/) +{ +} + +void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) +{ + Q_UNUSED(iconText); +} + +QWidget *qt_pressGrab = 0; +QWidget *qt_mouseGrb = 0; +static QWidget *keyboardGrb = 0; + +void QWidget::grabMouse() +{ + if (qt_mouseGrb) + qt_mouseGrb->releaseMouse(); + + // XXX + //qwsDisplay()->grabMouse(this,true); + + qt_mouseGrb = this; + qt_pressGrab = 0; +} + +#ifndef QT_NO_CURSOR +void QWidget::grabMouse(const QCursor &cursor) +{ + Q_UNUSED(cursor); + + if (qt_mouseGrb) + qt_mouseGrb->releaseMouse(); + + // XXX + //qwsDisplay()->grabMouse(this,true); + //qwsDisplay()->selectCursor(this, cursor.handle()); + qt_mouseGrb = this; + qt_pressGrab = 0; +} +#endif + +void QWidget::releaseMouse() +{ + if (qt_mouseGrb == this) { + // XXX + //qwsDisplay()->grabMouse(this,false); + qt_mouseGrb = 0; + } +} + +void QWidget::grabKeyboard() +{ + if (keyboardGrb) + keyboardGrb->releaseKeyboard(); + // XXX + //qwsDisplay()->grabKeyboard(this, true); + keyboardGrb = this; +} + +void QWidget::releaseKeyboard() +{ + if (keyboardGrb == this) { + // XXX + //qwsDisplay()->grabKeyboard(this, false); + keyboardGrb = 0; + } +} + +QWidget *QWidget::mouseGrabber() +{ + if (qt_mouseGrb) + return qt_mouseGrb; + return qt_pressGrab; +} + +QWidget *QWidget::keyboardGrabber() +{ + return keyboardGrb; +} + +void QWidget::activateWindow() +{ + if (windowHandle()) + windowHandle()->requestActivateWindow(); +} + +void QWidgetPrivate::show_sys() +{ + Q_Q(QWidget); + q->setAttribute(Qt::WA_Mapped); + if (q->testAttribute(Qt::WA_DontShowOnScreen)) { + invalidateBuffer(q->rect()); + return; + } + + QApplication::postEvent(q, new QUpdateLaterEvent(q->rect())); + + if (!q->isWindow() && !q->testAttribute(Qt::WA_NativeWindow)) + return; + + QWindow *window = q->windowHandle(); + if (window) { + QRect geomRect = q->geometry(); + if (!q->isWindow()) { + QPoint topLeftOfWindow = q->mapTo(q->nativeParentWidget(),QPoint()); + geomRect.moveTopLeft(topLeftOfWindow); + } + const QRect windowRect = window->geometry(); + if (windowRect != geomRect) { + window->setGeometry(geomRect); + } + if (QWindowSurface *surface = q->windowSurface()) { + if (windowRect.size() != geomRect.size()) { + surface->resize(geomRect.size()); + } + } + if (window) + window->setVisible(true); + } +} + + +void QWidgetPrivate::hide_sys() +{ + Q_Q(QWidget); + q->setAttribute(Qt::WA_Mapped, false); + if (!q->isWindow()) { + QWidget *p = q->parentWidget(); + if (p &&p->isVisible()) { + invalidateBuffer(q->rect()); + } + return; + } + if (QWindow *window = q->windowHandle()) { + window->setVisible(false); + } + + //### we don't yet have proper focus event handling + if (q == QApplicationPrivate::active_window) + QApplication::setActiveWindow(0); + +} + +void QWidgetPrivate::setMaxWindowState_helper() +{ + setFullScreenSize_helper(); //### decoration size +} + +void QWidgetPrivate::setFullScreenSize_helper() +{ + Q_Q(QWidget); + + const uint old_state = data.in_set_window_state; + data.in_set_window_state = 1; + + const QRect screen = qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(q)); + q->move(screen.topLeft()); + q->resize(screen.size()); + + data.in_set_window_state = old_state; +} + +static Qt::WindowStates effectiveState(Qt::WindowStates state) + { + if (state & Qt::WindowMinimized) + return Qt::WindowMinimized; + else if (state & Qt::WindowFullScreen) + return Qt::WindowFullScreen; + else if (state & Qt::WindowMaximized) + return Qt::WindowMaximized; + return Qt::WindowNoState; + } + +void QWidget::setWindowState(Qt::WindowStates newstate) +{ + Q_D(QWidget); + Qt::WindowStates oldstate = windowState(); + if (oldstate == newstate) + return; + if (isWindow() && !testAttribute(Qt::WA_WState_Created)) + create(); + + data->window_state = newstate; + data->in_set_window_state = 1; + bool needShow = false; + Qt::WindowStates newEffectiveState = effectiveState(newstate); + Qt::WindowStates oldEffectiveState = effectiveState(oldstate); + if (isWindow() && newEffectiveState != oldEffectiveState) { + d->createTLExtra(); + if (oldEffectiveState == Qt::WindowNoState) { //normal + d->topData()->normalGeometry = geometry(); + } else if (oldEffectiveState == Qt::WindowFullScreen) { + setParent(0, d->topData()->savedFlags); + needShow = true; + } else if (oldEffectiveState == Qt::WindowMinimized) { + needShow = true; + } + + if (newEffectiveState == Qt::WindowMinimized) { + //### not ideal... + hide(); + needShow = false; + } else if (newEffectiveState == Qt::WindowFullScreen) { + d->topData()->savedFlags = windowFlags(); + setParent(0, Qt::FramelessWindowHint | (windowFlags() & Qt::WindowStaysOnTopHint)); + d->setFullScreenSize_helper(); + raise(); + needShow = true; + } else if (newEffectiveState == Qt::WindowMaximized) { + createWinId(); + d->setMaxWindowState_helper(); + } else { //normal + QRect r = d->topData()->normalGeometry; + if (r.width() >= 0) { + d->topData()->normalGeometry = QRect(0,0,-1,-1); + setGeometry(r); + } + } + } + data->in_set_window_state = 0; + + if (needShow) + show(); + + if (newstate & Qt::WindowActive) + activateWindow(); + + QWindowStateChangeEvent e(oldstate); + QApplication::sendEvent(this, &e); +} + +void QWidgetPrivate::setFocus_sys() +{ + +} + +void QWidgetPrivate::raise_sys() +{ + Q_Q(QWidget); + if (q->isWindow()) { + q->windowHandle()->raise(); + } +} + +void QWidgetPrivate::lower_sys() +{ + Q_Q(QWidget); + if (q->isWindow()) { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + q->windowHandle()->lower(); + } else if (QWidget *p = q->parentWidget()) { + setDirtyOpaqueRegion(); + p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); + } +} + +void QWidgetPrivate::stackUnder_sys(QWidget*) +{ + Q_Q(QWidget); + if (QWidget *p = q->parentWidget()) { + setDirtyOpaqueRegion(); + p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); + } +} + +void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) +{ + Q_Q(QWidget); + if (extra) { // any size restrictions? + w = qMin(w,extra->maxw); + h = qMin(h,extra->maxh); + w = qMax(w,extra->minw); + h = qMax(h,extra->minh); + } + + QPoint oldp = q->geometry().topLeft(); + QSize olds = q->size(); + QRect r(x, y, w, h); + + bool isResize = olds != r.size(); + isMove = oldp != r.topLeft(); //### why do we have isMove as a parameter? + + + // We only care about stuff that changes the geometry, or may + // cause the window manager to change its state + if (r.size() == olds && oldp == r.topLeft()) + return; + + if (!data.in_set_window_state) { + q->data->window_state &= ~Qt::WindowMaximized; + q->data->window_state &= ~Qt::WindowFullScreen; + if (q->isWindow()) + topData()->normalGeometry = QRect(0, 0, -1, -1); + } + + QPoint oldPos = q->pos(); + data.crect = r; + + if (q->isVisible()) { + if (q->windowHandle()) { + if (q->isWindow()) { + q->windowHandle()->setGeometry(q->geometry()); + } else { + QPoint posInNativeParent = q->mapTo(q->nativeParentWidget(),QPoint()); + q->windowHandle()->setGeometry(QRect(posInNativeParent,r.size())); + } + const QWidgetBackingStore *bs = maybeBackingStore(); + if (bs->windowSurface) { + if (isResize) + bs->windowSurface->resize(r.size()); + } + } else { + if (isMove && !isResize) + moveRect(QRect(oldPos, olds), x - oldPos.x(), y - oldPos.y()); + else + invalidateBuffer_resizeHelper(oldPos, olds); + } + + if (isMove) { + QMoveEvent e(q->pos(), oldPos); + QApplication::sendEvent(q, &e); + } + if (isResize) { + QResizeEvent e(r.size(), olds); + QApplication::sendEvent(q, &e); + if (q->windowHandle()) + q->update(); + } + } else { // not visible + if (isMove && q->pos() != oldPos) + q->setAttribute(Qt::WA_PendingMoveEvent, true); + if (isResize) + q->setAttribute(Qt::WA_PendingResizeEvent, true); + } + +} + +void QWidgetPrivate::setConstraints_sys() +{ +} + +void QWidgetPrivate::scroll_sys(int dx, int dy) +{ + Q_Q(QWidget); + scrollChildren(dx, dy); + scrollRect(q->rect(), dx, dy); +} + +void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) +{ + scrollRect(r, dx, dy); +} + +int QWidget::metric(PaintDeviceMetric m) const +{ + Q_D(const QWidget); + + QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(windowHandle()); + if (!screen) { + if (m == PdmDpiX || m == PdmDpiY) + return 72; + return QPaintDevice::metric(m); + } + int val; + if (m == PdmWidth) { + val = data->crect.width(); + } else if (m == PdmWidthMM) { + val = data->crect.width() * screen->physicalSize().width() / screen->geometry().width(); + } else if (m == PdmHeight) { + val = data->crect.height(); + } else if (m == PdmHeightMM) { + val = data->crect.height() * screen->physicalSize().height() / screen->geometry().height(); + } else if (m == PdmDepth) { + return screen->depth(); + } else if (m == PdmDpiX || m == PdmPhysicalDpiX) { + if (d->extra && d->extra->customDpiX) + return d->extra->customDpiX; + else if (d->parent) + return static_cast(d->parent)->metric(m); + return qRound(screen->geometry().width() / double(screen->physicalSize().width() / 25.4)); + } else if (m == PdmDpiY || m == PdmPhysicalDpiY) { + if (d->extra && d->extra->customDpiY) + return d->extra->customDpiY; + else if (d->parent) + return static_cast(d->parent)->metric(m); + return qRound(screen->geometry().height() / double(screen->physicalSize().height() / 25.4)); + } else { + val = QPaintDevice::metric(m);// XXX + } + return val; +} + +/*! + \preliminary + + Returns the QPlatformWindow this widget will be drawn into. +*/ +QWindow *QWidget::windowHandle() const +{ + Q_D(const QWidget); + QTLWExtra *extra = d->maybeTopData(); + if (extra && extra->window) + return extra->window; + + return 0; +} + +void QWidgetPrivate::createSysExtra() +{ +} + +void QWidgetPrivate::deleteSysExtra() +{ + +} + +void QWidgetPrivate::createTLSysExtra() +{ + Q_Q(QWidget); + extra->topextra->screenIndex = 0; + extra->topextra->window = new QWidgetWindow(q); +} + +void QWidgetPrivate::deleteTLSysExtra() +{ + if (extra && extra->topextra) { + //the toplevel might have a context with a "qglcontext associated with it. We need to + //delete the qglcontext before we delete the qplatformglcontext. + //One unfortunate thing about this is that we potentially create a glContext just to + //delete it straight afterwards. + if (extra->topextra->window) { + extra->topextra->window->destroy(); + } + setWinId(0); + //hmmm. should we delete window.. + delete extra->topextra->window; + extra->topextra->window = 0; + } +} + +void QWidgetPrivate::registerDropSite(bool on) +{ + Q_UNUSED(on); +} + +void QWidgetPrivate::setMask_sys(const QRegion ®ion) +{ + Q_UNUSED(region); + // XXX +} + +void QWidgetPrivate::updateFrameStrut() +{ + // XXX +} + +void QWidgetPrivate::setWindowOpacity_sys(qreal level) +{ + Q_Q(QWidget); + q->windowHandle()->setOpacity(level); +} + +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) +{ + Q_UNUSED(dontShow); + Q_UNUSED(oldRect); + // XXX +} + +QPaintEngine *QWidget::paintEngine() const +{ + qWarning("QWidget::paintEngine: Should no longer be called"); + return 0; //##### @@@ +} + +QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() +{ + //This function should not be called. + Q_ASSERT(false); + return 0; +} + +void QWidgetPrivate::setModal_sys() +{ +} + +#ifndef QT_NO_CURSOR +void qt_qpa_set_cursor(QWidget * w, bool force) +{ + static QCursor arrowCursor(Qt::ArrowCursor); + static QPointer lastUnderMouse = 0; + + QCursor * override = QApplication::overrideCursor(); + + if (override && w != 0) + return; + + QWidget *cursorWidget; + QCursor cursorCursor; + + do { + if (w == 0) { + if (override) { + cursorCursor = *override; + cursorWidget = QApplication::topLevelAt(QCursor::pos()); + break; + } + w = QApplication::widgetAt(QCursor::pos()); + if (w == 0) // clear the override cursor while over empty space + w = QApplication::desktop(); + } else if (force) { + lastUnderMouse = w; + } else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse + && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) { + w = lastUnderMouse; + } + if (w == QApplication::desktop() && !override) { + cursorCursor = arrowCursor; + cursorWidget = w; + break; + } + + QWidget * curWin = QApplication::activeWindow(); + if (!curWin && w && w->internalWinId()) + return; + QWidget* cW = w && !w->internalWinId() ? w : curWin; + + if (!cW || cW->window() != w->window() || + !cW->isVisible() || !cW->underMouse() || override) + return; + + cursorCursor = w->cursor(); + cursorWidget = w; + } while (0); + foreach (QWeakPointer cursor, QPlatformCursorPrivate::getInstances()) + if (cursor) + cursor.data()->changeCursor(&cursorCursor, cursorWidget->windowHandle()); +} +#endif //QT_NO_CURSOR + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwidgetaction.cpp b/src/widgets/kernel/qwidgetaction.cpp new file mode 100644 index 0000000000..29586da34b --- /dev/null +++ b/src/widgets/kernel/qwidgetaction.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidgetaction.h" +#include "qdebug.h" + +#ifndef QT_NO_ACTION +#include "qwidgetaction_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWidgetAction + \since 4.2 + \brief The QWidgetAction class extends QAction by an interface + for inserting custom widgets into action based containers, such + as toolbars. + + \ingroup mainwindow-classes + + Most actions in an application are represented as items in menus or + buttons in toolbars. However sometimes more complex widgets are + necessary. For example a zoom action in a word processor may be + realized using a QComboBox in a QToolBar, presenting a range + of different zoom levels. QToolBar provides QToolBar::insertWidget() + as convenience function for inserting a single widget. + However if you want to implement an action that uses custom + widgets for visualization in multiple containers then you have to + subclass QWidgetAction. + + If a QWidgetAction is added for example to a QToolBar then + QWidgetAction::createWidget() is called. Reimplementations of that + function should create a new custom widget with the specified parent. + + If the action is removed from a container widget then + QWidgetAction::deleteWidget() is called with the previously created custom + widget as argument. The default implementation hides the widget and deletes + it using QObject::deleteLater(). + + If you have only one single custom widget then you can set it as default + widget using setDefaultWidget(). That widget will then be used if the + action is added to a QToolBar, or in general to an action container that + supports QWidgetAction. If a QWidgetAction with only a default widget is + added to two toolbars at the same time then the default widget is shown + only in the first toolbar the action was added to. QWidgetAction takes + over ownership of the default widget. + + Note that it is up to the widget to activate the action, for example by + reimplementing mouse event handlers and calling QAction::trigger(). + + \bold {Mac OS X}: If you add a widget to a menu in the application's menu + bar on Mac OS X, the widget will be added and it will function but with some + limitations: + \list 1 + \o The widget is reparented away from the QMenu to the native menu + view. If you show the menu in some other place (e.g. as a popup menu), + the widget will not be there. + \o Focus/Keyboard handling of the widget is not possible. + \o Due to Apple's design, mouse tracking on the widget currently does + not work. + \o Connecting the triggered() signal to a slot that opens a modal + dialog will cause a crash in Mac OS X 10.4 (known bug acknowledged + by Apple), a workaround is to use a QueuedConnection instead of a + DirectConnection. + \endlist + + \sa QAction, QActionGroup, QWidget +*/ + +/*! + Constructs an action with \a parent. +*/ +QWidgetAction::QWidgetAction(QObject *parent) + : QAction(*(new QWidgetActionPrivate), parent) +{ +} + +/*! + Destroys the object and frees allocated resources. +*/ +QWidgetAction::~QWidgetAction() +{ + Q_D(QWidgetAction); + for (int i = 0; i < d->createdWidgets.count(); ++i) + disconnect(d->createdWidgets.at(i), SIGNAL(destroyed(QObject*)), + this, SLOT(_q_widgetDestroyed(QObject*))); + QList widgetsToDelete = d->createdWidgets; + d->createdWidgets.clear(); + qDeleteAll(widgetsToDelete); + delete d->defaultWidget; +} + +/*! + Sets \a widget to be the default widget. The ownership is + transferred to QWidgetAction. Unless createWidget() is + reimplemented by a subclass to return a new widget the default + widget is used when a container widget requests a widget through + requestWidget(). +*/ +void QWidgetAction::setDefaultWidget(QWidget *widget) +{ + Q_D(QWidgetAction); + if (widget == d->defaultWidget || d->defaultWidgetInUse) + return; + delete d->defaultWidget; + d->defaultWidget = widget; + if (!widget) + return; + + setVisible(!(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide))); + d->defaultWidget->hide(); + d->defaultWidget->setParent(0); + d->defaultWidgetInUse = false; + if (!isEnabled()) + d->defaultWidget->setEnabled(false); +} + +/*! + Returns the default widget. +*/ +QWidget *QWidgetAction::defaultWidget() const +{ + Q_D(const QWidgetAction); + return d->defaultWidget; +} + +/*! + Returns a widget that represents the action, with the given \a + parent. + + Container widgets that support actions can call this function to + request a widget as visual representation of the action. + + \sa releaseWidget(), createWidget(), defaultWidget() +*/ +QWidget *QWidgetAction::requestWidget(QWidget *parent) +{ + Q_D(QWidgetAction); + + QWidget *w = createWidget(parent); + if (!w) { + if (d->defaultWidgetInUse || !d->defaultWidget) + return 0; + d->defaultWidget->setParent(parent); + d->defaultWidgetInUse = true; + return d->defaultWidget; + } + + connect(w, SIGNAL(destroyed(QObject*)), + this, SLOT(_q_widgetDestroyed(QObject*))); + d->createdWidgets.append(w); + return w; +} + +/*! + Releases the specified \a widget. + + Container widgets that support actions call this function when a widget + action is removed. + + \sa requestWidget(), deleteWidget(), defaultWidget() +*/ +void QWidgetAction::releaseWidget(QWidget *widget) +{ + Q_D(QWidgetAction); + + if (widget == d->defaultWidget) { + d->defaultWidget->hide(); + d->defaultWidget->setParent(0); + d->defaultWidgetInUse = false; + return; + } + + if (!d->createdWidgets.contains(widget)) + return; + + disconnect(widget, SIGNAL(destroyed(QObject*)), + this, SLOT(_q_widgetDestroyed(QObject*))); + d->createdWidgets.removeAll(widget); + deleteWidget(widget); +} + +/*! + \reimp +*/ +bool QWidgetAction::event(QEvent *event) +{ + Q_D(QWidgetAction); + if (event->type() == QEvent::ActionChanged) { + if (d->defaultWidget) + d->defaultWidget->setEnabled(isEnabled()); + for (int i = 0; i < d->createdWidgets.count(); ++i) + d->createdWidgets.at(i)->setEnabled(isEnabled()); + } + return QAction::event(event); +} + +/*! + \reimp + */ +bool QWidgetAction::eventFilter(QObject *obj, QEvent *event) +{ + return QAction::eventFilter(obj,event); +} + +/*! + This function is called whenever the action is added to a container widget + that supports custom widgets. If you don't want a custom widget to be + used as representation of the action in the specified \a parent widget then + 0 should be returned. + + \sa deleteWidget() +*/ +QWidget *QWidgetAction::createWidget(QWidget *parent) +{ + Q_UNUSED(parent) + return 0; +} + +/*! + This function is called whenever the action is removed from a + container widget that displays the action using a custom \a + widget previously created using createWidget(). The default + implementation hides the \a widget and schedules it for deletion + using QObject::deleteLater(). + + \sa createWidget() +*/ +void QWidgetAction::deleteWidget(QWidget *widget) +{ + widget->hide(); + widget->deleteLater(); +} + +/*! + Returns the list of widgets that have been using createWidget() and + are currently in use by widgets the action has been added to. +*/ +QList QWidgetAction::createdWidgets() const +{ + Q_D(const QWidgetAction); + return d->createdWidgets; +} + +QT_END_NAMESPACE + +#include "moc_qwidgetaction.cpp" + +#endif // QT_NO_ACTION diff --git a/src/widgets/kernel/qwidgetaction.h b/src/widgets/kernel/qwidgetaction.h new file mode 100644 index 0000000000..a32b5d60dd --- /dev/null +++ b/src/widgets/kernel/qwidgetaction.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGETACTION_H +#define QWIDGETACTION_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_ACTION + +class QWidgetActionPrivate; + +class Q_GUI_EXPORT QWidgetAction : public QAction +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWidgetAction) + +public: + explicit QWidgetAction(QObject *parent); + virtual ~QWidgetAction(); + + void setDefaultWidget(QWidget *w); + QWidget *defaultWidget() const; + + QWidget *requestWidget(QWidget *parent); + void releaseWidget(QWidget *widget); + +protected: + virtual bool event(QEvent *); + virtual bool eventFilter(QObject *, QEvent *); + virtual QWidget *createWidget(QWidget *parent); + virtual void deleteWidget(QWidget *widget); + QList createdWidgets() const; + +private: + Q_DISABLE_COPY(QWidgetAction) + Q_PRIVATE_SLOT(d_func(), void _q_widgetDestroyed(QObject *)) + friend class QToolBar; +}; + +#endif // QT_NO_ACTION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QWIDGETACTION_H diff --git a/src/widgets/kernel/qwidgetaction_p.h b/src/widgets/kernel/qwidgetaction_p.h new file mode 100644 index 0000000000..e4f59a04d2 --- /dev/null +++ b/src/widgets/kernel/qwidgetaction_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGETACTION_P_H +#define QWIDGETACTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qaction_p.h" + +QT_BEGIN_NAMESPACE + +class QWidgetActionPrivate : public QActionPrivate +{ + Q_DECLARE_PUBLIC(QWidgetAction) +public: + inline QWidgetActionPrivate() : defaultWidgetInUse(false), autoCreated(false) {} + QPointer defaultWidget; + QList createdWidgets; + uint defaultWidgetInUse : 1; + uint autoCreated : 1; // created by QToolBar::addWidget and the like + + inline void _q_widgetDestroyed(QObject *o) { + createdWidgets.removeAll(static_cast(o)); + } +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/widgets/kernel/qwidgetwindow_qpa.cpp b/src/widgets/kernel/qwidgetwindow_qpa.cpp new file mode 100644 index 0000000000..d1ef77d48c --- /dev/null +++ b/src/widgets/kernel/qwidgetwindow_qpa.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidgetwindow_qpa_p.h" + +#include "private/qwidget_p.h" +#include "private/qapplication_p.h" + +QT_BEGIN_NAMESPACE + +QWidget *qt_button_down = 0; // widget got last button-down + +QWidgetWindow::QWidgetWindow(QWidget *widget) + : m_widget(widget) +{ +} + +bool QWidgetWindow::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::Close: + handleCloseEvent(static_cast(event)); + return true; + + case QEvent::Enter: + case QEvent::Leave: + handleEnterLeaveEvent(event); + return true; + + case QEvent::KeyPress: + case QEvent::KeyRelease: + handleKeyEvent(static_cast(event)); + return true; + + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + handleMouseEvent(static_cast(event)); + return true; + + case QEvent::Move: + handleMoveEvent(static_cast(event)); + return true; + + case QEvent::Resize: + handleResizeEvent(static_cast(event)); + return true; + + case QEvent::Wheel: + handleWheelEvent(static_cast(event)); + return true; + + default: + break; + } + + return m_widget->event(event) || QWindow::event(event); +} + +QPointer qt_last_mouse_receiver = 0; + +void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) +{ + if (event->type() == QEvent::Leave) { + QApplicationPrivate::dispatchEnterLeave(0, m_widget); + qt_last_mouse_receiver = 0; + } else { + QApplicationPrivate::dispatchEnterLeave(m_widget, 0); + qt_last_mouse_receiver = m_widget; + } +} + +void QWidgetWindow::handleMouseEvent(QMouseEvent *event) +{ + // which child should have it? + QWidget *widget = m_implicit_mouse_grabber ? m_implicit_mouse_grabber.data() : m_widget->childAt(event->pos()); + + if (qApp->d_func()->inPopupMode()) { + widget = qApp->activePopupWidget(); + m_implicit_mouse_grabber.clear(); + } + + if (!widget) + widget = m_widget; + + if (event->type() == QEvent::MouseButtonPress && !m_implicit_mouse_grabber) + m_implicit_mouse_grabber = widget; + + if (event->buttons() == Qt::NoButton) + m_implicit_mouse_grabber.clear(); + + QPoint mapped = widget->mapFrom(m_widget, event->pos()); + + if (widget != qt_last_mouse_receiver) { + QApplicationPrivate::dispatchEnterLeave(widget, qt_last_mouse_receiver); + qt_last_mouse_receiver = widget; + } + + QMouseEvent translated(event->type(), mapped, event->globalPos(), event->button(), event->buttons(), event->modifiers()); + QGuiApplication::sendSpontaneousEvent(widget, &translated); + + if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::RightButton) { + QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPos(), event->modifiers()); + QGuiApplication::sendSpontaneousEvent(widget, &e); + } +} + +void QWidgetWindow::handleKeyEvent(QKeyEvent *event) +{ + QWidget *widget = m_widget->focusWidget(); + + if (!widget) + widget = m_widget; + + QGuiApplication::sendSpontaneousEvent(widget, event); +} + +void QWidgetWindow::handleMoveEvent(QMoveEvent *event) +{ + m_widget->data->crect = geometry(); + QGuiApplication::sendSpontaneousEvent(m_widget, event); +} + +void QWidgetWindow::handleResizeEvent(QResizeEvent *event) +{ + m_widget->data->crect = geometry(); + QGuiApplication::sendSpontaneousEvent(m_widget, event); +} + +void QWidgetWindow::handleCloseEvent(QCloseEvent *) +{ + m_widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); +} + +void QWidgetWindow::handleWheelEvent(QWheelEvent *event) +{ + // which child should have it? + QWidget *widget = m_widget->childAt(event->pos()); + + if (!widget) + widget = m_widget; + + QPoint mapped = widget->mapFrom(m_widget, event->pos()); + + QWheelEvent translated(mapped, event->globalPos(), event->delta(), event->buttons(), event->modifiers(), event->orientation()); + QGuiApplication::sendSpontaneousEvent(widget, &translated); +} + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h new file mode 100644 index 0000000000..9eb1e4f60e --- /dev/null +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGETWINDOW_QPA_P_H +#define QWIDGETWINDOW_QPA_P_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QWidgetWindow : public QWindow +{ + Q_OBJECT +public: + QWidgetWindow(QWidget *widget); + + QWidget *widget() const { return m_widget; } + +protected: + bool event(QEvent *); + + void handleCloseEvent(QCloseEvent *); + void handleEnterLeaveEvent(QEvent *); + void handleKeyEvent(QKeyEvent *); + void handleMouseEvent(QMouseEvent *); + void handleMoveEvent(QMoveEvent *); + void handleResizeEvent(QResizeEvent *); + void handleWheelEvent(QWheelEvent *); + +private: + QWidget *m_widget; + QWeakPointer m_implicit_mouse_grabber; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QWIDGETWINDOW_QPA_P_H diff --git a/src/widgets/kernel/symbian.pri b/src/widgets/kernel/symbian.pri new file mode 100644 index 0000000000..69422dd02e --- /dev/null +++ b/src/widgets/kernel/symbian.pri @@ -0,0 +1,7 @@ +symbian { + contains(QT_CONFIG, s60): LIBS+= $$QMAKE_LIBS_S60 + RESOURCES += symbian/symbianresources.qrc + + HEADERS += symbian/qsymbianevent.h + SOURCES += symbian/qsymbianevent.cpp +} diff --git a/src/widgets/kernel/win.pri b/src/widgets/kernel/win.pri new file mode 100644 index 0000000000..5ecf4dd94a --- /dev/null +++ b/src/widgets/kernel/win.pri @@ -0,0 +1,4 @@ +# Qt/Windows only configuration file +# -------------------------------------------------------------------- + + INCLUDEPATH += ../3rdparty/wintab diff --git a/src/widgets/kernel/x11.pri b/src/widgets/kernel/x11.pri new file mode 100644 index 0000000000..82de1b68af --- /dev/null +++ b/src/widgets/kernel/x11.pri @@ -0,0 +1,4 @@ +x11 { + contains(QT_CONFIG, nas): LIBS_PRIVATE += -laudio -lXt +} + -- cgit v1.2.3