summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@nokia.com>2011-09-13 08:54:45 +0200
committerGunnar Sletta <gunnar.sletta@nokia.com>2011-09-13 08:54:45 +0200
commitb62bd0584a7872b6917917009b707785b3abd077 (patch)
tree9981f274712c098cabbff0c4667672a3934e5393 /src/widgets/widgets
parent5e10745dca1d10025404a9f268f03ae697fb10cc (diff)
parent97baad65f65783d2b5ff938f6217aec9434f2e5f (diff)
Merge branch 'refactor'
Conflicts: mkspecs/qws/linux-lsb-g++/qmake.conf src/gui/image/qpixmap_mac.cpp src/gui/painting/qpaintengine_x11.cpp src/gui/painting/qtessellator.cpp src/gui/text/qfontengine_qws.cpp src/gui/text/qfontengine_x11.cpp src/gui/widgets/qlinecontrol.cpp src/opengl/qgl.h src/opengl/qgl_x11egl.cpp src/plugins/plugins.pro Change-Id: If52dcd55cd55f2983a756c2f843967702b60a310
Diffstat (limited to 'src/widgets/widgets')
-rw-r--r--src/widgets/widgets/qabstractbutton.cpp1470
-rw-r--r--src/widgets/widgets/qabstractbutton.h180
-rw-r--r--src/widgets/widgets/qabstractbutton_p.h110
-rw-r--r--src/widgets/widgets/qabstractscrollarea.cpp1506
-rw-r--r--src/widgets/widgets/qabstractscrollarea.h144
-rw-r--r--src/widgets/widgets/qabstractscrollarea_p.h146
-rw-r--r--src/widgets/widgets/qabstractslider.cpp1001
-rw-r--r--src/widgets/widgets/qabstractslider.h184
-rw-r--r--src/widgets/widgets/qabstractslider_p.h147
-rw-r--r--src/widgets/widgets/qabstractspinbox.cpp2122
-rw-r--r--src/widgets/widgets/qabstractspinbox.h181
-rw-r--r--src/widgets/widgets/qabstractspinbox_p.h170
-rw-r--r--src/widgets/widgets/qbuttongroup.cpp269
-rw-r--r--src/widgets/widgets/qbuttongroup.h112
-rw-r--r--src/widgets/widgets/qcalendartextnavigator_p.h112
-rw-r--r--src/widgets/widgets/qcalendarwidget.cpp3104
-rw-r--r--src/widgets/widgets/qcalendarwidget.h204
-rw-r--r--src/widgets/widgets/qcheckbox.cpp417
-rw-r--r--src/widgets/widgets/qcheckbox.h114
-rw-r--r--src/widgets/widgets/qcocoatoolbardelegate_mac.mm153
-rw-r--r--src/widgets/widgets/qcocoatoolbardelegate_mac_p.h71
-rw-r--r--src/widgets/widgets/qcombobox.cpp3319
-rw-r--r--src/widgets/widgets/qcombobox.h339
-rw-r--r--src/widgets/widgets/qcombobox_p.h421
-rw-r--r--src/widgets/widgets/qcommandlinkbutton.cpp410
-rw-r--r--src/widgets/widgets/qcommandlinkbutton.h85
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp2655
-rw-r--r--src/widgets/widgets/qdatetimeedit.h230
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h185
-rw-r--r--src/widgets/widgets/qdial.cpp546
-rw-r--r--src/widgets/widgets/qdial.h122
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp1285
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.h168
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp3329
-rw-r--r--src/widgets/widgets/qdockarealayout_p.h308
-rw-r--r--src/widgets/widgets/qdockwidget.cpp1605
-rw-r--r--src/widgets/widgets/qdockwidget.h146
-rw-r--r--src/widgets/widgets/qdockwidget_p.h207
-rw-r--r--src/widgets/widgets/qeffects.cpp613
-rw-r--r--src/widgets/widgets/qeffects_p.h84
-rw-r--r--src/widgets/widgets/qfocusframe.cpp339
-rw-r--r--src/widgets/widgets/qfocusframe.h82
-rw-r--r--src/widgets/widgets/qfontcombobox.cpp474
-rw-r--r--src/widgets/widgets/qfontcombobox.h112
-rw-r--r--src/widgets/widgets/qframe.cpp564
-rw-r--r--src/widgets/widgets/qframe.h148
-rw-r--r--src/widgets/widgets/qframe_p.h84
-rw-r--r--src/widgets/widgets/qgroupbox.cpp781
-rw-r--r--src/widgets/widgets/qgroupbox.h122
-rw-r--r--src/widgets/widgets/qlabel.cpp1734
-rw-r--r--src/widgets/widgets/qlabel.h182
-rw-r--r--src/widgets/widgets/qlabel_p.h153
-rw-r--r--src/widgets/widgets/qlcdnumber.cpp1312
-rw-r--r--src/widgets/widgets/qlcdnumber.h144
-rw-r--r--src/widgets/widgets/qlineedit.cpp2363
-rw-r--r--src/widgets/widgets/qlineedit.h300
-rw-r--r--src/widgets/widgets/qlineedit_p.cpp293
-rw-r--r--src/widgets/widgets/qlineedit_p.h155
-rw-r--r--src/widgets/widgets/qmaccocoaviewcontainer_mac.h73
-rw-r--r--src/widgets/widgets/qmaccocoaviewcontainer_mac.mm187
-rw-r--r--src/widgets/widgets/qmacnativewidget_mac.h74
-rw-r--r--src/widgets/widgets/qmacnativewidget_mac.mm133
-rw-r--r--src/widgets/widgets/qmainwindow.cpp1686
-rw-r--r--src/widgets/widgets/qmainwindow.h219
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp2017
-rw-r--r--src/widgets/widgets/qmainwindowlayout_mac.mm607
-rw-r--r--src/widgets/widgets/qmainwindowlayout_p.h357
-rw-r--r--src/widgets/widgets/qmdiarea.cpp2678
-rw-r--r--src/widgets/widgets/qmdiarea.h179
-rw-r--r--src/widgets/widgets/qmdiarea_p.h285
-rw-r--r--src/widgets/widgets/qmdisubwindow.cpp3547
-rw-r--r--src/widgets/widgets/qmdisubwindow.h159
-rw-r--r--src/widgets/widgets/qmdisubwindow_p.h348
-rw-r--r--src/widgets/widgets/qmenu.cpp3100
-rw-r--r--src/widgets/widgets/qmenu.h210
-rw-r--r--src/widgets/widgets/qmenu_p.h316
-rw-r--r--src/widgets/widgets/qmenu_symbian.cpp464
-rw-r--r--src/widgets/widgets/qmenu_wince.cpp668
-rw-r--r--src/widgets/widgets/qmenu_wince.rc231
-rw-r--r--src/widgets/widgets/qmenu_wince_resource_p.h94
-rw-r--r--src/widgets/widgets/qmenubar.cpp2063
-rw-r--r--src/widgets/widgets/qmenubar.h177
-rw-r--r--src/widgets/widgets/qmenubar_p.h251
-rw-r--r--src/widgets/widgets/qplaintextedit.cpp2996
-rw-r--r--src/widgets/widgets/qplaintextedit.h327
-rw-r--r--src/widgets/widgets/qplaintextedit_p.h187
-rw-r--r--src/widgets/widgets/qprogressbar.cpp595
-rw-r--r--src/widgets/widgets/qprogressbar.h132
-rw-r--r--src/widgets/widgets/qpushbutton.cpp784
-rw-r--r--src/widgets/widgets/qpushbutton.h127
-rw-r--r--src/widgets/widgets/qpushbutton_p.h90
-rw-r--r--src/widgets/widgets/qradiobutton.cpp296
-rw-r--r--src/widgets/widgets/qradiobutton.h89
-rw-r--r--src/widgets/widgets/qrubberband.cpp336
-rw-r--r--src/widgets/widgets/qrubberband.h104
-rw-r--r--src/widgets/widgets/qscrollarea.cpp522
-rw-r--r--src/widgets/widgets/qscrollarea.h101
-rw-r--r--src/widgets/widgets/qscrollarea_p.h81
-rw-r--r--src/widgets/widgets/qscrollbar.cpp764
-rw-r--r--src/widgets/widgets/qscrollbar.h104
-rw-r--r--src/widgets/widgets/qsizegrip.cpp570
-rw-r--r--src/widgets/widgets/qsizegrip.h95
-rw-r--r--src/widgets/widgets/qslider.cpp666
-rw-r--r--src/widgets/widgets/qslider.h134
-rw-r--r--src/widgets/widgets/qspinbox.cpp1327
-rw-r--r--src/widgets/widgets/qspinbox.h188
-rw-r--r--src/widgets/widgets/qsplashscreen.cpp315
-rw-r--r--src/widgets/widgets/qsplashscreen.h99
-rw-r--r--src/widgets/widgets/qsplitter.cpp1862
-rw-r--r--src/widgets/widgets/qsplitter.h192
-rw-r--r--src/widgets/widgets/qsplitter_p.h149
-rw-r--r--src/widgets/widgets/qstackedwidget.cpp338
-rw-r--r--src/widgets/widgets/qstackedwidget.h100
-rw-r--r--src/widgets/widgets/qstatusbar.cpp847
-rw-r--r--src/widgets/widgets/qstatusbar.h116
-rw-r--r--src/widgets/widgets/qtabbar.cpp2376
-rw-r--r--src/widgets/widgets/qtabbar.h226
-rw-r--r--src/widgets/widgets/qtabbar_p.h263
-rw-r--r--src/widgets/widgets/qtabwidget.cpp1516
-rw-r--r--src/widgets/widgets/qtabwidget.h254
-rw-r--r--src/widgets/widgets/qtextbrowser.cpp1275
-rw-r--r--src/widgets/widgets/qtextbrowser.h140
-rw-r--r--src/widgets/widgets/qtextedit.cpp2809
-rw-r--r--src/widgets/widgets/qtextedit.h430
-rw-r--r--src/widgets/widgets/qtextedit_p.h141
-rw-r--r--src/widgets/widgets/qtoolbar.cpp1349
-rw-r--r--src/widgets/widgets/qtoolbar.h188
-rw-r--r--src/widgets/widgets/qtoolbar_p.h135
-rw-r--r--src/widgets/widgets/qtoolbararealayout.cpp1391
-rw-r--r--src/widgets/widgets/qtoolbararealayout_p.h248
-rw-r--r--src/widgets/widgets/qtoolbarextension.cpp92
-rw-r--r--src/widgets/widgets/qtoolbarextension_p.h80
-rw-r--r--src/widgets/widgets/qtoolbarlayout.cpp742
-rw-r--r--src/widgets/widgets/qtoolbarlayout_p.h134
-rw-r--r--src/widgets/widgets/qtoolbarseparator.cpp91
-rw-r--r--src/widgets/widgets/qtoolbarseparator_p.h88
-rw-r--r--src/widgets/widgets/qtoolbox.cpp822
-rw-r--r--src/widgets/widgets/qtoolbox.h148
-rw-r--r--src/widgets/widgets/qtoolbutton.cpp1247
-rw-r--r--src/widgets/widgets/qtoolbutton.h199
-rw-r--r--src/widgets/widgets/qwidgetanimator.cpp117
-rw-r--r--src/widgets/widgets/qwidgetanimator_p.h89
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol.cpp1862
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol_p.h499
-rw-r--r--src/widgets/widgets/qwidgetresizehandler.cpp547
-rw-r--r--src/widgets/widgets/qwidgetresizehandler_p.h141
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp3148
-rw-r--r--src/widgets/widgets/qwidgettextcontrol_p.h305
-rw-r--r--src/widgets/widgets/qwidgettextcontrol_p_p.h238
-rw-r--r--src/widgets/widgets/qworkspace.cpp3376
-rw-r--r--src/widgets/widgets/qworkspace.h137
-rw-r--r--src/widgets/widgets/widgets.pri165
152 files changed, 99080 insertions, 0 deletions
diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp
new file mode 100644
index 0000000000..d777cc7567
--- /dev/null
+++ b/src/widgets/widgets/qabstractbutton.cpp
@@ -0,0 +1,1470 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractbutton.h"
+#include "qabstractitemview.h"
+#include "qbuttongroup.h"
+#include "qabstractbutton_p.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qaction.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define AUTO_REPEAT_DELAY 300
+#define AUTO_REPEAT_INTERVAL 100
+
+Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets;
+
+/*!
+ \class QAbstractButton
+
+ \brief The QAbstractButton class is the abstract base class of
+ button widgets, providing functionality common to buttons.
+
+ \ingroup abstractwidgets
+
+ This class implements an \e abstract button.
+ Subclasses of this class handle user actions, and specify how the button
+ is drawn.
+
+ QAbstractButton provides support for both push buttons and checkable
+ (toggle) buttons. Checkable buttons are implemented in the QRadioButton
+ and QCheckBox classes. Push buttons are implemented in the
+ QPushButton and QToolButton classes; these also provide toggle
+ behavior if required.
+
+ Any button can display a label containing text and an icon. setText()
+ sets the text; setIcon() sets the icon. If a button is disabled, its label
+ is changed to give the button a "disabled" appearance.
+
+ If the button is a text button with a string containing an
+ ampersand ('&'), QAbstractButton automatically creates a shortcut
+ key. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 0
+
+ The \key Alt+C shortcut is assigned to the button, i.e., when the
+ user presses \key Alt+C the button will call animateClick(). See
+ the \l {QShortcut#mnemonic}{QShortcut} documentation for details
+ (to display an actual ampersand, use '&&').
+
+ You can also set a custom shortcut key using the setShortcut()
+ function. This is useful mostly for buttons that do not have any
+ text, because they have no automatic shortcut.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 1
+
+ All of the buttons provided by Qt (QPushButton, QToolButton,
+ QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}.
+
+ A button can be made the default button in a dialog are provided by
+ QPushButton::setDefault() and QPushButton::setAutoDefault().
+
+ QAbstractButton provides most of the states used for buttons:
+
+ \list
+
+ \o isDown() indicates whether the button is \e pressed down.
+
+ \o isChecked() indicates whether the button is \e checked. Only
+ checkable buttons can be checked and unchecked (see below).
+
+ \o isEnabled() indicates whether the button can be pressed by the
+ user.
+
+ \o setAutoRepeat() sets whether the button will auto-repeat if the
+ user holds it down. \l autoRepeatDelay and \l autoRepeatInterval
+ define how auto-repetition is done.
+
+ \o setCheckable() sets whether the button is a toggle button or not.
+
+ \endlist
+
+ The difference between isDown() and isChecked() is as follows.
+ When the user clicks a toggle button to check it, the button is first
+ \e pressed then released into the \e checked state. When the user
+ clicks it again (to uncheck it), the button moves first to the
+ \e pressed state, then to the \e unchecked state (isChecked() and
+ isDown() are both false).
+
+ QAbstractButton provides four signals:
+
+ \list 1
+
+ \o pressed() is emitted when the left mouse button is pressed while
+ the mouse cursor is inside the button.
+
+ \o released() is emitted when the left mouse button is released.
+
+ \o clicked() is emitted when the button is first pressed and then
+ released, when the shortcut key is typed, or when click() or
+ animateClick() is called.
+
+ \o toggled() is emitted when the state of a toggle button changes.
+
+ \endlist
+
+ To subclass QAbstractButton, you must reimplement at least
+ paintEvent() to draw the button's outline and its text or pixmap. It
+ is generally advisable to reimplement sizeHint() as well, and
+ sometimes hitButton() (to determine whether a button press is within
+ the button). For buttons with more than two states (like tri-state
+ buttons), you will also have to reimplement checkStateSet() and
+ nextCheckState().
+
+ \sa QButtonGroup
+*/
+
+QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type)
+ :
+#ifndef QT_NO_SHORTCUT
+ shortcutId(0),
+#endif
+ checkable(false), checked(false), autoRepeat(false), autoExclusive(false),
+ down(false), blockRefresh(false), pressed(false),
+#ifndef QT_NO_BUTTONGROUP
+ group(0),
+#endif
+ autoRepeatDelay(AUTO_REPEAT_DELAY),
+ autoRepeatInterval(AUTO_REPEAT_INTERVAL),
+ controlType(type)
+{}
+
+#ifndef QT_NO_BUTTONGROUP
+
+class QButtonGroupPrivate: public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QButtonGroup)
+
+public:
+ QButtonGroupPrivate():exclusive(true){}
+ QList<QAbstractButton *> buttonList;
+ QPointer<QAbstractButton> checkedButton;
+ void detectCheckedButton();
+ void notifyChecked(QAbstractButton *button);
+ bool exclusive;
+ QMap<QAbstractButton*, int> mapping;
+};
+
+QButtonGroup::QButtonGroup(QObject *parent)
+ : QObject(*new QButtonGroupPrivate, parent)
+{
+}
+
+QButtonGroup::~QButtonGroup()
+{
+ Q_D(QButtonGroup);
+ for (int i = 0; i < d->buttonList.count(); ++i)
+ d->buttonList.at(i)->d_func()->group = 0;
+}
+
+
+bool QButtonGroup::exclusive() const
+{
+ Q_D(const QButtonGroup);
+ return d->exclusive;
+}
+
+void QButtonGroup::setExclusive(bool exclusive)
+{
+ Q_D(QButtonGroup);
+ d->exclusive = exclusive;
+}
+
+
+// TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id)
+void QButtonGroup::addButton(QAbstractButton *button)
+{
+ addButton(button, -1);
+}
+
+void QButtonGroup::addButton(QAbstractButton *button, int id)
+{
+ Q_D(QButtonGroup);
+ if (QButtonGroup *previous = button->d_func()->group)
+ previous->removeButton(button);
+ button->d_func()->group = this;
+ d->buttonList.append(button);
+ if (id == -1) {
+ QList<int> ids = d->mapping.values();
+ if (ids.isEmpty())
+ d->mapping[button] = -2;
+ else {
+ qSort(ids);
+ d->mapping[button] = ids.first()-1;
+ }
+ } else {
+ d->mapping[button] = id;
+ }
+
+ if (d->exclusive && button->isChecked())
+ button->d_func()->notifyChecked();
+}
+
+void QButtonGroup::removeButton(QAbstractButton *button)
+{
+ Q_D(QButtonGroup);
+ if (d->checkedButton == button) {
+ d->detectCheckedButton();
+ }
+ if (button->d_func()->group == this) {
+ button->d_func()->group = 0;
+ d->buttonList.removeAll(button);
+ d->mapping.remove(button);
+ }
+}
+
+QList<QAbstractButton*> QButtonGroup::buttons() const
+{
+ Q_D(const QButtonGroup);
+ return d->buttonList;
+}
+
+QAbstractButton *QButtonGroup::checkedButton() const
+{
+ Q_D(const QButtonGroup);
+ return d->checkedButton;
+}
+
+QAbstractButton *QButtonGroup::button(int id) const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.key(id);
+}
+
+void QButtonGroup::setId(QAbstractButton *button, int id)
+{
+ Q_D(QButtonGroup);
+ if (button && id != -1)
+ d->mapping[button] = id;
+}
+
+int QButtonGroup::id(QAbstractButton *button) const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.value(button, -1);
+}
+
+int QButtonGroup::checkedId() const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.value(d->checkedButton, -1);
+}
+
+// detect a checked button other than the current one
+void QButtonGroupPrivate::detectCheckedButton()
+{
+ QAbstractButton *previous = checkedButton;
+ checkedButton = 0;
+ if (exclusive)
+ return;
+ for (int i = 0; i < buttonList.count(); i++) {
+ if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) {
+ checkedButton = buttonList.at(i);
+ return;
+ }
+ }
+}
+
+#endif // QT_NO_BUTTONGROUP
+
+QList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ if (group)
+ return group->d_func()->buttonList;
+#endif
+
+ QList<QAbstractButton*>candidates = parent->findChildren<QAbstractButton *>();
+ if (autoExclusive) {
+ for (int i = candidates.count() - 1; i >= 0; --i) {
+ QAbstractButton *candidate = candidates.at(i);
+ if (!candidate->autoExclusive()
+#ifndef QT_NO_BUTTONGROUP
+ || candidate->group()
+#endif
+ )
+ candidates.removeAt(i);
+ }
+ }
+ return candidates;
+}
+
+QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ if (group)
+ return group->d_func()->checkedButton;
+#endif
+
+ Q_Q(const QAbstractButton);
+ QList<QAbstractButton *> buttonList = queryButtonList();
+ if (!autoExclusive || buttonList.count() == 1) // no group
+ return 0;
+
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *b = buttonList.at(i);
+ if (b->d_func()->checked && b != q)
+ return b;
+ }
+ return checked ? const_cast<QAbstractButton *>(q) : 0;
+}
+
+void QAbstractButtonPrivate::notifyChecked()
+{
+#ifndef QT_NO_BUTTONGROUP
+ Q_Q(QAbstractButton);
+ if (group) {
+ QAbstractButton *previous = group->d_func()->checkedButton;
+ group->d_func()->checkedButton = q;
+ if (group->d_func()->exclusive && previous && previous != q)
+ previous->nextCheckState();
+ } else
+#endif
+ if (autoExclusive) {
+ if (QAbstractButton *b = queryCheckedButton())
+ b->setChecked(false);
+ }
+}
+
+void QAbstractButtonPrivate::moveFocus(int key)
+{
+ QList<QAbstractButton *> buttonList = queryButtonList();;
+#ifndef QT_NO_BUTTONGROUP
+ bool exclusive = group ? group->d_func()->exclusive : autoExclusive;
+#else
+ bool exclusive = autoExclusive;
+#endif
+ QWidget *f = QApplication::focusWidget();
+ QAbstractButton *fb = qobject_cast<QAbstractButton *>(f);
+ if (!fb || !buttonList.contains(fb))
+ return;
+
+ QAbstractButton *candidate = 0;
+ int bestScore = -1;
+ QRect target = f->rect().translated(f->mapToGlobal(QPoint(0,0)));
+ QPoint goal = target.center();
+ uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
+
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *button = buttonList.at(i);
+ if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() &&
+ (autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
+ QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0)));
+ QPoint p = buttonRect.center();
+
+ //Priority to widgets that overlap on the same coordinate.
+ //In that case, the distance in the direction will be used as significant score,
+ //take also in account orthogonal distance in case two widget are in the same distance.
+ int score;
+ if ((buttonRect.x() < target.right() && target.x() < buttonRect.right())
+ && (key == Qt::Key_Up || key == Qt::Key_Down)) {
+ //one item's is at the vertical of the other
+ score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x());
+ } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom())
+ && (key == Qt::Key_Left || key == Qt::Key_Right) ) {
+ //one item's is at the horizontal of the other
+ score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y());
+ } else {
+ score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x());
+ }
+
+ if (score > bestScore && candidate)
+ continue;
+
+ switch(key) {
+ case Qt::Key_Up:
+ if (p.y() < goal.y()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Down:
+ if (p.y() > goal.y()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Left:
+ if (p.x() < goal.x()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Right:
+ if (p.x() > goal.x()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ }
+ }
+ }
+
+ if (exclusive
+#ifdef QT_KEYPAD_NAVIGATION
+ && !QApplication::keypadNavigationEnabled()
+#endif
+ && candidate
+ && fb->d_func()->checked
+ && candidate->d_func()->checkable)
+ candidate->click();
+
+ if (candidate) {
+ if (key == Qt::Key_Up || key == Qt::Key_Left)
+ candidate->setFocus(Qt::BacktabFocusReason);
+ else
+ candidate->setFocus(Qt::TabFocusReason);
+ }
+}
+
+void QAbstractButtonPrivate::fixFocusPolicy()
+{
+ Q_Q(QAbstractButton);
+#ifndef QT_NO_BUTTONGROUP
+ if (!group && !autoExclusive)
+#else
+ if (!autoExclusive)
+#endif
+ return;
+
+ QList<QAbstractButton *> buttonList = queryButtonList();
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *b = buttonList.at(i);
+ if (!b->isCheckable())
+ continue;
+ b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable())
+ ? (b->focusPolicy() | Qt::TabFocus)
+ : (b->focusPolicy() & ~Qt::TabFocus)));
+ }
+}
+
+void QAbstractButtonPrivate::init()
+{
+ Q_Q(QAbstractButton);
+
+ q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType));
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ q->setForegroundRole(QPalette::ButtonText);
+ q->setBackgroundRole(QPalette::Button);
+}
+
+void QAbstractButtonPrivate::refresh()
+{
+ Q_Q(QAbstractButton);
+
+ if (blockRefresh)
+ return;
+ q->update();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(q, 0, QAccessible::StateChanged);
+#endif
+}
+
+void QAbstractButtonPrivate::click()
+{
+ Q_Q(QAbstractButton);
+
+ down = false;
+ blockRefresh = true;
+ bool changeState = true;
+ if (checked && queryCheckedButton() == q) {
+ // the checked button of an exclusive or autoexclusive group cannot be unchecked
+#ifndef QT_NO_BUTTONGROUP
+ if (group ? group->d_func()->exclusive : autoExclusive)
+#else
+ if (autoExclusive)
+#endif
+ changeState = false;
+ }
+
+ QPointer<QAbstractButton> guard(q);
+ if (changeState) {
+ q->nextCheckState();
+ if (!guard)
+ return;
+ }
+ blockRefresh = false;
+ refresh();
+ q->repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (guard)
+ emitReleased();
+ if (guard)
+ emitClicked();
+}
+
+void QAbstractButtonPrivate::emitClicked()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->clicked(checked);
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonClicked(group->id(q));
+ if (guard && group)
+ emit group->buttonClicked(q);
+ }
+#endif
+}
+
+void QAbstractButtonPrivate::emitPressed()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->pressed();
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonPressed(group->id(q));
+ if (guard && group)
+ emit group->buttonPressed(q);
+ }
+#endif
+}
+
+void QAbstractButtonPrivate::emitReleased()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->released();
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonReleased(group->id(q));
+ if (guard && group)
+ emit group->buttonReleased(q);
+ }
+#endif
+}
+
+/*!
+ Constructs an abstract button with a \a parent.
+*/
+QAbstractButton::QAbstractButton(QWidget *parent)
+ : QWidget(*new QAbstractButtonPrivate, parent, 0)
+{
+ Q_D(QAbstractButton);
+ d->init();
+}
+
+/*!
+ Destroys the button.
+ */
+ QAbstractButton::~QAbstractButton()
+{
+#ifndef QT_NO_BUTTONGROUP
+ Q_D(QAbstractButton);
+ if (d->group)
+ d->group->removeButton(this);
+#endif
+}
+
+
+/*! \internal
+ */
+QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
+ : QWidget(dd, parent, 0)
+{
+ Q_D(QAbstractButton);
+ d->init();
+}
+
+/*!
+\property QAbstractButton::text
+\brief the text shown on the button
+
+If the button has no text, the text() function will return a an empty
+string.
+
+If the text contains an ampersand character ('&'), a shortcut is
+automatically created for it. The character that follows the '&' will
+be used as the shortcut key. Any previous shortcut will be
+overwritten, or cleared if no shortcut is defined by the text. See the
+\l {QShortcut#mnemonic}{QShortcut} documentation for details (to
+display an actual ampersand, use '&&').
+
+There is no default text.
+*/
+
+void QAbstractButton::setText(const QString &text)
+{
+ Q_D(QAbstractButton);
+ if (d->text == text)
+ return;
+ d->text = text;
+#ifndef QT_NO_SHORTCUT
+ QKeySequence newMnemonic = QKeySequence::mnemonic(text);
+ setShortcut(newMnemonic);
+#endif
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+QString QAbstractButton::text() const
+{
+ Q_D(const QAbstractButton);
+ return d->text;
+}
+
+
+/*!
+ \property QAbstractButton::icon
+ \brief the icon shown on the button
+
+ The icon's default size is defined by the GUI style, but can be
+ adjusted by setting the \l iconSize property.
+*/
+void QAbstractButton::setIcon(const QIcon &icon)
+{
+ Q_D(QAbstractButton);
+ d->icon = icon;
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+}
+
+QIcon QAbstractButton::icon() const
+{
+ Q_D(const QAbstractButton);
+ return d->icon;
+}
+
+#ifndef QT_NO_SHORTCUT
+/*!
+\property QAbstractButton::shortcut
+\brief the mnemonic associated with the button
+*/
+
+void QAbstractButton::setShortcut(const QKeySequence &key)
+{
+ Q_D(QAbstractButton);
+ if (d->shortcutId != 0)
+ releaseShortcut(d->shortcutId);
+ d->shortcut = key;
+ d->shortcutId = grabShortcut(key);
+}
+
+QKeySequence QAbstractButton::shortcut() const
+{
+ Q_D(const QAbstractButton);
+ return d->shortcut;
+}
+#endif // QT_NO_SHORTCUT
+
+/*!
+\property QAbstractButton::checkable
+\brief whether the button is checkable
+
+By default, the button is not checkable.
+
+\sa checked
+*/
+void QAbstractButton::setCheckable(bool checkable)
+{
+ Q_D(QAbstractButton);
+ if (d->checkable == checkable)
+ return;
+
+ d->checkable = checkable;
+ d->checked = false;
+}
+
+bool QAbstractButton::isCheckable() const
+{
+ Q_D(const QAbstractButton);
+ return d->checkable;
+}
+
+/*!
+\property QAbstractButton::checked
+\brief whether the button is checked
+
+Only checkable buttons can be checked. By default, the button is unchecked.
+
+\sa checkable
+*/
+void QAbstractButton::setChecked(bool checked)
+{
+ Q_D(QAbstractButton);
+ if (!d->checkable || d->checked == checked) {
+ if (!d->blockRefresh)
+ checkStateSet();
+ return;
+ }
+
+ if (!checked && d->queryCheckedButton() == this) {
+ // the checked button of an exclusive or autoexclusive group cannot be unchecked
+#ifndef QT_NO_BUTTONGROUP
+ if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
+ return;
+ if (d->group)
+ d->group->d_func()->detectCheckedButton();
+#else
+ if (d->autoExclusive)
+ return;
+#endif
+ }
+
+ QPointer<QAbstractButton> guard(this);
+
+ d->checked = checked;
+ if (!d->blockRefresh)
+ checkStateSet();
+ d->refresh();
+
+ if (guard && checked)
+ d->notifyChecked();
+ if (guard)
+ emit toggled(checked);
+}
+
+bool QAbstractButton::isChecked() const
+{
+ Q_D(const QAbstractButton);
+ return d->checked;
+}
+
+/*!
+ \property QAbstractButton::down
+ \brief whether the button is pressed down
+
+ If this property is true, the button is pressed down. The signals
+ pressed() and clicked() are not emitted if you set this property
+ to true. The default is false.
+*/
+
+void QAbstractButton::setDown(bool down)
+{
+ Q_D(QAbstractButton);
+ if (d->down == down)
+ return;
+ d->down = down;
+ d->refresh();
+ if (d->autoRepeat && d->down)
+ d->repeatTimer.start(d->autoRepeatDelay, this);
+ else
+ d->repeatTimer.stop();
+}
+
+bool QAbstractButton::isDown() const
+{
+ Q_D(const QAbstractButton);
+ return d->down;
+}
+
+/*!
+\property QAbstractButton::autoRepeat
+\brief whether autoRepeat is enabled
+
+If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at
+regular intervals when the button is down. autoRepeat is off by default.
+The initial delay and the repetition interval are defined in milliseconds by \l
+autoRepeatDelay and \l autoRepeatInterval.
+
+Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the
+system and not by this class. The pressed(), released(), and clicked() signals will be emitted
+like in the normal case.
+*/
+
+void QAbstractButton::setAutoRepeat(bool autoRepeat)
+{
+ Q_D(QAbstractButton);
+ if (d->autoRepeat == autoRepeat)
+ return;
+ d->autoRepeat = autoRepeat;
+ if (d->autoRepeat && d->down)
+ d->repeatTimer.start(d->autoRepeatDelay, this);
+ else
+ d->repeatTimer.stop();
+}
+
+bool QAbstractButton::autoRepeat() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeat;
+}
+
+/*!
+ \property QAbstractButton::autoRepeatDelay
+ \brief the initial delay of auto-repetition
+ \since 4.2
+
+ If \l autoRepeat is enabled, then autoRepeatDelay defines the initial
+ delay in milliseconds before auto-repetition kicks in.
+
+ \sa autoRepeat, autoRepeatInterval
+*/
+
+void QAbstractButton::setAutoRepeatDelay(int autoRepeatDelay)
+{
+ Q_D(QAbstractButton);
+ d->autoRepeatDelay = autoRepeatDelay;
+}
+
+int QAbstractButton::autoRepeatDelay() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeatDelay;
+}
+
+/*!
+ \property QAbstractButton::autoRepeatInterval
+ \brief the interval of auto-repetition
+ \since 4.2
+
+ If \l autoRepeat is enabled, then autoRepeatInterval defines the
+ length of the auto-repetition interval in millisecons.
+
+ \sa autoRepeat, autoRepeatDelay
+*/
+
+void QAbstractButton::setAutoRepeatInterval(int autoRepeatInterval)
+{
+ Q_D(QAbstractButton);
+ d->autoRepeatInterval = autoRepeatInterval;
+}
+
+int QAbstractButton::autoRepeatInterval() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeatInterval;
+}
+
+
+
+/*!
+\property QAbstractButton::autoExclusive
+\brief whether auto-exclusivity is enabled
+
+If auto-exclusivity is enabled, checkable buttons that belong to the
+same parent widget behave as if they were part of the same
+exclusive button group. In an exclusive button group, only one button
+can be checked at any time; checking another button automatically
+unchecks the previously checked one.
+
+The property has no effect on buttons that belong to a button
+group.
+
+autoExclusive is off by default, except for radio buttons.
+
+\sa QRadioButton
+*/
+void QAbstractButton::setAutoExclusive(bool autoExclusive)
+{
+ Q_D(QAbstractButton);
+ d->autoExclusive = autoExclusive;
+}
+
+bool QAbstractButton::autoExclusive() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoExclusive;
+}
+
+#ifndef QT_NO_BUTTONGROUP
+/*!
+ Returns the group that this button belongs to.
+
+ If the button is not a member of any QButtonGroup, this function
+ returns 0.
+
+ \sa QButtonGroup
+*/
+QButtonGroup *QAbstractButton::group() const
+{
+ Q_D(const QAbstractButton);
+ return d->group;
+}
+#endif // QT_NO_BUTTONGROUP
+
+/*!
+Performs an animated click: the button is pressed immediately, and
+released \a msec milliseconds later (the default is 100 ms).
+
+Calling this function again before the button was released will reset
+the release timer.
+
+All signals associated with a click are emitted as appropriate.
+
+This function does nothing if the button is \link setEnabled()
+disabled. \endlink
+
+\sa click()
+*/
+void QAbstractButton::animateClick(int msec)
+{
+ if (!isEnabled())
+ return;
+ Q_D(QAbstractButton);
+ if (d->checkable && focusPolicy() & Qt::ClickFocus)
+ setFocus();
+ setDown(true);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (!d->animateTimer.isActive())
+ d->emitPressed();
+ d->animateTimer.start(msec, this);
+}
+
+/*!
+Performs a click.
+
+All the usual signals associated with a click are emitted as
+appropriate. If the button is checkable, the state of the button is
+toggled.
+
+This function does nothing if the button is \link setEnabled()
+disabled. \endlink
+
+\sa animateClick()
+ */
+void QAbstractButton::click()
+{
+ if (!isEnabled())
+ return;
+ Q_D(QAbstractButton);
+ QPointer<QAbstractButton> guard(this);
+ d->down = true;
+ d->emitPressed();
+ if (guard) {
+ d->down = false;
+ nextCheckState();
+ if (guard)
+ d->emitReleased();
+ if (guard)
+ d->emitClicked();
+ }
+}
+
+/*! \fn void QAbstractButton::toggle()
+
+ Toggles the state of a checkable button.
+
+ \sa checked
+*/
+void QAbstractButton::toggle()
+{
+ Q_D(QAbstractButton);
+ setChecked(!d->checked);
+}
+
+
+/*! This virtual handler is called when setChecked() was called,
+unless it was called from within nextCheckState(). It allows
+subclasses to reset their intermediate button states.
+
+\sa nextCheckState()
+ */
+void QAbstractButton::checkStateSet()
+{
+}
+
+/*! This virtual handler is called when a button is clicked. The
+default implementation calls setChecked(!isChecked()) if the button
+isCheckable(). It allows subclasses to implement intermediate button
+states.
+
+\sa checkStateSet()
+*/
+void QAbstractButton::nextCheckState()
+{
+ if (isCheckable())
+ setChecked(!isChecked());
+}
+
+/*!
+Returns true if \a pos is inside the clickable button rectangle;
+otherwise returns false.
+
+By default, the clickable area is the entire widget. Subclasses
+may reimplement this function to provide support for clickable
+areas of different shapes and sizes.
+*/
+bool QAbstractButton::hitButton(const QPoint &pos) const
+{
+ return rect().contains(pos);
+}
+
+/*! \reimp */
+bool QAbstractButton::event(QEvent *e)
+{
+ // as opposed to other widgets, disabled buttons accept mouse
+ // events. This avoids surprising click-through scenarios
+ if (!isEnabled()) {
+ switch(e->type()) {
+ case QEvent::TabletPress:
+ case QEvent::TabletRelease:
+ case QEvent::TabletMove:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ case QEvent::HoverMove:
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::ContextMenu:
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel:
+#endif
+ return true;
+ default:
+ break;
+ }
+ }
+
+#ifndef QT_NO_SHORTCUT
+ if (e->type() == QEvent::Shortcut) {
+ Q_D(QAbstractButton);
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ if (d->shortcutId != se->shortcutId())
+ return false;
+ if (!se->isAmbiguous()) {
+ if (!d->animateTimer.isActive())
+ animateClick();
+ } else {
+ if (focusPolicy() != Qt::NoFocus)
+ setFocus(Qt::ShortcutFocusReason);
+ window()->setAttribute(Qt::WA_KeyboardFocusChange);
+ }
+ return true;
+ }
+#endif
+ return QWidget::event(e);
+}
+
+/*! \reimp */
+void QAbstractButton::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->button() != Qt::LeftButton) {
+ e->ignore();
+ return;
+ }
+ if (hitButton(e->pos())) {
+ setDown(true);
+ d->pressed = true;
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitPressed();
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ d->pressed = false;
+
+ if (e->button() != Qt::LeftButton) {
+ e->ignore();
+ return;
+ }
+
+ if (!d->down) {
+ e->ignore();
+ return;
+ }
+
+ if (hitButton(e->pos())) {
+ d->repeatTimer.stop();
+ d->click();
+ e->accept();
+ } else {
+ setDown(false);
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (!(e->buttons() & Qt::LeftButton) || !d->pressed) {
+ e->ignore();
+ return;
+ }
+
+ if (hitButton(e->pos()) != d->down) {
+ setDown(!d->down);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (d->down)
+ d->emitPressed();
+ else
+ d->emitReleased();
+ e->accept();
+ } else if (!hitButton(e->pos())) {
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QAbstractButton);
+ bool next = true;
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ e->ignore();
+ break;
+ case Qt::Key_Select:
+ case Qt::Key_Space:
+ if (!e->isAutoRepeat()) {
+ setDown(true);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitPressed();
+ }
+ break;
+ case Qt::Key_Up:
+ case Qt::Key_Left:
+ next = false;
+ // fall through
+ case Qt::Key_Right:
+ case Qt::Key_Down:
+#ifdef QT_KEYPAD_NAVIGATION
+ if ((QApplication::keypadNavigationEnabled()
+ && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
+ || (!QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
+ || (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down))) {
+ e->ignore();
+ return;
+ }
+#endif
+ QWidget *pw;
+ if (d->autoExclusive
+#ifndef QT_NO_BUTTONGROUP
+ || d->group
+#endif
+#ifndef QT_NO_ITEMVIEWS
+ || ((pw = parentWidget()) && qobject_cast<QAbstractItemView *>(pw->parentWidget()))
+#endif
+ ) {
+ // ### Using qobject_cast to check if the parent is a viewport of
+ // QAbstractItemView is a crude hack, and should be revisited and
+ // cleaned up when fixing task 194373. It's here to ensure that we
+ // keep compatibility outside QAbstractItemView.
+ d->moveFocus(e->key());
+ if (hasFocus()) // nothing happend, propagate
+ e->ignore();
+ } else {
+ focusNextPrevChild(next);
+ }
+ break;
+ case Qt::Key_Escape:
+ if (d->down) {
+ setDown(false);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitReleased();
+ break;
+ }
+ // fall through
+ default:
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::keyReleaseEvent(QKeyEvent *e)
+{
+ Q_D(QAbstractButton);
+
+ if (!e->isAutoRepeat())
+ d->repeatTimer.stop();
+
+ switch (e->key()) {
+ case Qt::Key_Select:
+ case Qt::Key_Space:
+ if (!e->isAutoRepeat() && d->down)
+ d->click();
+ break;
+ default:
+ e->ignore();
+ }
+}
+
+/*!\reimp
+ */
+void QAbstractButton::timerEvent(QTimerEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->timerId() == d->repeatTimer.timerId()) {
+ d->repeatTimer.start(d->autoRepeatInterval, this);
+ if (d->down) {
+ QPointer<QAbstractButton> guard(this);
+ nextCheckState();
+ if (guard)
+ d->emitReleased();
+ if (guard)
+ d->emitClicked();
+ if (guard)
+ d->emitPressed();
+ }
+ } else if (e->timerId() == d->animateTimer.timerId()) {
+ d->animateTimer.stop();
+ d->click();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QAbstractButton);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled())
+#endif
+ d->fixFocusPolicy();
+ QWidget::focusInEvent(e);
+}
+
+/*! \reimp */
+void QAbstractButton::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->reason() != Qt::PopupFocusReason)
+ d->down = false;
+ QWidget::focusOutEvent(e);
+}
+
+/*! \reimp */
+void QAbstractButton::changeEvent(QEvent *e)
+{
+ Q_D(QAbstractButton);
+ switch (e->type()) {
+ case QEvent::EnabledChange:
+ if (!isEnabled())
+ setDown(false);
+ break;
+ default:
+ d->sizeHint = QSize();
+ break;
+ }
+ QWidget::changeEvent(e);
+}
+
+/*!
+ \fn void QAbstractButton::paintEvent(QPaintEvent *e)
+ \reimp
+*/
+
+/*!
+ \fn void QAbstractButton::pressed()
+
+ This signal is emitted when the button is pressed down.
+
+ \sa released(), clicked()
+*/
+
+/*!
+ \fn void QAbstractButton::released()
+
+ This signal is emitted when the button is released.
+
+ \sa pressed(), clicked(), toggled()
+*/
+
+/*!
+\fn void QAbstractButton::clicked(bool checked)
+
+This signal is emitted when the button is activated (i.e. pressed down
+then released while the mouse cursor is inside the button), when the
+shortcut key is typed, or when click() or animateClick() is called.
+Notably, this signal is \e not emitted if you call setDown(),
+setChecked() or toggle().
+
+If the button is checkable, \a checked is true if the button is
+checked, or false if the button is unchecked.
+
+\sa pressed(), released(), toggled()
+*/
+
+/*!
+\fn void QAbstractButton::toggled(bool checked)
+
+This signal is emitted whenever a checkable button changes its state.
+\a checked is true if the button is checked, or false if the button is
+unchecked.
+
+This may be the result of a user action, click() slot activation,
+or because setChecked() was called.
+
+The states of buttons in exclusive button groups are updated before this
+signal is emitted. This means that slots can act on either the "off"
+signal or the "on" signal emitted by the buttons in the group whose
+states have changed.
+
+For example, a slot that reacts to signals emitted by newly checked
+buttons but which ignores signals from buttons that have been unchecked
+can be implemented using the following pattern:
+
+\snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 2
+
+Button groups can be created using the QButtonGroup class, and
+updates to the button states monitored with the
+\l{QButtonGroup::buttonClicked()} signal.
+
+\sa checked, clicked()
+*/
+
+/*!
+ \property QAbstractButton::iconSize
+ \brief the icon size used for this button.
+
+ The default size is defined by the GUI style. This is a maximum
+ size for the icons. Smaller icons will not be scaled up.
+*/
+
+QSize QAbstractButton::iconSize() const
+{
+ Q_D(const QAbstractButton);
+ if (d->iconSize.isValid())
+ return d->iconSize;
+ int e = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this);
+ return QSize(e, e);
+}
+
+void QAbstractButton::setIconSize(const QSize &size)
+{
+ Q_D(QAbstractButton);
+ if (d->iconSize == size)
+ return;
+
+ d->iconSize = size;
+ d->sizeHint = QSize();
+ updateGeometry();
+ if (isVisible()) {
+ update();
+ }
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Use icon() instead.
+*/
+QIcon *QAbstractButton::iconSet() const
+{
+ Q_D(const QAbstractButton);
+ if (!d->icon.isNull())
+ return const_cast<QIcon *>(&d->icon);
+ return 0;
+}
+
+/*!
+ Use QAbstractButton(QWidget *) instead.
+
+ Call setObjectName() if you want to specify an object name, and
+ setParent() if you want to set the window flags.
+*/
+QAbstractButton::QAbstractButton(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QWidget(*new QAbstractButtonPrivate, parent, f)
+{
+ Q_D(QAbstractButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*! \fn bool QAbstractButton::isOn() const
+
+ Use isChecked() instead.
+*/
+
+/*!
+ \fn QPixmap *QAbstractButton::pixmap() const
+
+ This compatibility function always returns 0.
+
+ Use icon() instead.
+*/
+
+/*! \fn void QAbstractButton::setPixmap(const QPixmap &p)
+
+ Use setIcon() instead.
+*/
+
+/*! \fn void QAbstractButton::setIconSet(const QIcon &icon)
+
+ Use setIcon() instead.
+*/
+
+/*! \fn void QAbstractButton::setOn(bool b)
+
+ Use setChecked() instead.
+*/
+
+/*! \fn bool QAbstractButton::isToggleButton() const
+
+ Use isCheckable() instead.
+*/
+
+/*!
+ \fn void QAbstractButton::setToggleButton(bool b)
+
+ Use setCheckable() instead.
+*/
+
+/*! \fn void QAbstractButton::setAccel(const QKeySequence &key)
+
+ Use setShortcut() instead.
+*/
+
+/*! \fn QKeySequence QAbstractButton::accel() const
+
+ Use shortcut() instead.
+*/
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qabstractbutton.h b/src/widgets/widgets/qabstractbutton.h
new file mode 100644
index 0000000000..9edfa1b267
--- /dev/null
+++ b/src/widgets/widgets/qabstractbutton.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTBUTTON_H
+#define QABSTRACTBUTTON_H
+
+#include <QtWidgets/qicon.h>
+#include <QtGui/qkeysequence.h>
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QButtonGroup;
+class QAbstractButtonPrivate;
+
+class Q_WIDGETS_EXPORT QAbstractButton : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString text READ text WRITE setText)
+ Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+#ifndef QT_NO_SHORTCUT
+ Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
+#endif
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled USER true)
+ Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat)
+ Q_PROPERTY(bool autoExclusive READ autoExclusive WRITE setAutoExclusive)
+ Q_PROPERTY(int autoRepeatDelay READ autoRepeatDelay WRITE setAutoRepeatDelay)
+ Q_PROPERTY(int autoRepeatInterval READ autoRepeatInterval WRITE setAutoRepeatInterval)
+ Q_PROPERTY(bool down READ isDown WRITE setDown DESIGNABLE false)
+
+public:
+ explicit QAbstractButton(QWidget* parent=0);
+ ~QAbstractButton();
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setIcon(const QIcon &icon);
+ QIcon icon() const;
+
+ QSize iconSize() const;
+
+#ifndef QT_NO_SHORTCUT
+ void setShortcut(const QKeySequence &key);
+ QKeySequence shortcut() const;
+#endif
+
+ void setCheckable(bool);
+ bool isCheckable() const;
+
+ bool isChecked() const;
+
+ void setDown(bool);
+ bool isDown() const;
+
+ void setAutoRepeat(bool);
+ bool autoRepeat() const;
+
+ void setAutoRepeatDelay(int);
+ int autoRepeatDelay() const;
+
+ void setAutoRepeatInterval(int);
+ int autoRepeatInterval() const;
+
+ void setAutoExclusive(bool);
+ bool autoExclusive() const;
+
+#ifndef QT_NO_BUTTONGROUP
+ QButtonGroup *group() const;
+#endif
+
+public Q_SLOTS:
+ void setIconSize(const QSize &size);
+ void animateClick(int msec = 100);
+ void click();
+ void toggle();
+ void setChecked(bool);
+
+Q_SIGNALS:
+ void pressed();
+ void released();
+ void clicked(bool checked = false);
+ void toggled(bool checked);
+
+protected:
+ virtual void paintEvent(QPaintEvent *e) = 0;
+ virtual bool hitButton(const QPoint &pos) const;
+ virtual void checkStateSet();
+ virtual void nextCheckState();
+
+ bool event(QEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void keyReleaseEvent(QKeyEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+ void changeEvent(QEvent *e);
+ void timerEvent(QTimerEvent *e);
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QAbstractButton(QWidget *parent, const char *name, Qt::WindowFlags f=0);
+ inline QT3_SUPPORT bool isOn() const { return isChecked(); }
+ inline QT3_SUPPORT const QPixmap *pixmap() const { return 0; } // help styles compile
+ inline QT3_SUPPORT void setPixmap( const QPixmap &p ) {
+ setIcon(QIcon(p));
+ setIconSize(p.size());
+ }
+ QT3_SUPPORT QIcon *iconSet() const;
+ inline QT3_SUPPORT void setIconSet(const QIcon &icon) { setIcon(icon); }
+ inline QT3_SUPPORT bool isToggleButton() const { return isCheckable(); }
+ inline QT3_SUPPORT void setToggleButton(bool b) { setCheckable(b); }
+ inline QT3_SUPPORT void setAccel(const QKeySequence &key) { setShortcut(key); }
+ inline QT3_SUPPORT QKeySequence accel() const { return shortcut(); }
+
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void setOn(bool b) { setChecked(b); }
+#endif
+
+protected:
+ QAbstractButton(QAbstractButtonPrivate &dd, QWidget* parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractButton)
+ Q_DISABLE_COPY(QAbstractButton)
+ friend class QButtonGroup;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTBUTTON_H
diff --git a/src/widgets/widgets/qabstractbutton_p.h b/src/widgets/widgets/qabstractbutton_p.h
new file mode 100644
index 0000000000..d2d4c06bff
--- /dev/null
+++ b/src/widgets/widgets/qabstractbutton_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTBUTTON_P_H
+#define QABSTRACTBUTTON_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 "QtCore/qbasictimer.h"
+#include "private/qwidget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractButtonPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractButton)
+public:
+ QAbstractButtonPrivate(QSizePolicy::ControlType type = QSizePolicy::DefaultType);
+
+ QString text;
+ QIcon icon;
+ QSize iconSize;
+#ifndef QT_NO_SHORTCUT
+ QKeySequence shortcut;
+ int shortcutId;
+#endif
+ uint checkable :1;
+ uint checked :1;
+ uint autoRepeat :1;
+ uint autoExclusive :1;
+ uint down :1;
+ uint blockRefresh :1;
+ uint pressed : 1;
+
+#ifndef QT_NO_BUTTONGROUP
+ QButtonGroup* group;
+#endif
+ QBasicTimer repeatTimer;
+ QBasicTimer animateTimer;
+
+ int autoRepeatDelay, autoRepeatInterval;
+
+ QSizePolicy::ControlType controlType;
+ mutable QSize sizeHint;
+
+ void init();
+ void click();
+ void refresh();
+
+ QList<QAbstractButton *>queryButtonList() const;
+ QAbstractButton *queryCheckedButton() const;
+ void notifyChecked();
+ void moveFocus(int key);
+ void fixFocusPolicy();
+
+ void emitPressed();
+ void emitReleased();
+ void emitClicked();
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTBUTTON_P_H
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
new file mode 100644
index 0000000000..6081bc8a55
--- /dev/null
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -0,0 +1,1506 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractscrollarea.h"
+
+#ifndef QT_NO_SCROLLAREA
+
+#include "qscrollbar.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qevent.h"
+#include "qdebug.h"
+#include "qboxlayout.h"
+#include "qpainter.h"
+#include "qmargins.h"
+
+#include <QDebug>
+
+#include "qabstractscrollarea_p.h"
+#include <qwidget.h>
+
+#include <private/qapplication_p.h>
+
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+#ifdef Q_WS_WIN
+# include <qlibrary.h>
+# include <windows.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractScrollArea
+ \brief The QAbstractScrollArea widget provides a scrolling area with
+ on-demand scroll bars.
+
+ \ingroup abstractwidgets
+
+ QAbstractScrollArea is a low-level abstraction of a scrolling
+ area. The area provides a central widget called the viewport, in
+ which the contents of the area is to be scrolled (i.e, the
+ visible parts of the contents are rendered in the viewport).
+
+ Next to the viewport is a vertical scroll bar, and below is a
+ horizontal scroll bar. When all of the area contents fits in the
+ viewport, each scroll bar can be either visible or hidden
+ depending on the scroll bar's Qt::ScrollBarPolicy. When a scroll
+ bar is hidden, the viewport expands in order to cover all
+ available space. When a scroll bar becomes visible again, the
+ viewport shrinks in order to make room for the scroll bar.
+
+ It is possible to reserve a margin area around the viewport, see
+ setViewportMargins(). The feature is mostly used to place a
+ QHeaderView widget above or beside the scrolling area. Subclasses
+ of QAbstractScrollArea should implement margins.
+
+ When inheriting QAbstractScrollArea, you need to do the
+ following:
+
+ \list
+ \o Control the scroll bars by setting their
+ range, value, page step, and tracking their
+ movements.
+ \o Draw the contents of the area in the viewport according
+ to the values of the scroll bars.
+ \o Handle events received by the viewport in
+ viewportEvent() - notably resize events.
+ \o Use \c{viewport->update()} to update the contents of the
+ viewport instead of \l{QWidget::update()}{update()}
+ as all painting operations take place on the viewport.
+ \endlist
+
+ With a scroll bar policy of Qt::ScrollBarAsNeeded (the default),
+ QAbstractScrollArea shows scroll bars when they provide a non-zero
+ scrolling range, and hides them otherwise.
+
+ The scroll bars and viewport should be updated whenever the viewport
+ receives a resize event or the size of the contents changes.
+ The viewport also needs to be updated when the scroll bars
+ values change. The initial values of the scroll bars are often
+ set when the area receives new contents.
+
+ We give a simple example, in which we have implemented a scroll area
+ that can scroll any QWidget. We make the widget a child of the
+ viewport; this way, we do not have to calculate which part of
+ the widget to draw but can simply move the widget with
+ QWidget::move(). When the area contents or the viewport size
+ changes, we do the following:
+
+ \snippet doc/src/snippets/myscrollarea.cpp 1
+
+ When the scroll bars change value, we need to update the widget
+ position, i.e., find the part of the widget that is to be drawn in
+ the viewport:
+
+ \snippet doc/src/snippets/myscrollarea.cpp 0
+
+ In order to track scroll bar movements, reimplement the virtual
+ function scrollContentsBy(). In order to fine-tune scrolling
+ behavior, connect to a scroll bar's
+ QAbstractSlider::actionTriggered() signal and adjust the \l
+ QAbstractSlider::sliderPosition as you wish.
+
+ For convenience, QAbstractScrollArea makes all viewport events
+ available in the virtual viewportEvent() handler. QWidget's
+ specialized handlers are remapped to viewport events in the cases
+ where this makes sense. The remapped specialized handlers are:
+ paintEvent(), mousePressEvent(), mouseReleaseEvent(),
+ mouseDoubleClickEvent(), mouseMoveEvent(), wheelEvent(),
+ dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(), dropEvent(),
+ contextMenuEvent(), and resizeEvent().
+
+ QScrollArea, which inherits QAbstractScrollArea, provides smooth
+ scrolling for any QWidget (i.e., the widget is scrolled pixel by
+ pixel). You only need to subclass QAbstractScrollArea if you need
+ more specialized behavior. This is, for instance, true if the
+ entire contents of the area is not suitable for being drawn on a
+ QWidget or if you do not want smooth scrolling.
+
+ \sa QScrollArea
+*/
+
+QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate()
+ :hbar(0), vbar(0), vbarpolicy(Qt::ScrollBarAsNeeded), hbarpolicy(Qt::ScrollBarAsNeeded),
+ viewport(0), cornerWidget(0), left(0), top(0), right(0), bottom(0),
+ xoffset(0), yoffset(0), viewportFilter(0)
+#ifdef Q_WS_WIN
+ , singleFingerPanEnabled(false)
+#endif
+{
+}
+
+QAbstractScrollAreaScrollBarContainer::QAbstractScrollAreaScrollBarContainer(Qt::Orientation orientation, QWidget *parent)
+ :QWidget(parent), scrollBar(new QScrollBar(orientation, this)),
+ layout(new QBoxLayout(orientation == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom)),
+ orientation(orientation)
+{
+ setLayout(layout);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(scrollBar);
+}
+
+/*! \internal
+ Adds a widget to the scroll bar container.
+*/
+void QAbstractScrollAreaScrollBarContainer::addWidget(QWidget *widget, LogicalPosition position)
+{
+ QSizePolicy policy = widget->sizePolicy();
+ if (orientation == Qt::Vertical)
+ policy.setHorizontalPolicy(QSizePolicy::Ignored);
+ else
+ policy.setVerticalPolicy(QSizePolicy::Ignored);
+ widget->setSizePolicy(policy);
+ widget->setParent(this);
+
+ const int insertIndex = (position & LogicalLeft) ? 0 : scrollBarLayoutIndex() + 1;
+ layout->insertWidget(insertIndex, widget);
+}
+
+/*! \internal
+ Retuns a list of scroll bar widgets for the given position. The scroll bar
+ itself is not returned.
+*/
+QWidgetList QAbstractScrollAreaScrollBarContainer::widgets(LogicalPosition position)
+{
+ QWidgetList list;
+ const int scrollBarIndex = scrollBarLayoutIndex();
+ if (position == LogicalLeft) {
+ for (int i = 0; i < scrollBarIndex; ++i)
+ list.append(layout->itemAt(i)->widget());
+ } else if (position == LogicalRight) {
+ const int layoutItemCount = layout->count();
+ for (int i = scrollBarIndex + 1; i < layoutItemCount; ++i)
+ list.append(layout->itemAt(i)->widget());
+ }
+ return list;
+}
+
+/*! \internal
+ Returns the layout index for the scroll bar. This needs to be
+ recalculated by a linear search for each use, since items in
+ the layout can be removed at any time (i.e. when a widget is
+ deleted or re-parented).
+*/
+int QAbstractScrollAreaScrollBarContainer::scrollBarLayoutIndex() const
+{
+ const int layoutItemCount = layout->count();
+ for (int i = 0; i < layoutItemCount; ++i) {
+ if (qobject_cast<QScrollBar *>(layout->itemAt(i)->widget()))
+ return i;
+ }
+ return -1;
+}
+
+/*! \internal
+*/
+void QAbstractScrollAreaPrivate::replaceScrollBar(QScrollBar *scrollBar,
+ Qt::Orientation orientation)
+{
+ Q_Q(QAbstractScrollArea);
+
+ QAbstractScrollAreaScrollBarContainer *container = scrollBarContainers[orientation];
+ bool horizontal = (orientation == Qt::Horizontal);
+ QScrollBar *oldBar = horizontal ? hbar : vbar;
+ if (horizontal)
+ hbar = scrollBar;
+ else
+ vbar = scrollBar;
+ scrollBar->setParent(container);
+ container->scrollBar = scrollBar;
+ container->layout->removeWidget(oldBar);
+ container->layout->insertWidget(0, scrollBar);
+ scrollBar->setVisible(oldBar->isVisibleTo(container));
+ scrollBar->setInvertedAppearance(oldBar->invertedAppearance());
+ scrollBar->setInvertedControls(oldBar->invertedControls());
+ scrollBar->setRange(oldBar->minimum(), oldBar->maximum());
+ scrollBar->setOrientation(oldBar->orientation());
+ scrollBar->setPageStep(oldBar->pageStep());
+ scrollBar->setSingleStep(oldBar->singleStep());
+ scrollBar->setSliderDown(oldBar->isSliderDown());
+ scrollBar->setSliderPosition(oldBar->sliderPosition());
+ scrollBar->setTracking(oldBar->hasTracking());
+ scrollBar->setValue(oldBar->value());
+ delete oldBar;
+
+ QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
+ q, horizontal ? SLOT(_q_hslide(int)) : SLOT(_q_vslide(int)));
+ QObject::connect(scrollBar, SIGNAL(rangeChanged(int,int)),
+ q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
+}
+
+void QAbstractScrollAreaPrivate::init()
+{
+ Q_Q(QAbstractScrollArea);
+ viewport = new QWidget(q);
+ viewport->setObjectName(QLatin1String("qt_scrollarea_viewport"));
+ viewport->setBackgroundRole(QPalette::Base);
+ viewport->setAutoFillBackground(true);
+ scrollBarContainers[Qt::Horizontal] = new QAbstractScrollAreaScrollBarContainer(Qt::Horizontal, q);
+ scrollBarContainers[Qt::Horizontal]->setObjectName(QLatin1String("qt_scrollarea_hcontainer"));
+ hbar = scrollBarContainers[Qt::Horizontal]->scrollBar;
+ hbar->setRange(0,0);
+ scrollBarContainers[Qt::Horizontal]->setVisible(false);
+ QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(_q_hslide(int)));
+ QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
+ scrollBarContainers[Qt::Vertical] = new QAbstractScrollAreaScrollBarContainer(Qt::Vertical, q);
+ scrollBarContainers[Qt::Vertical]->setObjectName(QLatin1String("qt_scrollarea_vcontainer"));
+ vbar = scrollBarContainers[Qt::Vertical]->scrollBar;
+ vbar->setRange(0,0);
+ scrollBarContainers[Qt::Vertical]->setVisible(false);
+ QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int)));
+ QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
+ viewportFilter.reset(new QAbstractScrollAreaFilter(this));
+ viewport->installEventFilter(viewportFilter.data());
+ viewport->setFocusProxy(q);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ layoutChildren();
+#ifndef Q_WS_MAC
+# ifndef QT_NO_GESTURES
+ viewport->grabGesture(Qt::PanGesture);
+# endif
+#endif
+#ifdef Q_WS_MAEMO_5
+# ifndef QT_NO_GESTURES
+ // viewport->grabGesture(Qt::TouchFlickGesture);
+# endif
+#endif
+}
+
+#ifdef Q_WS_WIN
+void QAbstractScrollAreaPrivate::setSingleFingerPanEnabled(bool on)
+{
+ singleFingerPanEnabled = on;
+ QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
+ if (dd)
+ dd->winSetupGestures();
+}
+#endif // Q_WS_WIN
+
+void QAbstractScrollAreaPrivate::layoutChildren()
+{
+ Q_Q(QAbstractScrollArea);
+ bool needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
+ || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
+
+ bool needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
+ || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
+
+#ifdef Q_WS_MAC
+ QWidget * const window = q->window();
+
+ // Use small scroll bars for tool windows, to match the native size grip.
+ bool hbarIsSmall = hbar->testAttribute(Qt::WA_MacSmallSize);
+ bool vbarIsSmall = vbar->testAttribute(Qt::WA_MacSmallSize);
+ const Qt::WindowType windowType = window->windowType();
+ if (windowType == Qt::Tool) {
+ if (!hbarIsSmall) {
+ hbar->setAttribute(Qt::WA_MacMiniSize, false);
+ hbar->setAttribute(Qt::WA_MacNormalSize, false);
+ hbar->setAttribute(Qt::WA_MacSmallSize, true);
+ }
+ if (!vbarIsSmall) {
+ vbar->setAttribute(Qt::WA_MacMiniSize, false);
+ vbar->setAttribute(Qt::WA_MacNormalSize, false);
+ vbar->setAttribute(Qt::WA_MacSmallSize, true);
+ }
+ } else {
+ if (hbarIsSmall) {
+ hbar->setAttribute(Qt::WA_MacMiniSize, false);
+ hbar->setAttribute(Qt::WA_MacNormalSize, false);
+ hbar->setAttribute(Qt::WA_MacSmallSize, false);
+ }
+ if (vbarIsSmall) {
+ vbar->setAttribute(Qt::WA_MacMiniSize, false);
+ vbar->setAttribute(Qt::WA_MacNormalSize, false);
+ vbar->setAttribute(Qt::WA_MacSmallSize, false);
+ }
+ }
+#endif
+
+ const int hsbExt = hbar->sizeHint().height();
+ const int vsbExt = vbar->sizeHint().width();
+ const QPoint extPoint(vsbExt, hsbExt);
+ const QSize extSize(vsbExt, hsbExt);
+
+ const QRect widgetRect = q->rect();
+ QStyleOption opt(0);
+ opt.init(q);
+
+ const bool hasCornerWidget = (cornerWidget != 0);
+
+// If the scroll bars are at the very right and bottom of the window we
+// move their positions to be aligned with the size grip.
+#ifdef Q_WS_MAC
+ // Check if a native sizegrip is present.
+ bool hasMacReverseSizeGrip = false;
+ bool hasMacSizeGrip = false;
+ bool nativeGripPresent = false;
+ if (q->testAttribute(Qt::WA_WState_Created))
+ nativeGripPresent = qt_mac_checkForNativeSizeGrip(q);
+
+ if (nativeGripPresent) {
+ // Look for a native size grip at the visual window bottom right and at the
+ // absolute window bottom right. In reverse mode, the native size grip does not
+ // swich side, so we need to check if it is on the "wrong side".
+ const QPoint scrollAreaBottomRight = q->mapTo(window, widgetRect.bottomRight() - QPoint(frameWidth, frameWidth));
+ const QPoint windowBottomRight = window->rect().bottomRight();
+ const QPoint visualWindowBottomRight = QStyle::visualPos(opt.direction, opt.rect, windowBottomRight);
+ const QPoint offset = windowBottomRight - scrollAreaBottomRight;
+ const QPoint visualOffset = visualWindowBottomRight - scrollAreaBottomRight;
+ hasMacSizeGrip = (visualOffset.manhattanLength() < vsbExt);
+ hasMacReverseSizeGrip = (hasMacSizeGrip == false && (offset.manhattanLength() < hsbExt));
+ }
+#endif
+
+ QPoint cornerOffset(needv ? vsbExt : 0, needh ? hsbExt : 0);
+ QRect controlsRect;
+ QRect viewportRect;
+
+ // In FrameOnlyAroundContents mode the frame is drawn between the controls and
+ // the viewport, else the frame rect is equal to the widget rect.
+ if ((frameStyle != QFrame::NoFrame) &&
+ q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, q)) {
+ controlsRect = widgetRect;
+ const int extra = q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, q);
+ const QPoint cornerExtra(needv ? extra : 0, needh ? extra : 0);
+ QRect frameRect = widgetRect;
+ frameRect.adjust(0, 0, -cornerOffset.x() - cornerExtra.x(), -cornerOffset.y() - cornerExtra.y());
+ q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, frameRect));
+ // The frame rect needs to be in logical coords, however we need to flip
+ // the contentsRect back before passing it on to the viewportRect
+ // since the viewportRect has its logical coords calculated later.
+ viewportRect = QStyle::visualRect(opt.direction, opt.rect, q->contentsRect());
+ } else {
+ q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, widgetRect));
+ controlsRect = q->contentsRect();
+ viewportRect = QRect(controlsRect.topLeft(), controlsRect.bottomRight() - cornerOffset);
+ }
+
+ // If we have a corner widget and are only showing one scroll bar, we need to move it
+ // to make room for the corner widget.
+ if (hasCornerWidget && (needv || needh))
+ cornerOffset = extPoint;
+
+#ifdef Q_WS_MAC
+ // Also move the scroll bars if they are covered by the native Mac size grip.
+ if (hasMacSizeGrip)
+ cornerOffset = extPoint;
+#endif
+
+ // The corner point is where the scroll bar rects, the corner widget rect and the
+ // viewport rect meets.
+ const QPoint cornerPoint(controlsRect.bottomRight() + QPoint(1, 1) - cornerOffset);
+
+ // Some styles paints the corner if both scorllbars are showing and there is
+ // no corner widget. Also, on the Mac we paint if there is a native
+ // (transparent) sizegrip in the area where a corner widget would be.
+ if ((needv && needh && hasCornerWidget == false)
+ || ((needv || needh)
+#ifdef Q_WS_MAC
+ && hasMacSizeGrip
+#endif
+ )
+ ) {
+ cornerPaintingRect = QStyle::visualRect(opt.direction, opt.rect, QRect(cornerPoint, extSize));
+ } else {
+ cornerPaintingRect = QRect();
+ }
+
+#ifdef Q_WS_MAC
+ if (hasMacReverseSizeGrip)
+ reverseCornerPaintingRect = QRect(controlsRect.bottomRight() + QPoint(1, 1) - extPoint, extSize);
+ else
+ reverseCornerPaintingRect = QRect();
+#endif
+
+ if (needh) {
+ QRect horizontalScrollBarRect(QPoint(controlsRect.left(), cornerPoint.y()), QPoint(cornerPoint.x() - 1, controlsRect.bottom()));
+#ifdef Q_WS_MAC
+ if (hasMacReverseSizeGrip)
+ horizontalScrollBarRect.adjust(vsbExt, 0, 0, 0);
+#endif
+ scrollBarContainers[Qt::Horizontal]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, horizontalScrollBarRect));
+ scrollBarContainers[Qt::Horizontal]->raise();
+ }
+
+ if (needv) {
+ const QRect verticalScrollBarRect (QPoint(cornerPoint.x(), controlsRect.top()), QPoint(controlsRect.right(), cornerPoint.y() - 1));
+ scrollBarContainers[Qt::Vertical]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, verticalScrollBarRect));
+ scrollBarContainers[Qt::Vertical]->raise();
+ }
+
+ if (cornerWidget) {
+ const QRect cornerWidgetRect(cornerPoint, controlsRect.bottomRight());
+ cornerWidget->setGeometry(QStyle::visualRect(opt.direction, opt.rect, cornerWidgetRect));
+ }
+
+ scrollBarContainers[Qt::Horizontal]->setVisible(needh);
+ scrollBarContainers[Qt::Vertical]->setVisible(needv);
+
+ if (q->isRightToLeft())
+ viewportRect.adjust(right, top, -left, -bottom);
+ else
+ viewportRect.adjust(left, top, -right, -bottom);
+
+ viewport->setGeometry(QStyle::visualRect(opt.direction, opt.rect, viewportRect)); // resize the viewport last
+}
+
+/*!
+ \internal
+
+ Creates a new QAbstractScrollAreaPrivate, \a dd with the given \a parent.
+*/
+QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent)
+ :QFrame(dd, parent)
+{
+ Q_D(QAbstractScrollArea);
+ QT_TRY {
+ d->init();
+ } QT_CATCH(...) {
+ d->viewportFilter.reset();
+ QT_RETHROW;
+ }
+}
+
+/*!
+ Constructs a viewport.
+
+ The \a parent argument is sent to the QWidget constructor.
+*/
+QAbstractScrollArea::QAbstractScrollArea(QWidget *parent)
+ :QFrame(*new QAbstractScrollAreaPrivate, parent)
+{
+ Q_D(QAbstractScrollArea);
+ QT_TRY {
+ d->init();
+ } QT_CATCH(...) {
+ d->viewportFilter.reset();
+ QT_RETHROW;
+ }
+}
+
+
+/*!
+ Destroys the viewport.
+ */
+QAbstractScrollArea::~QAbstractScrollArea()
+{
+ Q_D(QAbstractScrollArea);
+ // reset it here, otherwise we'll have a dangling pointer in ~QWidget
+ d->viewportFilter.reset();
+}
+
+
+/*!
+ \since 4.2
+ Sets the viewport to be the given \a widget.
+ The QAbstractScrollArea will take ownership of the given \a widget.
+
+ If \a widget is 0, QAbstractScrollArea will assign a new QWidget instance
+ for the viewport.
+
+ \sa viewport()
+*/
+void QAbstractScrollArea::setViewport(QWidget *widget)
+{
+ Q_D(QAbstractScrollArea);
+ if (widget != d->viewport) {
+ QWidget *oldViewport = d->viewport;
+ if (!widget)
+ widget = new QWidget;
+ d->viewport = widget;
+ d->viewport->setParent(this);
+ d->viewport->setFocusProxy(this);
+ d->viewport->installEventFilter(d->viewportFilter.data());
+#ifndef Q_WS_MAC
+#ifndef QT_NO_GESTURES
+ d->viewport->grabGesture(Qt::PanGesture);
+#endif
+#endif
+#ifdef Q_WS_MAEMO_5
+#ifndef QT_NO_GESTURES
+// d->viewport->grabGesture(Qt::TouchFlickGesture);
+#endif
+#endif
+ d->layoutChildren();
+ if (isVisible())
+ d->viewport->show();
+ QMetaObject::invokeMethod(this, "setupViewport", Q_ARG(QWidget *, widget));
+ delete oldViewport;
+ }
+}
+
+/*!
+ Returns the viewport widget.
+
+ Use the QScrollArea::widget() function to retrieve the contents of
+ the viewport widget.
+
+ \sa QScrollArea::widget()
+*/
+QWidget *QAbstractScrollArea::viewport() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->viewport;
+}
+
+
+/*!
+Returns the size of the viewport as if the scroll bars had no valid
+scrolling range.
+*/
+// ### still thinking about the name
+QSize QAbstractScrollArea::maximumViewportSize() const
+{
+ Q_D(const QAbstractScrollArea);
+ int hsbExt = d->hbar->sizeHint().height();
+ int vsbExt = d->vbar->sizeHint().width();
+
+ int f = 2 * d->frameWidth;
+ QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom);
+ if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
+ max.rwidth() -= vsbExt;
+ if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
+ max.rheight() -= hsbExt;
+ return max;
+}
+
+/*!
+ \property QAbstractScrollArea::verticalScrollBarPolicy
+ \brief the policy for the vertical scroll bar
+
+ The default policy is Qt::ScrollBarAsNeeded.
+
+ \sa horizontalScrollBarPolicy
+*/
+
+Qt::ScrollBarPolicy QAbstractScrollArea::verticalScrollBarPolicy() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->vbarpolicy;
+}
+
+void QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
+{
+ Q_D(QAbstractScrollArea);
+ const Qt::ScrollBarPolicy oldPolicy = d->vbarpolicy;
+ d->vbarpolicy = policy;
+ if (isVisible())
+ d->layoutChildren();
+ if (oldPolicy != d->vbarpolicy)
+ d->scrollBarPolicyChanged(Qt::Vertical, d->vbarpolicy);
+}
+
+
+/*!
+ Returns the vertical scroll bar.
+
+ \sa verticalScrollBarPolicy, horizontalScrollBar()
+ */
+QScrollBar *QAbstractScrollArea::verticalScrollBar() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->vbar;
+}
+
+/*!
+ \since 4.2
+ Replaces the existing vertical scroll bar with \a scrollBar, and sets all
+ the former scroll bar's slider properties on the new scroll bar. The former
+ scroll bar is then deleted.
+
+ QAbstractScrollArea already provides vertical and horizontal scroll bars by
+ default. You can call this function to replace the default vertical
+ scroll bar with your own custom scroll bar.
+
+ \sa verticalScrollBar(), setHorizontalScrollBar()
+*/
+void QAbstractScrollArea::setVerticalScrollBar(QScrollBar *scrollBar)
+{
+ Q_D(QAbstractScrollArea);
+ if (!scrollBar) {
+ qWarning("QAbstractScrollArea::setVerticalScrollBar: Cannot set a null scroll bar");
+ return;
+ }
+
+ d->replaceScrollBar(scrollBar, Qt::Vertical);
+}
+
+/*!
+ \property QAbstractScrollArea::horizontalScrollBarPolicy
+ \brief the policy for the horizontal scroll bar
+
+ The default policy is Qt::ScrollBarAsNeeded.
+
+ \sa verticalScrollBarPolicy
+*/
+
+Qt::ScrollBarPolicy QAbstractScrollArea::horizontalScrollBarPolicy() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->hbarpolicy;
+}
+
+void QAbstractScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
+{
+ Q_D(QAbstractScrollArea);
+ const Qt::ScrollBarPolicy oldPolicy = d->hbarpolicy;
+ d->hbarpolicy = policy;
+ if (isVisible())
+ d->layoutChildren();
+ if (oldPolicy != d->hbarpolicy)
+ d->scrollBarPolicyChanged(Qt::Horizontal, d->hbarpolicy);
+}
+
+/*!
+ Returns the horizontal scroll bar.
+
+ \sa horizontalScrollBarPolicy, verticalScrollBar()
+ */
+QScrollBar *QAbstractScrollArea::horizontalScrollBar() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->hbar;
+}
+
+/*!
+ \since 4.2
+
+ Replaces the existing horizontal scroll bar with \a scrollBar, and sets all
+ the former scroll bar's slider properties on the new scroll bar. The former
+ scroll bar is then deleted.
+
+ QAbstractScrollArea already provides horizontal and vertical scroll bars by
+ default. You can call this function to replace the default horizontal
+ scroll bar with your own custom scroll bar.
+
+ \sa horizontalScrollBar(), setVerticalScrollBar()
+*/
+void QAbstractScrollArea::setHorizontalScrollBar(QScrollBar *scrollBar)
+{
+ Q_D(QAbstractScrollArea);
+ if (!scrollBar) {
+ qWarning("QAbstractScrollArea::setHorizontalScrollBar: Cannot set a null scroll bar");
+ return;
+ }
+
+ d->replaceScrollBar(scrollBar, Qt::Horizontal);
+}
+
+/*!
+ \since 4.2
+
+ Returns the widget in the corner between the two scroll bars.
+
+ By default, no corner widget is present.
+*/
+QWidget *QAbstractScrollArea::cornerWidget() const
+{
+ Q_D(const QAbstractScrollArea);
+ return d->cornerWidget;
+}
+
+/*!
+ \since 4.2
+
+ Sets the widget in the corner between the two scroll bars to be
+ \a widget.
+
+ You will probably also want to set at least one of the scroll bar
+ modes to \c AlwaysOn.
+
+ Passing 0 shows no widget in the corner.
+
+ Any previous corner widget is hidden.
+
+ You may call setCornerWidget() with the same widget at different
+ times.
+
+ All widgets set here will be deleted by the scroll area when it is
+ destroyed unless you separately reparent the widget after setting
+ some other corner widget (or 0).
+
+ Any \e newly set widget should have no current parent.
+
+ By default, no corner widget is present.
+
+ \sa horizontalScrollBarPolicy, horizontalScrollBarPolicy
+*/
+void QAbstractScrollArea::setCornerWidget(QWidget *widget)
+{
+ Q_D(QAbstractScrollArea);
+ QWidget* oldWidget = d->cornerWidget;
+ if (oldWidget != widget) {
+ if (oldWidget)
+ oldWidget->hide();
+ d->cornerWidget = widget;
+
+ if (widget && widget->parentWidget() != this)
+ widget->setParent(this);
+
+ d->layoutChildren();
+ if (widget)
+ widget->show();
+ } else {
+ d->cornerWidget = widget;
+ d->layoutChildren();
+ }
+}
+
+/*!
+ \since 4.2
+ Adds \a widget as a scroll bar widget in the location specified
+ by \a alignment.
+
+ Scroll bar widgets are shown next to the horizontal or vertical
+ scroll bar, and can be placed on either side of it. If you want
+ the scroll bar widgets to be always visible, set the
+ scrollBarPolicy for the corresponding scroll bar to \c AlwaysOn.
+
+ \a alignment must be one of Qt::Alignleft and Qt::AlignRight,
+ which maps to the horizontal scroll bar, or Qt::AlignTop and
+ Qt::AlignBottom, which maps to the vertical scroll bar.
+
+ A scroll bar widget can be removed by either re-parenting the
+ widget or deleting it. It's also possible to hide a widget with
+ QWidget::hide()
+
+ The scroll bar widget will be resized to fit the scroll bar
+ geometry for the current style. The following describes the case
+ for scroll bar widgets on the horizontal scroll bar:
+
+ The height of the widget will be set to match the height of the
+ scroll bar. To control the width of the widget, use
+ QWidget::setMinimumWidth and QWidget::setMaximumWidth, or
+ implement QWidget::sizeHint() and set a horizontal size policy.
+ If you want a square widget, call
+ QStyle::pixelMetric(QStyle::PM_ScrollBarExtent) and set the
+ width to this value.
+
+ \sa scrollBarWidgets()
+*/
+void QAbstractScrollArea::addScrollBarWidget(QWidget *widget, Qt::Alignment alignment)
+{
+ Q_D(QAbstractScrollArea);
+
+ if (widget == 0)
+ return;
+
+ const Qt::Orientation scrollBarOrientation
+ = ((alignment & Qt::AlignLeft) || (alignment & Qt::AlignRight)) ? Qt::Horizontal : Qt::Vertical;
+ const QAbstractScrollAreaScrollBarContainer::LogicalPosition position
+ = ((alignment & Qt::AlignRight) || (alignment & Qt::AlignBottom))
+ ? QAbstractScrollAreaScrollBarContainer::LogicalRight : QAbstractScrollAreaScrollBarContainer::LogicalLeft;
+ d->scrollBarContainers[scrollBarOrientation]->addWidget(widget, position);
+ d->layoutChildren();
+ if (isHidden() == false)
+ widget->show();
+}
+
+/*!
+ \since 4.2
+ Returns a list of the currently set scroll bar widgets. \a alignment
+ can be any combination of the four location flags.
+
+ \sa addScrollBarWidget()
+*/
+QWidgetList QAbstractScrollArea::scrollBarWidgets(Qt::Alignment alignment)
+{
+ Q_D(QAbstractScrollArea);
+
+ QWidgetList list;
+
+ if (alignment & Qt::AlignLeft)
+ list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
+ if (alignment & Qt::AlignRight)
+ list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
+ if (alignment & Qt::AlignTop)
+ list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
+ if (alignment & Qt::AlignBottom)
+ list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
+
+ return list;
+}
+
+/*!
+ Sets the margins around the scrolling area to \a left, \a top, \a
+ right and \a bottom. This is useful for applications such as
+ spreadsheets with "locked" rows and columns. The marginal space is
+ is left blank; put widgets in the unused area.
+
+ Note that this function is frequently called by QTreeView and
+ QTableView, so margins must be implemented by QAbstractScrollArea
+ subclasses. Also, if the subclasses are to be used in item views,
+ they should not call this function.
+
+ By default all margins are zero.
+
+*/
+void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom)
+{
+ Q_D(QAbstractScrollArea);
+ d->left = left;
+ d->top = top;
+ d->right = right;
+ d->bottom = bottom;
+ d->layoutChildren();
+}
+
+/*!
+ \since 4.6
+ Sets \a margins around the scrolling area. This is useful for
+ applications such as spreadsheets with "locked" rows and columns.
+ The marginal space is is left blank; put widgets in the unused
+ area.
+
+ By default all margins are zero.
+
+*/
+void QAbstractScrollArea::setViewportMargins(const QMargins &margins)
+{
+ setViewportMargins(margins.left(), margins.top(),
+ margins.right(), margins.bottom());
+}
+
+/*!
+ \fn bool QAbstractScrollArea::event(QEvent *event)
+
+ \reimp
+
+ This is the main event handler for the QAbstractScrollArea widget (\e not
+ the scrolling area viewport()). The specified \a event is a general event
+ object that may need to be cast to the appropriate class depending on its
+ type.
+
+ \sa QEvent::type()
+*/
+bool QAbstractScrollArea::event(QEvent *e)
+{
+ Q_D(QAbstractScrollArea);
+ switch (e->type()) {
+ case QEvent::AcceptDropsChange:
+ // There was a chance that with accessibility client we get an
+ // event before the viewport was created.
+ // Also, in some cases we might get here from QWidget::event() virtual function which is (indirectly) called
+ // from the viewport constructor at the time when the d->viewport is not yet initialized even without any
+ // accessibility client. See qabstractscrollarea autotest for a test case.
+ if (d->viewport)
+ d->viewport->setAcceptDrops(acceptDrops());
+ break;
+ case QEvent::MouseTrackingChange:
+ d->viewport->setMouseTracking(hasMouseTracking());
+ break;
+ case QEvent::Resize:
+ d->layoutChildren();
+ break;
+ case QEvent::Paint: {
+ QStyleOption option;
+ option.initFrom(this);
+ if (d->cornerPaintingRect.isValid()) {
+ option.rect = d->cornerPaintingRect;
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
+ }
+#ifdef Q_WS_MAC
+ if (d->reverseCornerPaintingRect.isValid()) {
+ option.rect = d->reverseCornerPaintingRect;
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
+ }
+#endif
+ }
+ QFrame::paintEvent((QPaintEvent*)e);
+ break;
+#ifndef QT_NO_CONTEXTMENU
+ case QEvent::ContextMenu:
+ if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard)
+ return QFrame::event(e);
+ e->ignore();
+ break;
+#endif // QT_NO_CONTEXTMENU
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+#ifndef QT_NO_DRAGANDDROP
+ case QEvent::Drop:
+ case QEvent::DragEnter:
+ case QEvent::DragMove:
+ case QEvent::DragLeave:
+#endif
+ // ignore touch events in case they have been propagated from the viewport
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ return false;
+#ifndef QT_NO_GESTURES
+ case QEvent::Gesture:
+ {
+ QGestureEvent *ge = static_cast<QGestureEvent *>(e);
+ QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));
+ if (g) {
+ QScrollBar *hBar = horizontalScrollBar();
+ QScrollBar *vBar = verticalScrollBar();
+ QPointF delta = g->delta();
+ if (!delta.isNull()) {
+ if (QApplication::isRightToLeft())
+ delta.rx() *= -1;
+ int newX = hBar->value() - delta.x();
+ int newY = vBar->value() - delta.y();
+ hBar->setValue(newX);
+ vBar->setValue(newY);
+ }
+ return true;
+ }
+ return false;
+ }
+#endif // QT_NO_GESTURES
+ case QEvent::ScrollPrepare:
+ {
+ QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e);
+ if (d->canStartScrollingAt(se->startPos().toPoint())) {
+ QScrollBar *hBar = horizontalScrollBar();
+ QScrollBar *vBar = verticalScrollBar();
+
+ se->setViewportSize(QSizeF(viewport()->size()));
+ se->setContentPosRange(QRectF(0, 0, hBar->maximum(), vBar->maximum()));
+ se->setContentPos(QPointF(hBar->value(), vBar->value()));
+ se->accept();
+ return true;
+ }
+ return false;
+ }
+ case QEvent::Scroll:
+ {
+ QScrollEvent *se = static_cast<QScrollEvent *>(e);
+
+ QScrollBar *hBar = horizontalScrollBar();
+ QScrollBar *vBar = verticalScrollBar();
+ hBar->setValue(se->contentPos().x());
+ vBar->setValue(se->contentPos().y());
+
+#ifdef Q_WS_WIN
+ typedef BOOL (*PtrBeginPanningFeedback)(HWND);
+ typedef BOOL (*PtrUpdatePanningFeedback)(HWND, LONG, LONG, BOOL);
+ typedef BOOL (*PtrEndPanningFeedback)(HWND, BOOL);
+
+ static PtrBeginPanningFeedback ptrBeginPanningFeedback = 0;
+ static PtrUpdatePanningFeedback ptrUpdatePanningFeedback = 0;
+ static PtrEndPanningFeedback ptrEndPanningFeedback = 0;
+
+ if (!ptrBeginPanningFeedback)
+ ptrBeginPanningFeedback = (PtrBeginPanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "BeginPanningFeedback");
+ if (!ptrUpdatePanningFeedback)
+ ptrUpdatePanningFeedback = (PtrUpdatePanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "UpdatePanningFeedback");
+ if (!ptrEndPanningFeedback)
+ ptrEndPanningFeedback = (PtrEndPanningFeedback) QLibrary::resolve(QLatin1String("UxTheme"), "EndPanningFeedback");
+
+ if (ptrBeginPanningFeedback && ptrUpdatePanningFeedback && ptrEndPanningFeedback) {
+ WId wid = window()->winId();
+
+ if (!se->overshootDistance().isNull() && d->overshoot.isNull())
+ ptrBeginPanningFeedback(wid);
+ if (!se->overshootDistance().isNull())
+ ptrUpdatePanningFeedback(wid, -se->overshootDistance().x(), -se->overshootDistance().y(), false);
+ if (se->overshootDistance().isNull() && !d->overshoot.isNull())
+ ptrEndPanningFeedback(wid, true);
+ } else
+#endif
+ {
+ QPoint delta = d->overshoot - se->overshootDistance().toPoint();
+ if (!delta.isNull())
+ viewport()->move(viewport()->pos() + delta);
+ }
+ d->overshoot = se->overshootDistance().toPoint();
+
+ return true;
+ }
+ case QEvent::StyleChange:
+ case QEvent::LayoutDirectionChange:
+ case QEvent::ApplicationLayoutDirectionChange:
+ case QEvent::LayoutRequest:
+ d->layoutChildren();
+ // fall through
+ default:
+ return QFrame::event(e);
+ }
+ return true;
+}
+
+/*!
+ \fn bool QAbstractScrollArea::viewportEvent(QEvent *event)
+
+ The main event handler for the scrolling area (the viewport() widget).
+ It handles the \a event specified, and can be called by subclasses to
+ provide reasonable default behavior.
+
+ Returns true to indicate to the event system that the event has been
+ handled, and needs no further processing; otherwise returns false to
+ indicate that the event should be propagated further.
+
+ You can reimplement this function in a subclass, but we recommend
+ using one of the specialized event handlers instead.
+
+ Specialized handlers for viewport events are: paintEvent(),
+ mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(),
+ mouseMoveEvent(), wheelEvent(), dragEnterEvent(), dragMoveEvent(),
+ dragLeaveEvent(), dropEvent(), contextMenuEvent(), and
+ resizeEvent().
+*/
+bool QAbstractScrollArea::viewportEvent(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::Resize:
+ case QEvent::Paint:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ case QEvent::MouseMove:
+ case QEvent::ContextMenu:
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel:
+#endif
+#ifndef QT_NO_DRAGANDDROP
+ case QEvent::Drop:
+ case QEvent::DragEnter:
+ case QEvent::DragMove:
+ case QEvent::DragLeave:
+#endif
+ return QFrame::event(e);
+ case QEvent::LayoutRequest:
+#ifndef QT_NO_GESTURES
+ case QEvent::Gesture:
+ case QEvent::GestureOverride:
+ return event(e);
+#endif
+ case QEvent::ScrollPrepare:
+ case QEvent::Scroll:
+ return event(e);
+ default:
+ break;
+ }
+ return false; // let the viewport widget handle the event
+}
+
+/*!
+ \fn void QAbstractScrollArea::resizeEvent(QResizeEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ resize events (passed in \a event), for the viewport() widget.
+
+ When resizeEvent() is called, the viewport already has its new
+ geometry: Its new size is accessible through the
+ QResizeEvent::size() function, and the old size through
+ QResizeEvent::oldSize().
+
+ \sa QWidget::resizeEvent()
+ */
+void QAbstractScrollArea::resizeEvent(QResizeEvent *)
+{
+}
+
+/*!
+ \fn void QAbstractScrollArea::paintEvent(QPaintEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ paint events (passed in \a event), for the viewport() widget.
+
+ \note If you open a painter, make sure to open it on the viewport().
+
+ \sa QWidget::paintEvent()
+*/
+void QAbstractScrollArea::paintEvent(QPaintEvent*)
+{
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ mouse press events for the viewport() widget. The event is passed
+ in \a e.
+
+ \sa QWidget::mousePressEvent()
+*/
+void QAbstractScrollArea::mousePressEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ mouse release events for the viewport() widget. The event is
+ passed in \a e.
+
+ \sa QWidget::mouseReleaseEvent()
+*/
+void QAbstractScrollArea::mouseReleaseEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ mouse double click events for the viewport() widget. The event is
+ passed in \a e.
+
+ \sa QWidget::mouseDoubleClickEvent()
+*/
+void QAbstractScrollArea::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ mouse move events for the viewport() widget. The event is passed
+ in \a e.
+
+ \sa QWidget::mouseMoveEvent()
+*/
+void QAbstractScrollArea::mouseMoveEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ wheel events for the viewport() widget. The event is passed in \a
+ e.
+
+ \sa QWidget::wheelEvent()
+*/
+#ifndef QT_NO_WHEELEVENT
+void QAbstractScrollArea::wheelEvent(QWheelEvent *e)
+{
+ Q_D(QAbstractScrollArea);
+ if (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal)
+ QApplication::sendEvent(d->hbar, e);
+ else
+ QApplication::sendEvent(d->vbar, e);
+}
+#endif
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ This event handler can be reimplemented in a subclass to receive
+ context menu events for the viewport() widget. The event is passed
+ in \a e.
+
+ \sa QWidget::contextMenuEvent()
+*/
+void QAbstractScrollArea::contextMenuEvent(QContextMenuEvent *e)
+{
+ e->ignore();
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ This function is called with key event \a e when key presses
+ occur. It handles PageUp, PageDown, Up, Down, Left, and Right, and
+ ignores all other key presses.
+*/
+void QAbstractScrollArea::keyPressEvent(QKeyEvent * e)
+{
+ Q_D(QAbstractScrollArea);
+ if (false){
+#ifndef QT_NO_SHORTCUT
+ } else if (e == QKeySequence::MoveToPreviousPage) {
+ d->vbar->triggerAction(QScrollBar::SliderPageStepSub);
+ } else if (e == QKeySequence::MoveToNextPage) {
+ d->vbar->triggerAction(QScrollBar::SliderPageStepAdd);
+#endif
+ } else {
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ e->ignore();
+ return;
+ }
+#endif
+ switch (e->key()) {
+ case Qt::Key_Up:
+ d->vbar->triggerAction(QScrollBar::SliderSingleStepSub);
+ break;
+ case Qt::Key_Down:
+ d->vbar->triggerAction(QScrollBar::SliderSingleStepAdd);
+ break;
+ case Qt::Key_Left:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && hasEditFocus()
+ && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->minimum())) {
+ //if we aren't using the hbar or we are already at the leftmost point ignore
+ e->ignore();
+ return;
+ }
+#endif
+ d->hbar->triggerAction(
+ layoutDirection() == Qt::LeftToRight
+ ? QScrollBar::SliderSingleStepSub : QScrollBar::SliderSingleStepAdd);
+ break;
+ case Qt::Key_Right:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && hasEditFocus()
+ && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->maximum())) {
+ //if we aren't using the hbar or we are already at the rightmost point ignore
+ e->ignore();
+ return;
+ }
+#endif
+ d->hbar->triggerAction(
+ layoutDirection() == Qt::LeftToRight
+ ? QScrollBar::SliderSingleStepAdd : QScrollBar::SliderSingleStepSub);
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ }
+ e->accept();
+}
+
+
+#ifndef QT_NO_DRAGANDDROP
+/*!
+ \fn void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ drag enter events (passed in \a event), for the viewport() widget.
+
+ \sa QWidget::dragEnterEvent()
+*/
+void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *)
+{
+}
+
+/*!
+ \fn void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ drag move events (passed in \a event), for the viewport() widget.
+
+ \sa QWidget::dragMoveEvent()
+*/
+void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *)
+{
+}
+
+/*!
+ \fn void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ drag leave events (passed in \a event), for the viewport() widget.
+
+ \sa QWidget::dragLeaveEvent()
+*/
+void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *)
+{
+}
+
+/*!
+ \fn void QAbstractScrollArea::dropEvent(QDropEvent *event)
+
+ This event handler can be reimplemented in a subclass to receive
+ drop events (passed in \a event), for the viewport() widget.
+
+ \sa QWidget::dropEvent()
+*/
+void QAbstractScrollArea::dropEvent(QDropEvent *)
+{
+}
+
+
+#endif
+
+/*!
+ This virtual handler is called when the scroll bars are moved by
+ \a dx, \a dy, and consequently the viewport's contents should be
+ scrolled accordingly.
+
+ The default implementation simply calls update() on the entire
+ viewport(), subclasses can reimplement this handler for
+ optimization purposes, or - like QScrollArea - to move a contents
+ widget. The parameters \a dx and \a dy are there for convenience,
+ so that the class knows how much should be scrolled (useful
+ e.g. when doing pixel-shifts). You may just as well ignore these
+ values and scroll directly to the position the scroll bars
+ indicate.
+
+ Calling this function in order to scroll programmatically is an
+ error, use the scroll bars instead (e.g. by calling
+ QScrollBar::setValue() directly).
+*/
+void QAbstractScrollArea::scrollContentsBy(int, int)
+{
+ viewport()->update();
+}
+
+bool QAbstractScrollAreaPrivate::canStartScrollingAt( const QPoint &startPos )
+{
+ Q_Q(QAbstractScrollArea);
+
+#ifndef QT_NO_GRAPHICSVIEW
+ // don't start scrolling when a drag mode has been set.
+ // don't start scrolling on a movable item.
+ if (QGraphicsView *view = qobject_cast<QGraphicsView *>(q)) {
+ if (view->dragMode() != QGraphicsView::NoDrag)
+ return false;
+
+ QGraphicsItem *childItem = view->itemAt(startPos);
+
+ if (childItem && (childItem->flags() & QGraphicsItem::ItemIsMovable))
+ return false;
+ }
+#endif
+
+ // don't start scrolling on a QAbstractSlider
+ if (qobject_cast<QAbstractSlider *>(q->viewport()->childAt(startPos))) {
+ return false;
+ }
+
+ return true;
+}
+
+void QAbstractScrollAreaPrivate::_q_hslide(int x)
+{
+ Q_Q(QAbstractScrollArea);
+ int dx = xoffset - x;
+ xoffset = x;
+ q->scrollContentsBy(dx, 0);
+}
+
+void QAbstractScrollAreaPrivate::_q_vslide(int y)
+{
+ Q_Q(QAbstractScrollArea);
+ int dy = yoffset - y;
+ yoffset = y;
+ q->scrollContentsBy(0, dy);
+}
+
+void QAbstractScrollAreaPrivate::_q_showOrHideScrollBars()
+{
+ layoutChildren();
+#ifdef Q_WS_WIN
+ // Need to re-subscribe to gestures as the content changes to make sure we
+ // enable/disable panning when needed.
+ QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
+ if (dd)
+ dd->winSetupGestures();
+#endif // Q_WS_WIN
+}
+
+QPoint QAbstractScrollAreaPrivate::contentsOffset() const
+{
+ Q_Q(const QAbstractScrollArea);
+ QPoint offset;
+ if (vbar->isVisible())
+ offset.setY(vbar->value());
+ if (hbar->isVisible()) {
+ if (q->isRightToLeft())
+ offset.setX(hbar->maximum() - hbar->value());
+ else
+ offset.setX(hbar->value());
+ }
+ return offset;
+}
+
+/*!
+ \reimp
+
+*/
+QSize QAbstractScrollArea::minimumSizeHint() const
+{
+ Q_D(const QAbstractScrollArea);
+ int hsbExt = d->hbar->sizeHint().height();
+ int vsbExt = d->vbar->sizeHint().width();
+ int extra = 2 * d->frameWidth;
+ QStyleOption opt;
+ opt.initFrom(this);
+ if ((d->frameStyle != QFrame::NoFrame)
+ && style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, this)) {
+ extra += style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, this);
+ }
+ return QSize(d->scrollBarContainers[Qt::Horizontal]->sizeHint().width() + vsbExt + extra,
+ d->scrollBarContainers[Qt::Vertical]->sizeHint().height() + hsbExt + extra);
+}
+
+/*!
+ \reimp
+*/
+QSize QAbstractScrollArea::sizeHint() const
+{
+ return QSize(256, 192);
+#if 0
+ Q_D(const QAbstractScrollArea);
+ int h = qMax(10, fontMetrics().height());
+ int f = 2 * d->frameWidth;
+ return QSize((6 * h) + f, (4 * h) + f);
+#endif
+}
+
+/*!
+ This slot is called by QAbstractScrollArea after setViewport(\a
+ viewport) has been called. Reimplement this function in a
+ subclass of QAbstractScrollArea to initialize the new \a viewport
+ before it is used.
+
+ \sa setViewport()
+*/
+void QAbstractScrollArea::setupViewport(QWidget *viewport)
+{
+ Q_UNUSED(viewport);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractscrollarea.cpp"
+#include "moc_qabstractscrollarea_p.cpp"
+
+#endif // QT_NO_SCROLLAREA
diff --git a/src/widgets/widgets/qabstractscrollarea.h b/src/widgets/widgets/qabstractscrollarea.h
new file mode 100644
index 0000000000..3f2a273297
--- /dev/null
+++ b/src/widgets/widgets/qabstractscrollarea.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSCROLLAREA_H
+#define QABSTRACTSCROLLAREA_H
+
+#include <QtWidgets/qframe.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SCROLLAREA
+
+class QMargins;
+class QScrollBar;
+class QAbstractScrollAreaPrivate;
+
+class Q_WIDGETS_EXPORT QAbstractScrollArea : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::ScrollBarPolicy verticalScrollBarPolicy READ verticalScrollBarPolicy WRITE setVerticalScrollBarPolicy)
+ Q_PROPERTY(Qt::ScrollBarPolicy horizontalScrollBarPolicy READ horizontalScrollBarPolicy WRITE setHorizontalScrollBarPolicy)
+
+public:
+ explicit QAbstractScrollArea(QWidget* parent=0);
+ ~QAbstractScrollArea();
+
+ Qt::ScrollBarPolicy verticalScrollBarPolicy() const;
+ void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy);
+ QScrollBar *verticalScrollBar() const;
+ void setVerticalScrollBar(QScrollBar *scrollbar);
+
+ Qt::ScrollBarPolicy horizontalScrollBarPolicy() const;
+ void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy);
+ QScrollBar *horizontalScrollBar() const;
+ void setHorizontalScrollBar(QScrollBar *scrollbar);
+
+ QWidget *cornerWidget() const;
+ void setCornerWidget(QWidget *widget);
+
+ void addScrollBarWidget(QWidget *widget, Qt::Alignment alignment);
+ QWidgetList scrollBarWidgets(Qt::Alignment alignment);
+
+ QWidget *viewport() const;
+ void setViewport(QWidget *widget);
+ QSize maximumViewportSize() const;
+
+ QSize minimumSizeHint() const;
+
+ QSize sizeHint() const;
+
+protected Q_SLOTS:
+ void setupViewport(QWidget *viewport);
+
+protected:
+ QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent = 0);
+ void setViewportMargins(int left, int top, int right, int bottom);
+ void setViewportMargins(const QMargins &margins);
+
+ bool event(QEvent *);
+ virtual bool viewportEvent(QEvent *);
+
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *);
+#endif
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *);
+#endif
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *);
+ void dragMoveEvent(QDragMoveEvent *);
+ void dragLeaveEvent(QDragLeaveEvent *);
+ void dropEvent(QDropEvent *);
+#endif
+
+ void keyPressEvent(QKeyEvent *);
+
+ virtual void scrollContentsBy(int dx, int dy);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractScrollArea)
+ Q_DISABLE_COPY(QAbstractScrollArea)
+ Q_PRIVATE_SLOT(d_func(), void _q_hslide(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_vslide(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_showOrHideScrollBars())
+
+ friend class QStyleSheetStyle;
+ friend class QWidgetPrivate;
+};
+
+#endif // QT_NO_SCROLLAREA
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTSCROLLAREA_H
diff --git a/src/widgets/widgets/qabstractscrollarea_p.h b/src/widgets/widgets/qabstractscrollarea_p.h
new file mode 100644
index 0000000000..5511d08f4e
--- /dev/null
+++ b/src/widgets/widgets/qabstractscrollarea_p.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSCROLLAREA_P_H
+#define QABSTRACTSCROLLAREA_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/qframe_p.h"
+#include "qabstractscrollarea.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SCROLLAREA
+
+class QScrollBar;
+class QAbstractScrollAreaScrollBarContainer;
+class Q_WIDGETS_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractScrollArea)
+
+public:
+ QAbstractScrollAreaPrivate();
+
+ void replaceScrollBar(QScrollBar *scrollBar, Qt::Orientation orientation);
+
+ QAbstractScrollAreaScrollBarContainer *scrollBarContainers[Qt::Vertical + 1];
+ QScrollBar *hbar, *vbar;
+ Qt::ScrollBarPolicy vbarpolicy, hbarpolicy;
+
+ QWidget *viewport;
+ QWidget *cornerWidget;
+ QRect cornerPaintingRect;
+#ifdef Q_WS_MAC
+ QRect reverseCornerPaintingRect;
+#endif
+ int left, top, right, bottom; // viewport margin
+
+ int xoffset, yoffset;
+ QPoint overshoot;
+
+ void init();
+ void layoutChildren();
+ // ### Fix for 4.4, talk to Bjoern E or Girish.
+ virtual void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) {}
+ bool canStartScrollingAt( const QPoint &startPos );
+
+ void _q_hslide(int);
+ void _q_vslide(int);
+ void _q_showOrHideScrollBars();
+
+ virtual QPoint contentsOffset() const;
+
+ inline bool viewportEvent(QEvent *event)
+ { return q_func()->viewportEvent(event); }
+ QScopedPointer<QObject> viewportFilter;
+
+#ifdef Q_WS_WIN
+ bool singleFingerPanEnabled;
+ void setSingleFingerPanEnabled(bool on = true);
+#endif
+};
+
+class QAbstractScrollAreaFilter : public QObject
+{
+ Q_OBJECT
+public:
+ QAbstractScrollAreaFilter(QAbstractScrollAreaPrivate *p) : d(p)
+ { setObjectName(QLatin1String("qt_abstractscrollarea_filter")); }
+ bool eventFilter(QObject *o, QEvent *e)
+ { return (o == d->viewport ? d->viewportEvent(e) : false); }
+private:
+ QAbstractScrollAreaPrivate *d;
+};
+
+class QBoxLayout;
+class QAbstractScrollAreaScrollBarContainer : public QWidget
+{
+public:
+ enum LogicalPosition { LogicalLeft = 1, LogicalRight = 2 };
+
+ QAbstractScrollAreaScrollBarContainer(Qt::Orientation orientation, QWidget *parent);
+ void addWidget(QWidget *widget, LogicalPosition position);
+ QWidgetList widgets(LogicalPosition position);
+ void removeWidget(QWidget *widget);
+
+ QScrollBar *scrollBar;
+ QBoxLayout *layout;
+private:
+ int scrollBarLayoutIndex() const;
+
+ Qt::Orientation orientation;
+};
+
+#endif // QT_NO_SCROLLAREA
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTSCROLLAREA_P_H
diff --git a/src/widgets/widgets/qabstractslider.cpp b/src/widgets/widgets/qabstractslider.cpp
new file mode 100644
index 0000000000..c86146e83e
--- /dev/null
+++ b/src/widgets/widgets/qabstractslider.cpp
@@ -0,0 +1,1001 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qapplication.h>
+#include "qabstractslider.h"
+#include "qevent.h"
+#include "qabstractslider_p.h"
+#include "qdebug.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractSlider
+ \brief The QAbstractSlider class provides an integer value within a range.
+
+ \ingroup abstractwidgets
+
+ The class is designed as a common super class for widgets like
+ QScrollBar, QSlider and QDial.
+
+ Here are the main properties of the class:
+
+ \list 1
+
+ \i \l value: The bounded integer that QAbstractSlider maintains.
+
+ \i \l minimum: The lowest possible value.
+
+ \i \l maximum: The highest possible value.
+
+ \i \l singleStep: The smaller of two natural steps that an
+ abstract sliders provides and typically corresponds to the user
+ pressing an arrow key.
+
+ \i \l pageStep: The larger of two natural steps that an abstract
+ slider provides and typically corresponds to the user pressing
+ PageUp or PageDown.
+
+ \i \l tracking: Whether slider tracking is enabled.
+
+ \i \l sliderPosition: The current position of the slider. If \l
+ tracking is enabled (the default), this is identical to \l value.
+
+ \endlist
+
+ Unity (1) may be viewed as a third step size. setValue() lets you
+ set the current value to any integer in the allowed range, not
+ just minimum() + \e n * singleStep() for integer values of \e n.
+ Some widgets may allow the user to set any value at all; others
+ may just provide multiples of singleStep() or pageStep().
+
+ QAbstractSlider emits a comprehensive set of signals:
+
+ \table
+ \header \i Signal \i Emitted when
+ \row \i \l valueChanged()
+ \i the value has changed. The \l tracking
+ determines whether this signal is emitted during user
+ interaction.
+ \row \i \l sliderPressed()
+ \i the user starts to drag the slider.
+ \row \i \l sliderMoved()
+ \i the user drags the slider.
+ \row \i \l sliderReleased()
+ \i the user releases the slider.
+ \row \i \l actionTriggered()
+ \i a slider action was triggerd.
+ \row \i \l rangeChanged()
+ \i a the range has changed.
+ \endtable
+
+ QAbstractSlider provides a virtual sliderChange() function that is
+ well suited for updating the on-screen representation of
+ sliders. By calling triggerAction(), subclasses trigger slider
+ actions. Two helper functions QStyle::sliderPositionFromValue() and
+ QStyle::sliderValueFromPosition() help subclasses and styles to map
+ screen coordinates to logical range values.
+
+ \sa QAbstractSpinBox, QSlider, QDial, QScrollBar, {Sliders Example}
+*/
+
+/*!
+ \enum QAbstractSlider::SliderAction
+
+ \value SliderNoAction
+ \value SliderSingleStepAdd
+ \value SliderSingleStepSub
+ \value SliderPageStepAdd
+ \value SliderPageStepSub
+ \value SliderToMinimum
+ \value SliderToMaximum
+ \value SliderMove
+
+*/
+
+/*!
+ \fn void QAbstractSlider::valueChanged(int value)
+
+ This signal is emitted when the slider value has changed, with the
+ new slider \a value as argument.
+*/
+
+/*!
+ \fn void QAbstractSlider::sliderPressed()
+
+ This signal is emitted when the user presses the slider with the
+ mouse, or programmatically when setSliderDown(true) is called.
+
+ \sa sliderReleased(), sliderMoved(), isSliderDown()
+*/
+
+/*!
+ \fn void QAbstractSlider::sliderMoved(int value)
+
+ This signal is emitted when sliderDown is true and the slider moves. This
+ usually happens when the user is dragging the slider. The \a value
+ is the new slider position.
+
+ This signal is emitted even when tracking is turned off.
+
+ \sa setTracking(), valueChanged(), isSliderDown(),
+ sliderPressed(), sliderReleased()
+*/
+
+/*!
+ \fn void QAbstractSlider::sliderReleased()
+
+ This signal is emitted when the user releases the slider with the
+ mouse, or programmatically when setSliderDown(false) is called.
+
+ \sa sliderPressed() sliderMoved() sliderDown
+*/
+
+/*!
+ \fn void QAbstractSlider::rangeChanged(int min, int max)
+
+ This signal is emitted when the slider range has changed, with \a
+ min being the new minimum, and \a max being the new maximum.
+
+ \sa minimum, maximum
+*/
+
+/*!
+ \fn void QAbstractSlider::actionTriggered(int action)
+
+ This signal is emitted when the slider action \a action is
+ triggered. Actions are \l SliderSingleStepAdd, \l
+ SliderSingleStepSub, \l SliderPageStepAdd, \l SliderPageStepSub,
+ \l SliderToMinimum, \l SliderToMaximum, and \l SliderMove.
+
+ When the signal is emitted, the \l sliderPosition has been
+ adjusted according to the action, but the \l value has not yet
+ been propagated (meaning the valueChanged() signal was not yet
+ emitted), and the visual display has not been updated. In slots
+ connected to this signal you can thus safely adjust any action by
+ calling setSliderPosition() yourself, based on both the action and
+ the slider's value.
+
+ \sa triggerAction()
+*/
+
+/*!
+ \enum QAbstractSlider::SliderChange
+
+ \value SliderRangeChange
+ \value SliderOrientationChange
+ \value SliderStepsChange
+ \value SliderValueChange
+*/
+
+QAbstractSliderPrivate::QAbstractSliderPrivate()
+ : minimum(0), maximum(99), pageStep(10), value(0), position(0), pressValue(-1),
+ singleStep(1), offset_accumulated(0), tracking(true),
+ blocktracking(false), pressed(false),
+ invertedAppearance(false), invertedControls(false),
+ orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction)
+#ifdef QT_KEYPAD_NAVIGATION
+ , isAutoRepeating(false)
+ , repeatMultiplier(1)
+{
+ firstRepeat.invalidate();
+#else
+{
+#endif
+
+}
+
+QAbstractSliderPrivate::~QAbstractSliderPrivate()
+{
+}
+
+/*!
+ Sets the slider's minimum to \a min and its maximum to \a max.
+
+ If \a max is smaller than \a min, \a min becomes the only legal
+ value.
+
+ \sa minimum maximum
+*/
+void QAbstractSlider::setRange(int min, int max)
+{
+ Q_D(QAbstractSlider);
+ int oldMin = d->minimum;
+ int oldMax = d->maximum;
+ d->minimum = min;
+ d->maximum = qMax(min, max);
+ if (oldMin != d->minimum || oldMax != d->maximum) {
+ sliderChange(SliderRangeChange);
+ emit rangeChanged(d->minimum, d->maximum);
+ setValue(d->value); // re-bound
+ }
+}
+
+
+void QAbstractSliderPrivate::setSteps(int single, int page)
+{
+ Q_Q(QAbstractSlider);
+ singleStep = qAbs(single);
+ pageStep = qAbs(page);
+ q->sliderChange(QAbstractSlider::SliderStepsChange);
+}
+
+/*!
+ Constructs an abstract slider.
+
+ The \a parent argument is sent to the QWidget constructor.
+
+ The \l minimum defaults to 0, the \l maximum to 99, with a \l
+ singleStep size of 1 and a \l pageStep size of 10, and an initial
+ \l value of 0.
+*/
+QAbstractSlider::QAbstractSlider(QWidget *parent)
+ :QWidget(*new QAbstractSliderPrivate, parent, 0)
+{
+}
+
+/*! \internal */
+QAbstractSlider::QAbstractSlider(QAbstractSliderPrivate &dd, QWidget *parent)
+ :QWidget(dd, parent, 0)
+{
+}
+
+/*!
+ Destroys the slider.
+*/
+QAbstractSlider::~QAbstractSlider()
+{
+}
+
+/*!
+ \property QAbstractSlider::orientation
+ \brief the orientation of the slider
+
+ The orientation must be \l Qt::Vertical (the default) or \l
+ Qt::Horizontal.
+*/
+void QAbstractSlider::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QAbstractSlider);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy(sp);
+ setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ }
+ update();
+ updateGeometry();
+}
+
+Qt::Orientation QAbstractSlider::orientation() const
+{
+ Q_D(const QAbstractSlider);
+ return d->orientation;
+}
+
+
+/*!
+ \property QAbstractSlider::minimum
+ \brief the sliders's minimum value
+
+ When setting this property, the \l maximum is adjusted if
+ necessary to ensure that the range remains valid. Also the
+ slider's current value is adjusted to be within the new range.
+
+*/
+
+void QAbstractSlider::setMinimum(int min)
+{
+ Q_D(QAbstractSlider);
+ setRange(min, qMax(d->maximum, min));
+}
+
+int QAbstractSlider::minimum() const
+{
+ Q_D(const QAbstractSlider);
+ return d->minimum;
+}
+
+
+/*!
+ \property QAbstractSlider::maximum
+ \brief the slider's maximum value
+
+ When setting this property, the \l minimum is adjusted if
+ necessary to ensure that the range remains valid. Also the
+ slider's current value is adjusted to be within the new range.
+
+
+*/
+
+void QAbstractSlider::setMaximum(int max)
+{
+ Q_D(QAbstractSlider);
+ setRange(qMin(d->minimum, max), max);
+}
+
+int QAbstractSlider::maximum() const
+{
+ Q_D(const QAbstractSlider);
+ return d->maximum;
+}
+
+
+
+/*!
+ \property QAbstractSlider::singleStep
+ \brief the single step.
+
+ The smaller of two natural steps that an
+ abstract sliders provides and typically corresponds to the user
+ pressing an arrow key.
+
+ If the property is modified during an auto repeating key event, behavior
+ is undefined.
+
+ \sa pageStep
+*/
+
+void QAbstractSlider::setSingleStep(int step)
+{
+ Q_D(QAbstractSlider);
+ if (step != d->singleStep)
+ d->setSteps(step, d->pageStep);
+}
+
+int QAbstractSlider::singleStep() const
+{
+ Q_D(const QAbstractSlider);
+ return d->singleStep;
+}
+
+
+/*!
+ \property QAbstractSlider::pageStep
+ \brief the page step.
+
+ The larger of two natural steps that an abstract slider provides
+ and typically corresponds to the user pressing PageUp or PageDown.
+
+ \sa singleStep
+*/
+
+void QAbstractSlider::setPageStep(int step)
+{
+ Q_D(QAbstractSlider);
+ if (step != d->pageStep)
+ d->setSteps(d->singleStep, step);
+}
+
+int QAbstractSlider::pageStep() const
+{
+ Q_D(const QAbstractSlider);
+ return d->pageStep;
+}
+
+/*!
+ \property QAbstractSlider::tracking
+ \brief whether slider tracking is enabled
+
+ If tracking is enabled (the default), the slider emits the
+ valueChanged() signal while the slider is being dragged. If
+ tracking is disabled, the slider emits the valueChanged() signal
+ only when the user releases the slider.
+
+ \sa sliderDown
+*/
+void QAbstractSlider::setTracking(bool enable)
+{
+ Q_D(QAbstractSlider);
+ d->tracking = enable;
+}
+
+bool QAbstractSlider::hasTracking() const
+{
+ Q_D(const QAbstractSlider);
+ return d->tracking;
+}
+
+
+/*!
+ \property QAbstractSlider::sliderDown
+ \brief whether the slider is pressed down.
+
+ The property is set by subclasses in order to let the abstract
+ slider know whether or not \l tracking has any effect.
+
+ Changing the slider down property emits the sliderPressed() and
+ sliderReleased() signals.
+
+*/
+void QAbstractSlider::setSliderDown(bool down)
+{
+ Q_D(QAbstractSlider);
+ bool doEmit = d->pressed != down;
+
+ d->pressed = down;
+
+ if (doEmit) {
+ if (down)
+ emit sliderPressed();
+ else
+ emit sliderReleased();
+ }
+
+ if (!down && d->position != d->value)
+ triggerAction(SliderMove);
+}
+
+bool QAbstractSlider::isSliderDown() const
+{
+ Q_D(const QAbstractSlider);
+ return d->pressed;
+}
+
+
+/*!
+ \property QAbstractSlider::sliderPosition
+ \brief the current slider position
+
+ If \l tracking is enabled (the default), this is identical to \l value.
+*/
+void QAbstractSlider::setSliderPosition(int position)
+{
+ Q_D(QAbstractSlider);
+ position = d->bound(position);
+ if (position == d->position)
+ return;
+ d->position = position;
+ if (!d->tracking)
+ update();
+ if (d->pressed)
+ emit sliderMoved(position);
+ if (d->tracking && !d->blocktracking)
+ triggerAction(SliderMove);
+}
+
+int QAbstractSlider::sliderPosition() const
+{
+ Q_D(const QAbstractSlider);
+ return d->position;
+}
+
+
+/*!
+ \property QAbstractSlider::value
+ \brief the slider's current value
+
+ The slider forces the value to be within the legal range: \l
+ minimum <= \c value <= \l maximum.
+
+ Changing the value also changes the \l sliderPosition.
+*/
+
+
+int QAbstractSlider::value() const
+{
+ Q_D(const QAbstractSlider);
+ return d->value;
+}
+
+void QAbstractSlider::setValue(int value)
+{
+ Q_D(QAbstractSlider);
+ value = d->bound(value);
+ if (d->value == value && d->position == value)
+ return;
+ d->value = value;
+ if (d->position != value) {
+ d->position = value;
+ if (d->pressed)
+ emit sliderMoved((d->position = value));
+ }
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
+#endif
+ sliderChange(SliderValueChange);
+ emit valueChanged(value);
+}
+
+/*!
+ \property QAbstractSlider::invertedAppearance
+ \brief whether or not a slider shows its values inverted.
+
+ If this property is false (the default), the minimum and maximum will
+ be shown in its classic position for the inherited widget. If the
+ value is true, the minimum and maximum appear at their opposite location.
+
+ Note: This property makes most sense for sliders and dials. For
+ scroll bars, the visual effect of the scroll bar subcontrols depends on
+ whether or not the styles understand inverted appearance; most styles
+ ignore this property for scroll bars.
+*/
+
+bool QAbstractSlider::invertedAppearance() const
+{
+ Q_D(const QAbstractSlider);
+ return d->invertedAppearance;
+}
+
+void QAbstractSlider::setInvertedAppearance(bool invert)
+{
+ Q_D(QAbstractSlider);
+ d->invertedAppearance = invert;
+ update();
+}
+
+
+/*!
+ \property QAbstractSlider::invertedControls
+ \brief whether or not the slider inverts its wheel and key events.
+
+ If this property is false, scrolling the mouse wheel "up" and using keys
+ like page up will increase the slider's value towards its maximum. Otherwise
+ pressing page up will move value towards the slider's minimum.
+*/
+
+
+bool QAbstractSlider::invertedControls() const
+{
+ Q_D(const QAbstractSlider);
+ return d->invertedControls;
+}
+
+void QAbstractSlider::setInvertedControls(bool invert)
+{
+ Q_D(QAbstractSlider);
+ d->invertedControls = invert;
+}
+
+/*! Triggers a slider \a action. Possible actions are \l
+ SliderSingleStepAdd, \l SliderSingleStepSub, \l SliderPageStepAdd,
+ \l SliderPageStepSub, \l SliderToMinimum, \l SliderToMaximum, and \l
+ SliderMove.
+
+ \sa actionTriggered()
+ */
+void QAbstractSlider::triggerAction(SliderAction action)
+{
+ Q_D(QAbstractSlider);
+ d->blocktracking = true;
+ switch (action) {
+ case SliderSingleStepAdd:
+ setSliderPosition(d->overflowSafeAdd(d->effectiveSingleStep()));
+ break;
+ case SliderSingleStepSub:
+ setSliderPosition(d->overflowSafeAdd(-d->effectiveSingleStep()));
+ break;
+ case SliderPageStepAdd:
+ setSliderPosition(d->overflowSafeAdd(d->pageStep));
+ break;
+ case SliderPageStepSub:
+ setSliderPosition(d->overflowSafeAdd(-d->pageStep));
+ break;
+ case SliderToMinimum:
+ setSliderPosition(d->minimum);
+ break;
+ case SliderToMaximum:
+ setSliderPosition(d->maximum);
+ break;
+ case SliderMove:
+ case SliderNoAction:
+ break;
+ };
+ emit actionTriggered(action);
+ d->blocktracking = false;
+ setValue(d->position);
+}
+
+/*! Sets action \a action to be triggered repetitively in intervals
+of \a repeatTime, after an initial delay of \a thresholdTime.
+
+\sa triggerAction() repeatAction()
+ */
+void QAbstractSlider::setRepeatAction(SliderAction action, int thresholdTime, int repeatTime)
+{
+ Q_D(QAbstractSlider);
+ if ((d->repeatAction = action) == SliderNoAction) {
+ d->repeatActionTimer.stop();
+ } else {
+ d->repeatActionTime = repeatTime;
+ d->repeatActionTimer.start(thresholdTime, this);
+ }
+}
+
+/*!
+ Returns the current repeat action.
+ \sa setRepeatAction()
+ */
+QAbstractSlider::SliderAction QAbstractSlider::repeatAction() const
+{
+ Q_D(const QAbstractSlider);
+ return d->repeatAction;
+}
+
+/*!\reimp
+ */
+void QAbstractSlider::timerEvent(QTimerEvent *e)
+{
+ Q_D(QAbstractSlider);
+ if (e->timerId() == d->repeatActionTimer.timerId()) {
+ if (d->repeatActionTime) { // was threshold time, use repeat time next time
+ d->repeatActionTimer.start(d->repeatActionTime, this);
+ d->repeatActionTime = 0;
+ }
+ if (d->repeatAction == SliderPageStepAdd)
+ d->setAdjustedSliderPosition(d->overflowSafeAdd(d->pageStep));
+ else if (d->repeatAction == SliderPageStepSub)
+ d->setAdjustedSliderPosition(d->overflowSafeAdd(-d->pageStep));
+ else
+ triggerAction(d->repeatAction);
+ }
+}
+
+/*!
+ Reimplement this virtual function to track slider changes such as
+ \l SliderRangeChange, \l SliderOrientationChange, \l
+ SliderStepsChange, or \l SliderValueChange. The default
+ implementation only updates the display and ignores the \a change
+ parameter.
+ */
+void QAbstractSlider::sliderChange(SliderChange)
+{
+ update();
+}
+
+bool QAbstractSliderPrivate::scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta)
+{
+ Q_Q(QAbstractSlider);
+ int stepsToScroll = 0;
+ // in Qt scrolling to the right gives negative values.
+ if (orientation == Qt::Horizontal)
+ delta = -delta;
+ qreal offset = qreal(delta) / 120;
+
+ if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::ShiftModifier)) {
+ // Scroll one page regardless of delta:
+ stepsToScroll = qBound(-pageStep, int(offset * pageStep), pageStep);
+ offset_accumulated = 0;
+ } else {
+ // Calculate how many lines to scroll. Depending on what delta is (and
+ // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can
+ // only scroll whole lines, so we keep the reminder until next event.
+ qreal stepsToScrollF =
+#ifndef QT_NO_WHEELEVENT
+ QApplication::wheelScrollLines() *
+#endif
+ offset * effectiveSingleStep();
+ // Check if wheel changed direction since last event:
+ if (offset_accumulated != 0 && (offset / offset_accumulated) < 0)
+ offset_accumulated = 0;
+
+ offset_accumulated += stepsToScrollF;
+#ifndef Q_WS_MAC
+ // Don't scroll more than one page in any case:
+ stepsToScroll = qBound(-pageStep, int(offset_accumulated), pageStep);
+#else
+ // Native UI-elements on Mac can scroll hundreds of lines at a time as
+ // a result of acceleration. So keep the same behaviour in Qt, and
+ // don't restrict stepsToScroll to certain maximum (pageStep):
+ stepsToScroll = int(offset_accumulated);
+#endif
+ offset_accumulated -= int(offset_accumulated);
+ if (stepsToScroll == 0)
+ return false;
+ }
+
+ if (invertedControls)
+ stepsToScroll = -stepsToScroll;
+
+ int prevValue = value;
+ position = overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction()
+ q->triggerAction(QAbstractSlider::SliderMove);
+
+ if (prevValue == value) {
+ offset_accumulated = 0;
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QAbstractSlider::wheelEvent(QWheelEvent * e)
+{
+ Q_D(QAbstractSlider);
+ e->ignore();
+ int delta = e->delta();
+ if (d->scrollByDelta(e->orientation(), e->modifiers(), delta))
+ e->accept();
+}
+
+#endif
+
+/*!
+ \reimp
+*/
+void QAbstractSlider::keyPressEvent(QKeyEvent *ev)
+{
+ Q_D(QAbstractSlider);
+ SliderAction action = SliderNoAction;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (ev->isAutoRepeat()) {
+ if (!d->firstRepeat.isValid())
+ d->firstRepeat.start();
+ else if (1 == d->repeatMultiplier) {
+ // This is the interval in milli seconds which one key repetition
+ // takes.
+ const int repeatMSecs = d->firstRepeat.elapsed();
+
+ /**
+ * The time it takes to currently navigate the whole slider.
+ */
+ const qreal currentTimeElapse = (qreal(maximum()) / singleStep()) * repeatMSecs;
+
+ /**
+ * This is an arbitrarily determined constant in msecs that
+ * specifies how long time it should take to navigate from the
+ * start to the end(excluding starting key auto repeat).
+ */
+ const int SliderRepeatElapse = 2500;
+
+ d->repeatMultiplier = currentTimeElapse / SliderRepeatElapse;
+ }
+
+ }
+ else if (d->firstRepeat.isValid()) {
+ d->firstRepeat.invalidate();
+ d->repeatMultiplier = 1;
+ }
+
+#endif
+
+ switch (ev->key()) {
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled())
+ setEditFocus(!hasEditFocus());
+ else
+ ev->ignore();
+ break;
+ case Qt::Key_Back:
+ if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
+ setValue(d->origValue);
+ setEditFocus(false);
+ } else
+ ev->ignore();
+ break;
+#endif
+
+ // It seems we need to use invertedAppearance for Left and right, otherwise, things look weird.
+ case Qt::Key_Left:
+#ifdef QT_KEYPAD_NAVIGATION
+ // In QApplication::KeypadNavigationDirectional, we want to change the slider
+ // value if there is no left/right navigation possible and if this slider is not
+ // inside a tab widget.
+ if (QApplication::keypadNavigationEnabled()
+ && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
+ || d->orientation == Qt::Vertical
+ || !hasEditFocus()
+ && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
+ ev->ignore();
+ return;
+ }
+ if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
+ action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
+ else
+#endif
+ if (isRightToLeft())
+ action = d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
+ else
+ action = !d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
+ break;
+ case Qt::Key_Right:
+#ifdef QT_KEYPAD_NAVIGATION
+ // Same logic as in Qt::Key_Left
+ if (QApplication::keypadNavigationEnabled()
+ && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
+ || d->orientation == Qt::Vertical
+ || !hasEditFocus()
+ && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
+ ev->ignore();
+ return;
+ }
+ if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
+ action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
+ else
+#endif
+ if (isRightToLeft())
+ action = d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
+ else
+ action = !d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
+ break;
+ case Qt::Key_Up:
+#ifdef QT_KEYPAD_NAVIGATION
+ // In QApplication::KeypadNavigationDirectional, we want to change the slider
+ // value if there is no up/down navigation possible.
+ if (QApplication::keypadNavigationEnabled()
+ && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
+ || d->orientation == Qt::Horizontal
+ || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
+ ev->ignore();
+ break;
+ }
+#endif
+ action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
+ break;
+ case Qt::Key_Down:
+#ifdef QT_KEYPAD_NAVIGATION
+ // Same logic as in Qt::Key_Up
+ if (QApplication::keypadNavigationEnabled()
+ && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
+ || d->orientation == Qt::Horizontal
+ || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
+ ev->ignore();
+ break;
+ }
+#endif
+ action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
+ break;
+ case Qt::Key_PageUp:
+ action = d->invertedControls ? SliderPageStepSub : SliderPageStepAdd;
+ break;
+ case Qt::Key_PageDown:
+ action = d->invertedControls ? SliderPageStepAdd : SliderPageStepSub;
+ break;
+ case Qt::Key_Home:
+ action = SliderToMinimum;
+ break;
+ case Qt::Key_End:
+ action = SliderToMaximum;
+ break;
+ default:
+ ev->ignore();
+ break;
+ }
+ if (action)
+ triggerAction(action);
+}
+
+/*!
+ \reimp
+*/
+void QAbstractSlider::changeEvent(QEvent *ev)
+{
+ Q_D(QAbstractSlider);
+ switch (ev->type()) {
+ case QEvent::EnabledChange:
+ if (!isEnabled()) {
+ d->repeatActionTimer.stop();
+ setSliderDown(false);
+ }
+ // fall through...
+ default:
+ QWidget::changeEvent(ev);
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractSlider::event(QEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_D(QAbstractSlider);
+ switch (e->type()) {
+ case QEvent::FocusIn:
+ d->origValue = d->value;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ return QWidget::event(e);
+}
+
+/*! \fn int QAbstractSlider::minValue() const
+
+ Use minimum() instead.
+*/
+
+/*! \fn int QAbstractSlider::maxValue() const
+
+ Use maximum() instead.
+*/
+
+/*! \fn int QAbstractSlider::lineStep() const
+
+ Use singleStep() instead.
+*/
+
+/*! \fn void QAbstractSlider::setMinValue(int v)
+
+ Use setMinimum() instead.
+*/
+
+/*! \fn void QAbstractSlider::setMaxValue(int v)
+
+ Use setMaximum() instead.
+*/
+
+/*! \fn void QAbstractSlider::setLineStep(int v)
+
+ Use setSingleStep() instead.
+*/
+
+/*! \fn void QAbstractSlider::addPage()
+
+ Use triggerAction(QAbstractSlider::SliderPageStepAdd) instead.
+*/
+
+/*! \fn void QAbstractSlider::subtractPage()
+
+ Use triggerAction(QAbstractSlider::SliderPageStepSub) instead.
+*/
+
+/*! \fn void QAbstractSlider::addLine()
+
+ Use triggerAction(QAbstractSlider::SliderSingleStepAdd) instead.
+*/
+
+/*! \fn void QAbstractSlider::subtractLine()
+
+ Use triggerAction(QAbstractSlider::SliderSingleStepSub) instead.
+*/
+
+/*! \fn void QAbstractSlider::setSteps(int single, int page)
+
+ Use setSingleStep(\a single) followed by setPageStep(\a page)
+ instead.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qabstractslider.h b/src/widgets/widgets/qabstractslider.h
new file mode 100644
index 0000000000..109798154e
--- /dev/null
+++ b/src/widgets/widgets/qabstractslider.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSLIDER_H
+#define QABSTRACTSLIDER_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QAbstractSliderPrivate;
+
+class Q_WIDGETS_EXPORT QAbstractSlider : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int minimum READ minimum WRITE setMinimum)
+ Q_PROPERTY(int maximum READ maximum WRITE setMaximum)
+ Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep)
+ Q_PROPERTY(int pageStep READ pageStep WRITE setPageStep)
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true)
+ Q_PROPERTY(int sliderPosition READ sliderPosition WRITE setSliderPosition NOTIFY sliderMoved)
+ Q_PROPERTY(bool tracking READ hasTracking WRITE setTracking)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(bool invertedAppearance READ invertedAppearance WRITE setInvertedAppearance)
+ Q_PROPERTY(bool invertedControls READ invertedControls WRITE setInvertedControls)
+ Q_PROPERTY(bool sliderDown READ isSliderDown WRITE setSliderDown DESIGNABLE false)
+
+public:
+ explicit QAbstractSlider(QWidget *parent=0);
+ ~QAbstractSlider();
+
+ Qt::Orientation orientation() const;
+
+ void setMinimum(int);
+ int minimum() const;
+
+ void setMaximum(int);
+ int maximum() const;
+
+ void setRange(int min, int max);
+
+ void setSingleStep(int);
+ int singleStep() const;
+
+ void setPageStep(int);
+ int pageStep() const;
+
+ void setTracking(bool enable);
+ bool hasTracking() const;
+
+ void setSliderDown(bool);
+ bool isSliderDown() const;
+
+ void setSliderPosition(int);
+ int sliderPosition() const;
+
+ void setInvertedAppearance(bool);
+ bool invertedAppearance() const;
+
+ void setInvertedControls(bool);
+ bool invertedControls() const;
+
+ enum SliderAction {
+ SliderNoAction,
+ SliderSingleStepAdd,
+ SliderSingleStepSub,
+ SliderPageStepAdd,
+ SliderPageStepSub,
+ SliderToMinimum,
+ SliderToMaximum,
+ SliderMove
+ };
+
+ int value() const;
+
+ void triggerAction(SliderAction action);
+
+public Q_SLOTS:
+ void setValue(int);
+ void setOrientation(Qt::Orientation);
+
+Q_SIGNALS:
+ void valueChanged(int value);
+
+ void sliderPressed();
+ void sliderMoved(int position);
+ void sliderReleased();
+
+ void rangeChanged(int min, int max);
+
+ void actionTriggered(int action);
+
+protected:
+ bool event(QEvent *e);
+
+ void setRepeatAction(SliderAction action, int thresholdTime = 500, int repeatTime = 50);
+ SliderAction repeatAction() const;
+
+ enum SliderChange {
+ SliderRangeChange,
+ SliderOrientationChange,
+ SliderStepsChange,
+ SliderValueChange
+ };
+ virtual void sliderChange(SliderChange change);
+
+ void keyPressEvent(QKeyEvent *ev);
+ void timerEvent(QTimerEvent *);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *e);
+#endif
+ void changeEvent(QEvent *e);
+
+#ifdef QT3_SUPPORT
+public:
+ inline QT3_SUPPORT int minValue() const { return minimum(); }
+ inline QT3_SUPPORT int maxValue() const { return maximum(); }
+ inline QT3_SUPPORT int lineStep() const { return singleStep(); }
+ inline QT3_SUPPORT void setMinValue(int v) { setMinimum(v); }
+ inline QT3_SUPPORT void setMaxValue(int v) { setMaximum(v); }
+ inline QT3_SUPPORT void setLineStep(int v) { setSingleStep(v); }
+ inline QT3_SUPPORT void setSteps(int single, int page) { setSingleStep(single); setPageStep(page); }
+ inline QT3_SUPPORT void addPage() { triggerAction(SliderPageStepAdd); }
+ inline QT3_SUPPORT void subtractPage() { triggerAction(SliderPageStepSub); }
+ inline QT3_SUPPORT void addLine() { triggerAction(SliderSingleStepAdd); }
+ inline QT3_SUPPORT void subtractLine() { triggerAction(SliderSingleStepSub); }
+#endif
+
+protected:
+ QAbstractSlider(QAbstractSliderPrivate &dd, QWidget *parent=0);
+
+private:
+ Q_DISABLE_COPY(QAbstractSlider)
+ Q_DECLARE_PRIVATE(QAbstractSlider)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTSLIDER_H
diff --git a/src/widgets/widgets/qabstractslider_p.h b/src/widgets/widgets/qabstractslider_p.h
new file mode 100644
index 0000000000..fdbc0f9534
--- /dev/null
+++ b/src/widgets/widgets/qabstractslider_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSLIDER_P_H
+#define QABSTRACTSLIDER_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 "QtCore/qbasictimer.h"
+#include "QtCore/qelapsedtimer.h"
+#include "private/qwidget_p.h"
+#include "qstyle.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractSliderPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractSlider)
+public:
+ QAbstractSliderPrivate();
+ ~QAbstractSliderPrivate();
+
+ void setSteps(int single, int page);
+
+ int minimum, maximum, pageStep, value, position, pressValue;
+
+ /**
+ * Call effectiveSingleStep() when changing the slider value.
+ */
+ int singleStep;
+
+ float offset_accumulated;
+ uint tracking : 1;
+ uint blocktracking :1;
+ uint pressed : 1;
+ uint invertedAppearance : 1;
+ uint invertedControls : 1;
+ Qt::Orientation orientation;
+
+ QBasicTimer repeatActionTimer;
+ int repeatActionTime;
+ QAbstractSlider::SliderAction repeatAction;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ int origValue;
+
+ /**
+ */
+ bool isAutoRepeating;
+
+ /**
+ * When we're auto repeating, we multiply singleStep with this value to
+ * get our effective step.
+ */
+ qreal repeatMultiplier;
+
+ /**
+ * The time of when the first auto repeating key press event occurs.
+ */
+ QElapsedTimer firstRepeat;
+
+#endif
+
+ inline int effectiveSingleStep() const
+ {
+ return singleStep
+#ifdef QT_KEYPAD_NAVIGATION
+ * repeatMultiplier
+#endif
+ ;
+ }
+
+ virtual int bound(int val) const { return qMax(minimum, qMin(maximum, val)); }
+ inline int overflowSafeAdd(int add) const
+ {
+ int newValue = value + add;
+ if (add > 0 && newValue < value)
+ newValue = maximum;
+ else if (add < 0 && newValue > value)
+ newValue = minimum;
+ return newValue;
+ }
+ inline void setAdjustedSliderPosition(int position)
+ {
+ Q_Q(QAbstractSlider);
+ if (q->style()->styleHint(QStyle::SH_Slider_StopMouseOverSlider, 0, q)) {
+ if ((position > pressValue - 2 * pageStep) && (position < pressValue + 2 * pageStep)) {
+ repeatAction = QAbstractSlider::SliderNoAction;
+ q->setSliderPosition(pressValue);
+ return;
+ }
+ }
+ q->triggerAction(repeatAction);
+ }
+ bool scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta);
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTSLIDER_P_H
diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp
new file mode 100644
index 0000000000..4372ae3341
--- /dev/null
+++ b/src/widgets/widgets/qabstractspinbox.cpp
@@ -0,0 +1,2122 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qplatformdefs.h>
+#include <private/qabstractspinbox_p.h>
+#include <private/qdatetime_p.h>
+#include <private/qlineedit_p.h>
+#include <qabstractspinbox.h>
+
+#ifndef QT_NO_SPINBOX
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdatetime.h>
+#include <qdatetimeedit.h>
+#include <qevent.h>
+#include <qmenu.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qstylepainter.h>
+#include <qdebug.h>
+#ifndef QT_NO_ACCESSIBILITY
+# include <qaccessible.h>
+#endif
+
+#if defined(Q_WS_X11)
+#include <limits.h>
+#endif
+
+#if defined(Q_OS_SYMBIAN)
+#include <w32std.h>
+#include <private/qt_s60_p.h>
+#endif
+
+//#define QABSTRACTSPINBOX_QSBDEBUG
+#ifdef QABSTRACTSPINBOX_QSBDEBUG
+# define QASBDEBUG qDebug
+#else
+# define QASBDEBUG if (false) qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractSpinBox
+ \brief The QAbstractSpinBox class provides a spinbox and a line edit to
+ display values.
+
+ \ingroup abstractwidgets
+
+ The class is designed as a common super class for widgets like
+ QSpinBox, QDoubleSpinBox and QDateTimeEdit
+
+ Here are the main properties of the class:
+
+ \list 1
+
+ \i \l text: The text that is displayed in the QAbstractSpinBox.
+
+ \i \l alignment: The alignment of the text in the QAbstractSpinBox.
+
+ \i \l wrapping: Whether the QAbstractSpinBox wraps from the
+ minimum value to the maximum value and vica versa.
+
+ \endlist
+
+ QAbstractSpinBox provides a virtual stepBy() function that is
+ called whenever the user triggers a step. This function takes an
+ integer value to signify how many steps were taken. E.g. Pressing
+ Qt::Key_Down will trigger a call to stepBy(-1).
+
+ QAbstractSpinBox also provide a virtual function stepEnabled() to
+ determine whether stepping up/down is allowed at any point. This
+ function returns a bitset of StepEnabled.
+
+ \sa QAbstractSlider, QSpinBox, QDoubleSpinBox, QDateTimeEdit,
+ {Spin Boxes Example}
+*/
+
+/*!
+ \enum QAbstractSpinBox::StepEnabledFlag
+
+ \value StepNone
+ \value StepUpEnabled
+ \value StepDownEnabled
+*/
+
+/*!
+ \fn void QAbstractSpinBox::editingFinished()
+
+ This signal is emitted editing is finished. This happens when the
+ spinbox loses focus and when enter is pressed.
+*/
+
+/*!
+ Constructs an abstract spinbox with the given \a parent with default
+ \l wrapping, and \l alignment properties.
+*/
+
+QAbstractSpinBox::QAbstractSpinBox(QWidget *parent)
+ : QWidget(*new QAbstractSpinBoxPrivate, parent, 0)
+{
+ Q_D(QAbstractSpinBox);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+QAbstractSpinBox::QAbstractSpinBox(QAbstractSpinBoxPrivate &dd, QWidget *parent)
+ : QWidget(dd, parent, 0)
+{
+ Q_D(QAbstractSpinBox);
+ d->init();
+}
+
+/*!
+ Called when the QAbstractSpinBox is destroyed.
+*/
+
+QAbstractSpinBox::~QAbstractSpinBox()
+{
+}
+
+/*!
+ \enum QAbstractSpinBox::ButtonSymbols
+
+ This enum type describes the symbols that can be displayed on the buttons
+ in a spin box.
+
+ \inlineimage qspinbox-updown.png
+ \inlineimage qspinbox-plusminus.png
+
+ \value UpDownArrows Little arrows in the classic style.
+ \value PlusMinus \bold{+} and \bold{-} symbols.
+ \value NoButtons Don't display buttons.
+
+ \sa QAbstractSpinBox::buttonSymbols
+*/
+
+/*!
+ \property QAbstractSpinBox::buttonSymbols
+
+ \brief the current button symbol mode
+
+ The possible values can be either \c UpDownArrows or \c PlusMinus.
+ The default is \c UpDownArrows.
+
+ Note that some styles might render PlusMinus and UpDownArrows
+ identically.
+
+ \sa ButtonSymbols
+*/
+
+QAbstractSpinBox::ButtonSymbols QAbstractSpinBox::buttonSymbols() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->buttonSymbols;
+}
+
+void QAbstractSpinBox::setButtonSymbols(ButtonSymbols buttonSymbols)
+{
+ Q_D(QAbstractSpinBox);
+ if (d->buttonSymbols != buttonSymbols) {
+ d->buttonSymbols = buttonSymbols;
+ d->updateEditFieldGeometry();
+ update();
+ }
+}
+
+/*!
+ \property QAbstractSpinBox::text
+
+ \brief the spin box's text, including any prefix and suffix
+
+ There is no default text.
+*/
+
+QString QAbstractSpinBox::text() const
+{
+ return lineEdit()->displayText();
+}
+
+
+/*!
+ \property QAbstractSpinBox::specialValueText
+ \brief the special-value text
+
+ If set, the spin box will display this text instead of a numeric
+ value whenever the current value is equal to minimum(). Typical use
+ is to indicate that this choice has a special (default) meaning.
+
+ For example, if your spin box allows the user to choose a scale factor
+ (or zoom level) for displaying an image, and your application is able
+ to automatically choose one that will enable the image to fit completely
+ within the display window, you can set up the spin box like this:
+
+ \snippet examples/widgets/spinboxes/window.cpp 3
+
+ The user will then be able to choose a scale from 1% to 1000%
+ or select "Auto" to leave it up to the application to choose. Your code
+ must then interpret the spin box value of 0 as a request from the user
+ to scale the image to fit inside the window.
+
+ All values are displayed with the prefix and suffix (if set), \e
+ except for the special value, which only shows the special value
+ text. This special text is passed in the QSpinBox::valueChanged()
+ signal that passes a QString.
+
+ To turn off the special-value text display, call this function
+ with an empty string. The default is no special-value text, i.e.
+ the numeric value is shown as usual.
+
+ If no special-value text is set, specialValueText() returns an
+ empty string.
+*/
+
+QString QAbstractSpinBox::specialValueText() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->specialValueText;
+}
+
+void QAbstractSpinBox::setSpecialValueText(const QString &specialValueText)
+{
+ Q_D(QAbstractSpinBox);
+
+ d->specialValueText = specialValueText;
+ d->cachedSizeHint = QSize(); // minimumSizeHint doesn't care about specialValueText
+ d->clearCache();
+ d->updateEdit();
+}
+
+/*!
+ \property QAbstractSpinBox::wrapping
+
+ \brief whether the spin box is circular.
+
+ If wrapping is true stepping up from maximum() value will take you
+ to the minimum() value and vica versa. Wrapping only make sense if
+ you have minimum() and maximum() values set.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qabstractspinbox.cpp 0
+
+ \sa QSpinBox::minimum(), QSpinBox::maximum()
+*/
+
+bool QAbstractSpinBox::wrapping() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->wrapping;
+}
+
+void QAbstractSpinBox::setWrapping(bool wrapping)
+{
+ Q_D(QAbstractSpinBox);
+ d->wrapping = wrapping;
+}
+
+
+/*!
+ \property QAbstractSpinBox::readOnly
+ \brief whether the spin box is read only.
+
+ In read-only mode, the user can still copy the text to the
+ clipboard, or drag and drop the text;
+ but cannot edit it.
+
+ The QLineEdit in the QAbstractSpinBox does not show a cursor in
+ read-only mode.
+
+ \sa QLineEdit::readOnly
+*/
+
+bool QAbstractSpinBox::isReadOnly() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->readOnly;
+}
+
+void QAbstractSpinBox::setReadOnly(bool enable)
+{
+ Q_D(QAbstractSpinBox);
+ d->readOnly = enable;
+ d->edit->setReadOnly(enable);
+ update();
+}
+
+/*!
+ \property QAbstractSpinBox::keyboardTracking
+ \brief whether keyboard tracking is enabled for the spinbox.
+ \since 4.3
+
+ If keyboard tracking is enabled (the default), the spinbox
+ emits the valueChanged() signal while the new value is being
+ entered from the keyboard.
+
+ E.g. when the user enters the value 600 by typing 6, 0, and 0,
+ the spinbox emits 3 signals with the values 6, 60, and 600
+ respectively.
+
+ If keyboard tracking is disabled, the spinbox doesn't emit the
+ valueChanged() signal while typing. It emits the signal later,
+ when the return key is pressed, when keyboard focus is lost, or
+ when other spinbox functionality is used, e.g. pressing an arrow
+ key.
+*/
+
+bool QAbstractSpinBox::keyboardTracking() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->keyboardTracking;
+}
+
+void QAbstractSpinBox::setKeyboardTracking(bool enable)
+{
+ Q_D(QAbstractSpinBox);
+ d->keyboardTracking = enable;
+}
+
+/*!
+ \property QAbstractSpinBox::frame
+ \brief whether the spin box draws itself with a frame
+
+ If enabled (the default) the spin box draws itself inside a frame,
+ otherwise the spin box draws itself without any frame.
+*/
+
+bool QAbstractSpinBox::hasFrame() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->frame;
+}
+
+
+void QAbstractSpinBox::setFrame(bool enable)
+{
+ Q_D(QAbstractSpinBox);
+ d->frame = enable;
+ update();
+ d->updateEditFieldGeometry();
+}
+
+/*!
+ \property QAbstractSpinBox::accelerated
+ \brief whether the spin box will accelerate the frequency of the steps when
+ pressing the step Up/Down buttons.
+ \since 4.2
+
+ If enabled the spin box will increase/decrease the value faster
+ the longer you hold the button down.
+*/
+
+void QAbstractSpinBox::setAccelerated(bool accelerate)
+{
+ Q_D(QAbstractSpinBox);
+ d->accelerate = accelerate;
+
+}
+bool QAbstractSpinBox::isAccelerated() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->accelerate;
+}
+
+/*!
+ \enum QAbstractSpinBox::CorrectionMode
+
+ This enum type describes the mode the spinbox will use to correct
+ an \l{QValidator::}{Intermediate} value if editing finishes.
+
+ \value CorrectToPreviousValue The spinbox will revert to the last
+ valid value.
+
+ \value CorrectToNearestValue The spinbox will revert to the nearest
+ valid value.
+
+ \sa correctionMode
+*/
+
+/*!
+ \property QAbstractSpinBox::correctionMode
+ \brief the mode to correct an \l{QValidator::}{Intermediate}
+ value if editing finishes
+ \since 4.2
+
+ The default mode is QAbstractSpinBox::CorrectToPreviousValue.
+
+ \sa acceptableInput, validate(), fixup()
+*/
+void QAbstractSpinBox::setCorrectionMode(CorrectionMode correctionMode)
+{
+ Q_D(QAbstractSpinBox);
+ d->correctionMode = correctionMode;
+
+}
+QAbstractSpinBox::CorrectionMode QAbstractSpinBox::correctionMode() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->correctionMode;
+}
+
+
+/*!
+ \property QAbstractSpinBox::acceptableInput
+ \brief whether the input satisfies the current validation
+ \since 4.2
+
+ \sa validate(), fixup(), correctionMode
+*/
+
+bool QAbstractSpinBox::hasAcceptableInput() const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->edit->hasAcceptableInput();
+}
+
+/*!
+ \property QAbstractSpinBox::alignment
+ \brief the alignment of the spin box
+
+ Possible Values are Qt::AlignLeft, Qt::AlignRight, and Qt::AlignHCenter.
+
+ By default, the alignment is Qt::AlignLeft
+
+ Attempting to set the alignment to an illegal flag combination
+ does nothing.
+
+ \sa Qt::Alignment
+*/
+
+Qt::Alignment QAbstractSpinBox::alignment() const
+{
+ Q_D(const QAbstractSpinBox);
+
+ return (Qt::Alignment)d->edit->alignment();
+}
+
+void QAbstractSpinBox::setAlignment(Qt::Alignment flag)
+{
+ Q_D(QAbstractSpinBox);
+
+ d->edit->setAlignment(flag);
+}
+
+/*!
+ Selects all the text in the spinbox except the prefix and suffix.
+*/
+
+void QAbstractSpinBox::selectAll()
+{
+ Q_D(QAbstractSpinBox);
+
+
+ if (!d->specialValue()) {
+ const int tmp = d->edit->displayText().size() - d->suffix.size();
+ d->edit->setSelection(tmp, -(tmp - d->prefix.size()));
+ } else {
+ d->edit->selectAll();
+ }
+}
+
+/*!
+ Clears the lineedit of all text but prefix and suffix.
+*/
+
+void QAbstractSpinBox::clear()
+{
+ Q_D(QAbstractSpinBox);
+
+ d->edit->setText(d->prefix + d->suffix);
+ d->edit->setCursorPosition(d->prefix.size());
+ d->cleared = true;
+}
+
+/*!
+ Virtual function that determines whether stepping up and down is
+ legal at any given time.
+
+ The up arrow will be painted as disabled unless (stepEnabled() &
+ StepUpEnabled) != 0.
+
+ The default implementation will return (StepUpEnabled|
+ StepDownEnabled) if wrapping is turned on. Else it will return
+ StepDownEnabled if value is > minimum() or'ed with StepUpEnabled if
+ value < maximum().
+
+ If you subclass QAbstractSpinBox you will need to reimplement this function.
+
+ \sa QSpinBox::minimum(), QSpinBox::maximum(), wrapping()
+*/
+
+
+QAbstractSpinBox::StepEnabled QAbstractSpinBox::stepEnabled() const
+{
+ Q_D(const QAbstractSpinBox);
+ if (d->readOnly || d->type == QVariant::Invalid)
+ return StepNone;
+ if (d->wrapping)
+ return StepEnabled(StepUpEnabled | StepDownEnabled);
+ StepEnabled ret = StepNone;
+ if (d->variantCompare(d->value, d->maximum) < 0) {
+ ret |= StepUpEnabled;
+ }
+ if (d->variantCompare(d->value, d->minimum) > 0) {
+ ret |= StepDownEnabled;
+ }
+ return ret;
+}
+
+/*!
+ This virtual function is called by the QAbstractSpinBox to
+ determine whether \a input is valid. The \a pos parameter indicates
+ the position in the string. Reimplemented in the various
+ subclasses.
+*/
+
+QValidator::State QAbstractSpinBox::validate(QString & /* input */, int & /* pos */) const
+{
+ return QValidator::Acceptable;
+}
+
+/*!
+ This virtual function is called by the QAbstractSpinBox if the
+ \a input is not validated to QValidator::Acceptable when Return is
+ pressed or interpretText() is called. It will try to change the
+ text so it is valid. Reimplemented in the various subclasses.
+*/
+
+void QAbstractSpinBox::fixup(QString & /* input */) const
+{
+}
+
+/*!
+ Steps up by one linestep
+ Calling this slot is analogous to calling stepBy(1);
+ \sa stepBy(), stepDown()
+*/
+
+void QAbstractSpinBox::stepUp()
+{
+ stepBy(1);
+}
+
+/*!
+ Steps down by one linestep
+ Calling this slot is analogous to calling stepBy(-1);
+ \sa stepBy(), stepUp()
+*/
+
+void QAbstractSpinBox::stepDown()
+{
+ stepBy(-1);
+}
+/*!
+ Virtual function that is called whenever the user triggers a step.
+ The \a steps parameter indicates how many steps were taken, e.g.
+ Pressing Qt::Key_Down will trigger a call to stepBy(-1),
+ whereas pressing Qt::Key_Prior will trigger a call to
+ stepBy(10).
+
+ If you subclass QAbstractSpinBox you must reimplement this
+ function. Note that this function is called even if the resulting
+ value will be outside the bounds of minimum and maximum. It's this
+ function's job to handle these situations.
+*/
+
+void QAbstractSpinBox::stepBy(int steps)
+{
+ Q_D(QAbstractSpinBox);
+
+ const QVariant old = d->value;
+ QString tmp = d->edit->displayText();
+ int cursorPos = d->edit->cursorPosition();
+ bool dontstep = false;
+ EmitPolicy e = EmitIfChanged;
+ if (d->pendingEmit) {
+ dontstep = validate(tmp, cursorPos) != QValidator::Acceptable;
+ d->cleared = false;
+ d->interpret(NeverEmit);
+ if (d->value != old)
+ e = AlwaysEmit;
+ }
+ if (!dontstep) {
+ d->setValue(d->bound(d->value + (d->singleStep * steps), old, steps), e);
+ } else if (e == AlwaysEmit) {
+ d->emitSignals(e, old);
+ }
+ selectAll();
+}
+
+/*!
+ This function returns a pointer to the line edit of the spin box.
+*/
+
+QLineEdit *QAbstractSpinBox::lineEdit() const
+{
+ Q_D(const QAbstractSpinBox);
+
+ return d->edit;
+}
+
+
+/*!
+ \fn void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
+
+ Sets the line edit of the spinbox to be \a lineEdit instead of the
+ current line edit widget. \a lineEdit can not be 0.
+
+ QAbstractSpinBox takes ownership of the new lineEdit
+
+ If QLineEdit::validator() for the \a lineEdit returns 0, the internal
+ validator of the spinbox will be set on the line edit.
+*/
+
+void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
+{
+ Q_D(QAbstractSpinBox);
+
+ if (!lineEdit) {
+ Q_ASSERT(lineEdit);
+ return;
+ }
+ delete d->edit;
+ d->edit = lineEdit;
+ if (!d->edit->validator())
+ d->edit->setValidator(d->validator);
+
+ if (d->edit->parent() != this)
+ d->edit->setParent(this);
+
+ d->edit->setFrame(false);
+ d->edit->setFocusProxy(this);
+ d->edit->setAcceptDrops(false);
+
+ if (d->type != QVariant::Invalid) {
+ connect(d->edit, SIGNAL(textChanged(QString)),
+ this, SLOT(_q_editorTextChanged(QString)));
+ connect(d->edit, SIGNAL(cursorPositionChanged(int,int)),
+ this, SLOT(_q_editorCursorPositionChanged(int,int)));
+ }
+ d->updateEditFieldGeometry();
+ d->edit->setContextMenuPolicy(Qt::NoContextMenu);
+
+ if (isVisible())
+ d->edit->show();
+ if (isVisible())
+ d->updateEdit();
+}
+
+
+/*!
+ This function interprets the text of the spin box. If the value
+ has changed since last interpretation it will emit signals.
+*/
+
+void QAbstractSpinBox::interpretText()
+{
+ Q_D(QAbstractSpinBox);
+ d->interpret(EmitIfChanged);
+}
+
+/*
+ Reimplemented in 4.6, so be careful.
+ */
+/*!
+ \reimp
+*/
+QVariant QAbstractSpinBox::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QAbstractSpinBox);
+ return d->edit->inputMethodQuery(query);
+}
+
+/*!
+ \reimp
+*/
+
+bool QAbstractSpinBox::event(QEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+ switch (event->type()) {
+ case QEvent::FontChange:
+ case QEvent::StyleChange:
+ d->cachedSizeHint = d->cachedMinimumSizeHint = QSize();
+ break;
+ case QEvent::ApplicationLayoutDirectionChange:
+ case QEvent::LayoutDirectionChange:
+ d->updateEditFieldGeometry();
+ break;
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d->updateHoverControl(he->pos());
+ break;
+ case QEvent::ShortcutOverride:
+ if (d->edit->event(event))
+ return true;
+ break;
+#ifdef QT_KEYPAD_NAVIGATION
+ case QEvent::EnterEditFocus:
+ case QEvent::LeaveEditFocus:
+ if (QApplication::keypadNavigationEnabled()) {
+ const bool b = d->edit->event(event);
+ d->edit->setSelection(d->edit->displayText().size() - d->suffix.size(),0);
+ if (event->type() == QEvent::LeaveEditFocus)
+ emit editingFinished();
+ if (b)
+ return true;
+ }
+ break;
+#endif
+ case QEvent::InputMethod:
+ return d->edit->event(event);
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::showEvent(QShowEvent *)
+{
+ Q_D(QAbstractSpinBox);
+ d->reset();
+
+ if (d->ignoreUpdateEdit) {
+ d->ignoreUpdateEdit = false;
+ } else {
+ d->updateEdit();
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::changeEvent(QEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ switch (event->type()) {
+ case QEvent::StyleChange:
+ d->spinClickTimerInterval = style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatRate, 0, this);
+ d->spinClickThresholdTimerInterval =
+ style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, 0, this);
+ d->reset();
+ d->updateEditFieldGeometry();
+ break;
+ case QEvent::EnabledChange:
+ if (!isEnabled()) {
+ d->reset();
+ }
+ break;
+ case QEvent::ActivationChange:
+ if (!isActiveWindow()){
+ d->reset();
+ if (d->pendingEmit) // pendingEmit can be true even if it hasn't changed.
+ d->interpret(EmitIfChanged); // E.g. 10 to 10.0
+ }
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+ QWidget::resizeEvent(event);
+
+ d->updateEditFieldGeometry();
+ update();
+}
+
+/*!
+ \reimp
+*/
+
+QSize QAbstractSpinBox::sizeHint() const
+{
+ Q_D(const QAbstractSpinBox);
+ if (d->cachedSizeHint.isEmpty()) {
+ ensurePolished();
+
+ const QFontMetrics fm(fontMetrics());
+ int h = d->edit->sizeHint().height();
+ int w = 0;
+ QString s;
+ s = d->prefix + d->textFromValue(d->minimum) + d->suffix + QLatin1Char(' ');
+ s.truncate(18);
+ w = qMax(w, fm.width(s));
+ s = d->prefix + d->textFromValue(d->maximum) + d->suffix + QLatin1Char(' ');
+ s.truncate(18);
+ w = qMax(w, fm.width(s));
+ if (d->specialValueText.size()) {
+ s = d->specialValueText;
+ w = qMax(w, fm.width(s));
+ }
+ w += 2; // cursor blinking space
+
+ QStyleOptionSpinBox opt;
+ initStyleOption(&opt);
+ QSize hint(w, h);
+ QSize extra(35, 6);
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ // get closer to final result by repeating the calculation
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ hint += extra;
+
+ opt.rect = rect();
+ d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
+ .expandedTo(QApplication::globalStrut());
+ }
+ return d->cachedSizeHint;
+}
+
+/*!
+ \reimp
+*/
+
+QSize QAbstractSpinBox::minimumSizeHint() const
+{
+ Q_D(const QAbstractSpinBox);
+ if (d->cachedMinimumSizeHint.isEmpty()) {
+ ensurePolished();
+
+ const QFontMetrics fm(fontMetrics());
+ int h = d->edit->minimumSizeHint().height();
+ int w = fm.width(QLatin1String("1000"));
+ w += 2; // cursor blinking space
+
+ QStyleOptionSpinBox opt;
+ initStyleOption(&opt);
+ QSize hint(w, h);
+ QSize extra(35, 6);
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ // get closer to final result by repeating the calculation
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ hint += extra;
+
+ opt.rect = rect();
+
+ d->cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
+ .expandedTo(QApplication::globalStrut());
+ }
+ return d->cachedMinimumSizeHint;
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::paintEvent(QPaintEvent *)
+{
+ QStyleOptionSpinBox opt;
+ initStyleOption(&opt);
+ QStylePainter p(this);
+ p.drawComplexControl(QStyle::CC_SpinBox, opt);
+}
+
+/*!
+ \reimp
+
+ This function handles keyboard input.
+
+ The following keys are handled specifically:
+ \table
+ \row \i Enter/Return
+ \i This will reinterpret the text and emit a signal even if the value has not changed
+ since last time a signal was emitted.
+ \row \i Up
+ \i This will invoke stepBy(1)
+ \row \i Down
+ \i This will invoke stepBy(-1)
+ \row \i Page up
+ \i This will invoke stepBy(10)
+ \row \i Page down
+ \i This will invoke stepBy(-10)
+ \endtable
+*/
+
+
+void QAbstractSpinBox::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ if (!event->text().isEmpty() && d->edit->cursorPosition() < d->prefix.size())
+ d->edit->setCursorPosition(d->prefix.size());
+
+ int steps = 1;
+ bool isPgUpOrDown = false;
+ switch (event->key()) {
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ steps *= 10;
+ isPgUpOrDown = true;
+ case Qt::Key_Up:
+ case Qt::Key_Down: {
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled()) {
+ // Reserve up/down for nav - use left/right for edit.
+ if (!hasEditFocus() && (event->key() == Qt::Key_Up
+ || event->key() == Qt::Key_Down)) {
+ event->ignore();
+ return;
+ }
+ }
+#endif
+ event->accept();
+ const bool up = (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_Up);
+ if (!(stepEnabled() & (up ? StepUpEnabled : StepDownEnabled)))
+ return;
+ if (!up)
+ steps *= -1;
+ if (style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) {
+ d->buttonState = (Keyboard | (up ? Up : Down));
+ }
+ if (d->spinClickTimerId == -1)
+ stepBy(steps);
+ if(event->isAutoRepeat() && !isPgUpOrDown) {
+ if(d->spinClickThresholdTimerId == -1 && d->spinClickTimerId == -1) {
+ d->updateState(up, true);
+ }
+ }
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
+#endif
+ return;
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ event->ignore();
+ return;
+ }
+ break;
+ case Qt::Key_Back:
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ event->ignore();
+ return;
+ }
+ break;
+#endif
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ d->edit->d_func()->control->clearUndo();
+ d->interpret(d->keyboardTracking ? AlwaysEmit : EmitIfChanged);
+ selectAll();
+ event->ignore();
+ emit editingFinished();
+ return;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ // Toggles between left/right moving cursor and inc/dec.
+ setEditFocus(!hasEditFocus());
+ }
+ return;
+#endif
+
+#ifdef Q_WS_X11 // only X11
+ case Qt::Key_U:
+ if (event->modifiers() & Qt::ControlModifier) {
+ event->accept();
+ if (!isReadOnly())
+ clear();
+ return;
+ }
+ break;
+#endif
+
+ case Qt::Key_End:
+ case Qt::Key_Home:
+ if (event->modifiers() & Qt::ShiftModifier) {
+ int currentPos = d->edit->cursorPosition();
+ const QString text = d->edit->displayText();
+ if (event->key() == Qt::Key_End) {
+ if ((currentPos == 0 && !d->prefix.isEmpty()) || text.size() - d->suffix.size() <= currentPos) {
+ break; // let lineedit handle this
+ } else {
+ d->edit->setSelection(currentPos, text.size() - d->suffix.size() - currentPos);
+ }
+ } else {
+ if ((currentPos == text.size() && !d->suffix.isEmpty()) || currentPos <= d->prefix.size()) {
+ break; // let lineedit handle this
+ } else {
+ d->edit->setSelection(currentPos, d->prefix.size() - currentPos);
+ }
+ }
+ event->accept();
+ return;
+ }
+ break;
+
+ default:
+#ifndef QT_NO_SHORTCUT
+ if (event == QKeySequence::SelectAll) {
+ selectAll();
+ event->accept();
+ return;
+ }
+#endif
+ break;
+ }
+
+ d->edit->event(event);
+ if (!isVisible())
+ d->ignoreUpdateEdit = true;
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ if (d->buttonState & Keyboard && !event->isAutoRepeat()) {
+ d->reset();
+ } else {
+ d->edit->event(event);
+ }
+}
+
+/*!
+ \reimp
+*/
+
+#ifndef QT_NO_WHEELEVENT
+void QAbstractSpinBox::wheelEvent(QWheelEvent *event)
+{
+ const int steps = (event->delta() > 0 ? 1 : -1);
+ if (stepEnabled() & (steps > 0 ? StepUpEnabled : StepDownEnabled))
+ stepBy(event->modifiers() & Qt::ControlModifier ? steps * 10 : steps);
+ event->accept();
+}
+#endif
+
+
+/*!
+ \reimp
+*/
+void QAbstractSpinBox::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ d->edit->event(event);
+ if (event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason) {
+ selectAll();
+ }
+ QWidget::focusInEvent(event);
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ if (d->pendingEmit)
+ d->interpret(EmitIfChanged);
+
+ d->reset();
+ d->edit->event(event);
+ d->updateEdit();
+ QWidget::focusOutEvent(event);
+
+#ifdef QT_KEYPAD_NAVIGATION
+ // editingFinished() is already emitted on LeaveEditFocus
+ if (!QApplication::keypadNavigationEnabled())
+#endif
+ emit editingFinished();
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::closeEvent(QCloseEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ d->reset();
+ if (d->pendingEmit)
+ d->interpret(EmitIfChanged);
+ QWidget::closeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::hideEvent(QHideEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+ d->reset();
+ if (d->pendingEmit)
+ d->interpret(EmitIfChanged);
+ QWidget::hideEvent(event);
+}
+
+
+/*!
+ \internal
+
+ Used when acceleration is turned on. We need to get the
+ keyboard auto repeat rate from OS. This value is used as
+ argument when starting acceleration related timers.
+
+ Every platform should, either, use native calls to obtain
+ the value or hard code some reasonable rate.
+
+ Remember that time value should be given in msecs.
+*/
+static int getKeyboardAutoRepeatRate() {
+ int ret = 30;
+#if defined(Q_OS_SYMBIAN)
+ TTimeIntervalMicroSeconds32 initialTime;
+ TTimeIntervalMicroSeconds32 time;
+ S60->wsSession().GetKeyboardRepeatRate(initialTime, time);
+ ret = time.Int() / 1000; // msecs
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ DWORD time;
+ if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0) != FALSE)
+ ret = static_cast<int>(1000 / static_cast<int>(time)); // msecs
+#endif
+ return ret; // msecs
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::timerEvent(QTimerEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ bool doStep = false;
+ if (event->timerId() == d->spinClickThresholdTimerId) {
+ killTimer(d->spinClickThresholdTimerId);
+ d->spinClickThresholdTimerId = -1;
+ d->effectiveSpinRepeatRate = d->buttonState & Keyboard
+ ? getKeyboardAutoRepeatRate()
+ : d->spinClickTimerInterval;
+ d->spinClickTimerId = startTimer(d->effectiveSpinRepeatRate);
+ doStep = true;
+ } else if (event->timerId() == d->spinClickTimerId) {
+ if (d->accelerate) {
+ d->acceleration = d->acceleration + (int)(d->effectiveSpinRepeatRate * 0.05);
+ if (d->effectiveSpinRepeatRate - d->acceleration >= 10) {
+ killTimer(d->spinClickTimerId);
+ d->spinClickTimerId = startTimer(d->effectiveSpinRepeatRate - d->acceleration);
+ }
+ }
+ doStep = true;
+ }
+
+ if (doStep) {
+ const StepEnabled st = stepEnabled();
+ if (d->buttonState & Up) {
+ if (!(st & StepUpEnabled)) {
+ d->reset();
+ } else {
+ stepBy(1);
+ }
+ } else if (d->buttonState & Down) {
+ if (!(st & StepDownEnabled)) {
+ d->reset();
+ } else {
+ stepBy(-1);
+ }
+ }
+ return;
+ }
+ QWidget::timerEvent(event);
+ return;
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::contextMenuEvent(QContextMenuEvent *event)
+{
+#ifdef QT_NO_CONTEXTMENU
+ Q_UNUSED(event);
+#else
+ Q_D(QAbstractSpinBox);
+
+ QPointer<QMenu> menu = d->edit->createStandardContextMenu();
+ if (!menu)
+ return;
+
+ d->reset();
+
+ QAction *selAll = new QAction(tr("&Select All"), menu);
+ menu->insertAction(d->edit->d_func()->selectAllAction,
+ selAll);
+ menu->removeAction(d->edit->d_func()->selectAllAction);
+ menu->addSeparator();
+ const uint se = stepEnabled();
+ QAction *up = menu->addAction(tr("&Step up"));
+ up->setEnabled(se & StepUpEnabled);
+ QAction *down = menu->addAction(tr("Step &down"));
+ down->setEnabled(se & StepDownEnabled);
+ menu->addSeparator();
+
+ const QPointer<QAbstractSpinBox> that = this;
+ const QPoint pos = (event->reason() == QContextMenuEvent::Mouse)
+ ? event->globalPos() : mapToGlobal(QPoint(event->pos().x(), 0)) + QPoint(width() / 2, height() / 2);
+ const QAction *action = menu->exec(pos);
+ delete static_cast<QMenu *>(menu);
+ if (that && action) {
+ if (action == up) {
+ stepBy(1);
+ } else if (action == down) {
+ stepBy(-1);
+ } else if (action == selAll) {
+ selectAll();
+ }
+ }
+ event->accept();
+#endif // QT_NO_CONTEXTMENU
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ d->updateHoverControl(event->pos());
+
+ // If we have a timer ID, update the state
+ if (d->spinClickTimerId != -1 && d->buttonSymbols != NoButtons) {
+ const StepEnabled se = stepEnabled();
+ if ((se & StepUpEnabled) && d->hoverControl == QStyle::SC_SpinBoxUp)
+ d->updateState(true);
+ else if ((se & StepDownEnabled) && d->hoverControl == QStyle::SC_SpinBoxDown)
+ d->updateState(false);
+ else
+ d->reset();
+ event->accept();
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QAbstractSpinBox::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ if (event->button() != Qt::LeftButton || d->buttonState != None) {
+ return;
+ }
+
+ d->updateHoverControl(event->pos());
+ event->accept();
+
+ const StepEnabled se = (d->buttonSymbols == NoButtons) ? StepEnabled(StepNone) : stepEnabled();
+ if ((se & StepUpEnabled) && d->hoverControl == QStyle::SC_SpinBoxUp) {
+ d->updateState(true);
+ } else if ((se & StepDownEnabled) && d->hoverControl == QStyle::SC_SpinBoxDown) {
+ d->updateState(false);
+ } else {
+ event->ignore();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QAbstractSpinBox::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QAbstractSpinBox);
+
+ if ((d->buttonState & Mouse) != 0)
+ d->reset();
+ event->accept();
+}
+
+// --- QAbstractSpinBoxPrivate ---
+
+/*!
+ \internal
+ Constructs a QAbstractSpinBoxPrivate object
+*/
+
+QAbstractSpinBoxPrivate::QAbstractSpinBoxPrivate()
+ : edit(0), type(QVariant::Invalid), spinClickTimerId(-1),
+ spinClickTimerInterval(100), spinClickThresholdTimerId(-1), spinClickThresholdTimerInterval(-1),
+ effectiveSpinRepeatRate(1), buttonState(None), cachedText(QLatin1String("\x01")),
+ cachedState(QValidator::Invalid), pendingEmit(false), readOnly(false), wrapping(false),
+ ignoreCursorPositionChanged(false), frame(true), accelerate(false), keyboardTracking(true),
+ cleared(false), ignoreUpdateEdit(false), correctionMode(QAbstractSpinBox::CorrectToPreviousValue),
+ acceleration(0), hoverControl(QStyle::SC_None), buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0)
+{
+}
+
+/*
+ \internal
+ Called when the QAbstractSpinBoxPrivate is destroyed
+*/
+QAbstractSpinBoxPrivate::~QAbstractSpinBoxPrivate()
+{
+}
+
+/*!
+ \internal
+ Updates the old and new hover control. Does nothing if the hover
+ control has not changed.
+*/
+bool QAbstractSpinBoxPrivate::updateHoverControl(const QPoint &pos)
+{
+ Q_Q(QAbstractSpinBox);
+ QRect lastHoverRect = hoverRect;
+ QStyle::SubControl lastHoverControl = hoverControl;
+ bool doesHover = q->testAttribute(Qt::WA_Hover);
+ if (lastHoverControl != newHoverControl(pos) && doesHover) {
+ q->update(lastHoverRect);
+ q->update(hoverRect);
+ return true;
+ }
+ return !doesHover;
+}
+
+/*!
+ \internal
+ Returns the hover control at \a pos.
+ This will update the hoverRect and hoverControl.
+*/
+QStyle::SubControl QAbstractSpinBoxPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QAbstractSpinBox);
+
+ QStyleOptionSpinBox opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ hoverControl = q->style()->hitTestComplexControl(QStyle::CC_SpinBox, &opt, pos, q);
+ hoverRect = q->style()->subControlRect(QStyle::CC_SpinBox, &opt, hoverControl, q);
+ return hoverControl;
+}
+
+/*!
+ \internal
+ Strips any prefix/suffix from \a text.
+*/
+
+QString QAbstractSpinBoxPrivate::stripped(const QString &t, int *pos) const
+{
+ QString text = t;
+ if (specialValueText.size() == 0 || text != specialValueText) {
+ int from = 0;
+ int size = text.size();
+ bool changed = false;
+ if (prefix.size() && text.startsWith(prefix)) {
+ from += prefix.size();
+ size -= from;
+ changed = true;
+ }
+ if (suffix.size() && text.endsWith(suffix)) {
+ size -= suffix.size();
+ changed = true;
+ }
+ if (changed)
+ text = text.mid(from, size);
+ }
+
+ const int s = text.size();
+ text = text.trimmed();
+ if (pos)
+ (*pos) -= (s - text.size());
+ return text;
+
+}
+
+void QAbstractSpinBoxPrivate::updateEditFieldGeometry()
+{
+ Q_Q(QAbstractSpinBox);
+ QStyleOptionSpinBox opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_SpinBoxEditField;
+ edit->setGeometry(q->style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, q));
+}
+/*!
+ \internal
+ Returns true if a specialValueText has been set and the current value is minimum.
+*/
+
+bool QAbstractSpinBoxPrivate::specialValue() const
+{
+ return (value == minimum && !specialValueText.isEmpty());
+}
+
+/*!
+ \internal Virtual function that emits signals when the value
+ changes. Reimplemented in the different subclasses.
+*/
+
+void QAbstractSpinBoxPrivate::emitSignals(EmitPolicy, const QVariant &)
+{
+}
+
+/*!
+ \internal
+
+ Slot connected to the line edit's textChanged(const QString &)
+ signal.
+*/
+
+void QAbstractSpinBoxPrivate::_q_editorTextChanged(const QString &t)
+{
+ Q_Q(QAbstractSpinBox);
+
+ if (keyboardTracking) {
+ QString tmp = t;
+ int pos = edit->cursorPosition();
+ QValidator::State state = q->validate(tmp, pos);
+ if (state == QValidator::Acceptable) {
+ const QVariant v = valueFromText(tmp);
+ setValue(v, EmitIfChanged, tmp != t);
+ pendingEmit = false;
+ } else {
+ pendingEmit = true;
+ }
+ } else {
+ pendingEmit = true;
+ }
+}
+
+/*!
+ \internal
+
+ Virtual slot connected to the line edit's
+ cursorPositionChanged(int, int) signal. Will move the cursor to a
+ valid position if the new one is invalid. E.g. inside the prefix.
+ Reimplemented in Q[Date|Time|DateTime]EditPrivate to account for
+ the different sections etc.
+*/
+
+void QAbstractSpinBoxPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
+{
+ if (!edit->hasSelectedText() && !ignoreCursorPositionChanged && !specialValue()) {
+ ignoreCursorPositionChanged = true;
+
+ bool allowSelection = true;
+ int pos = -1;
+ if (newpos < prefix.size() && newpos != 0) {
+ if (oldpos == 0) {
+ allowSelection = false;
+ pos = prefix.size();
+ } else {
+ pos = oldpos;
+ }
+ } else if (newpos > edit->text().size() - suffix.size()
+ && newpos != edit->text().size()) {
+ if (oldpos == edit->text().size()) {
+ pos = edit->text().size() - suffix.size();
+ allowSelection = false;
+ } else {
+ pos = edit->text().size();
+ }
+ }
+ if (pos != -1) {
+ const int selSize = edit->selectionStart() >= 0 && allowSelection
+ ? (edit->selectedText().size()
+ * (newpos < pos ? -1 : 1)) - newpos + pos
+ : 0;
+
+ const bool wasBlocked = edit->blockSignals(true);
+ if (selSize != 0) {
+ edit->setSelection(pos - selSize, selSize);
+ } else {
+ edit->setCursorPosition(pos);
+ }
+ edit->blockSignals(wasBlocked);
+ }
+ ignoreCursorPositionChanged = false;
+ }
+}
+
+/*!
+ \internal
+
+ Initialises the QAbstractSpinBoxPrivate object.
+*/
+
+void QAbstractSpinBoxPrivate::init()
+{
+ Q_Q(QAbstractSpinBox);
+
+ q->setLineEdit(new QLineEdit(q));
+ edit->setObjectName(QLatin1String("qt_spinbox_lineedit"));
+ validator = new QSpinBoxValidator(q, this);
+ edit->setValidator(validator);
+
+ QStyleOptionSpinBox opt;
+ q->initStyleOption(&opt);
+ spinClickTimerInterval = q->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatRate, &opt, q);
+ spinClickThresholdTimerInterval = q->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, &opt, q);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::SpinBox));
+ q->setAttribute(Qt::WA_InputMethodEnabled);
+
+ q->setAttribute(Qt::WA_MacShowFocusRect);
+}
+
+/*!
+ \internal
+
+ Resets the state of the spinbox. E.g. the state is set to
+ (Keyboard|Up) if Key up is currently pressed.
+*/
+
+void QAbstractSpinBoxPrivate::reset()
+{
+ Q_Q(QAbstractSpinBox);
+
+ buttonState = None;
+ if (q) {
+ if (spinClickTimerId != -1)
+ q->killTimer(spinClickTimerId);
+ if (spinClickThresholdTimerId != -1)
+ q->killTimer(spinClickThresholdTimerId);
+ spinClickTimerId = spinClickThresholdTimerId = -1;
+ acceleration = 0;
+ q->update();
+ }
+}
+
+/*!
+ \internal
+
+ Updates the state of the spinbox.
+*/
+
+void QAbstractSpinBoxPrivate::updateState(bool up, bool fromKeyboard /* = false */)
+{
+ Q_Q(QAbstractSpinBox);
+ if ((up && (buttonState & Up)) || (!up && (buttonState & Down)))
+ return;
+ reset();
+ if (q && (q->stepEnabled() & (up ? QAbstractSpinBox::StepUpEnabled
+ : QAbstractSpinBox::StepDownEnabled))) {
+ spinClickThresholdTimerId = q->startTimer(spinClickThresholdTimerInterval);
+ buttonState = (up ? Up : Down) | (fromKeyboard ? Keyboard : Mouse);
+ q->stepBy(up ? 1 : -1);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged);
+#endif
+ }
+}
+
+
+/*!
+ Initialize \a option with the values from this QSpinBox. This method
+ is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QAbstractSpinBox::initStyleOption(QStyleOptionSpinBox *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QAbstractSpinBox);
+ option->initFrom(this);
+ option->activeSubControls = QStyle::SC_None;
+ option->buttonSymbols = d->buttonSymbols;
+ option->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField;
+ if (d->buttonSymbols != QAbstractSpinBox::NoButtons) {
+ option->subControls |= QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown;
+ if (d->buttonState & Up) {
+ option->activeSubControls = QStyle::SC_SpinBoxUp;
+ } else if (d->buttonState & Down) {
+ option->activeSubControls = QStyle::SC_SpinBoxDown;
+ }
+ }
+
+ if (d->buttonState) {
+ option->state |= QStyle::State_Sunken;
+ } else {
+ option->activeSubControls = d->hoverControl;
+ }
+
+ option->stepEnabled = style()->styleHint(QStyle::SH_SpinControls_DisableOnBounds)
+ ? stepEnabled()
+ : (QAbstractSpinBox::StepDownEnabled|QAbstractSpinBox::StepUpEnabled);
+
+ option->frame = d->frame;
+}
+
+/*!
+ \internal
+
+ Bounds \a val to be within minimum and maximum. Also tries to be
+ clever about setting it at min and max depending on what it was
+ and what direction it was changed etc.
+*/
+
+QVariant QAbstractSpinBoxPrivate::bound(const QVariant &val, const QVariant &old, int steps) const
+{
+ QVariant v = val;
+ if (!wrapping || steps == 0 || old.isNull()) {
+ if (variantCompare(v, minimum) < 0) {
+ v = wrapping ? maximum : minimum;
+ }
+ if (variantCompare(v, maximum) > 0) {
+ v = wrapping ? minimum : maximum;
+ }
+ } else {
+ const bool wasMin = old == minimum;
+ const bool wasMax = old == maximum;
+ const int oldcmp = variantCompare(v, old);
+ const int maxcmp = variantCompare(v, maximum);
+ const int mincmp = variantCompare(v, minimum);
+ const bool wrapped = (oldcmp > 0 && steps < 0) || (oldcmp < 0 && steps > 0);
+ if (maxcmp > 0) {
+ v = ((wasMax && !wrapped && steps > 0) || (steps < 0 && !wasMin && wrapped))
+ ? minimum : maximum;
+ } else if (wrapped && (maxcmp > 0 || mincmp < 0)) {
+ v = ((wasMax && steps > 0) || (!wasMin && steps < 0)) ? minimum : maximum;
+ } else if (mincmp < 0) {
+ v = (!wasMax && !wasMin ? minimum : maximum);
+ }
+ }
+
+ return v;
+}
+
+/*!
+ \internal
+
+ Sets the value of the spin box to \a val. Depending on the value
+ of \a ep it will also emit signals.
+*/
+
+void QAbstractSpinBoxPrivate::setValue(const QVariant &val, EmitPolicy ep,
+ bool doUpdate)
+{
+ Q_Q(QAbstractSpinBox);
+ const QVariant old = value;
+ value = bound(val);
+ pendingEmit = false;
+ cleared = false;
+ if (doUpdate) {
+ updateEdit();
+ }
+ q->update();
+
+ if (ep == AlwaysEmit || (ep == EmitIfChanged && old != value)) {
+ emitSignals(ep, old);
+ }
+}
+
+/*!
+ \internal
+
+ Updates the line edit to reflect the current value of the spin box.
+*/
+
+void QAbstractSpinBoxPrivate::updateEdit()
+{
+ Q_Q(QAbstractSpinBox);
+ if (type == QVariant::Invalid)
+ return;
+ const QString newText = specialValue() ? specialValueText : prefix + textFromValue(value) + suffix;
+ if (newText == edit->displayText() || cleared)
+ return;
+
+ const bool empty = edit->text().isEmpty();
+ int cursor = edit->cursorPosition();
+ int selsize = edit->selectedText().size();
+ const bool sb = edit->blockSignals(true);
+ edit->setText(newText);
+
+ if (!specialValue()) {
+ cursor = qBound(prefix.size(), cursor, edit->displayText().size() - suffix.size());
+
+ if (selsize > 0) {
+ edit->setSelection(cursor, selsize);
+ } else {
+ edit->setCursorPosition(empty ? prefix.size() : cursor);
+ }
+ }
+ edit->blockSignals(sb);
+ q->update();
+}
+
+/*!
+ \internal
+
+ Convenience function to set min/max values.
+*/
+
+void QAbstractSpinBoxPrivate::setRange(const QVariant &min, const QVariant &max)
+{
+ Q_Q(QAbstractSpinBox);
+
+ clearCache();
+ minimum = min;
+ maximum = (variantCompare(min, max) < 0 ? max : min);
+ cachedSizeHint = QSize(); // minimumSizeHint doesn't care about min/max
+
+ reset();
+ if (!(bound(value) == value)) {
+ setValue(bound(value), EmitIfChanged);
+ } else if (value == minimum && !specialValueText.isEmpty()) {
+ updateEdit();
+ }
+
+ q->updateGeometry();
+}
+
+/*!
+ \internal
+
+ Convenience function to get a variant of the right type.
+*/
+
+QVariant QAbstractSpinBoxPrivate::getZeroVariant() const
+{
+ QVariant ret;
+ switch (type) {
+ case QVariant::Int: ret = QVariant((int)0); break;
+ case QVariant::Double: ret = QVariant((double)0.0); break;
+ default: break;
+ }
+ return ret;
+}
+
+/*!
+ \internal
+
+ Virtual method called that calls the public textFromValue()
+ functions in the subclasses. Needed to change signature from
+ QVariant to int/double/QDateTime etc. Used when needing to display
+ a value textually.
+
+ This method is reimeplemented in the various subclasses.
+*/
+
+QString QAbstractSpinBoxPrivate::textFromValue(const QVariant &) const
+{
+ return QString();
+}
+
+/*!
+ \internal
+
+ Virtual method called that calls the public valueFromText()
+ functions in the subclasses. Needed to change signature from
+ QVariant to int/double/QDateTime etc. Used when needing to
+ interpret a string as another type.
+
+ This method is reimeplemented in the various subclasses.
+*/
+
+QVariant QAbstractSpinBoxPrivate::valueFromText(const QString &) const
+{
+ return QVariant();
+}
+/*!
+ \internal
+
+ Interprets text and emits signals. Called when the spinbox needs
+ to interpret the text on the lineedit.
+*/
+
+void QAbstractSpinBoxPrivate::interpret(EmitPolicy ep)
+{
+ Q_Q(QAbstractSpinBox);
+ if (type == QVariant::Invalid || cleared)
+ return;
+
+ QVariant v = getZeroVariant();
+ bool doInterpret = true;
+ QString tmp = edit->displayText();
+ int pos = edit->cursorPosition();
+ const int oldpos = pos;
+
+ if (q->validate(tmp, pos) != QValidator::Acceptable) {
+ const QString copy = tmp;
+ q->fixup(tmp);
+ QASBDEBUG() << "QAbstractSpinBoxPrivate::interpret() text '"
+ << edit->displayText()
+ << "' >> '" << copy << '\''
+ << "' >> '" << tmp << '\'';
+
+ doInterpret = tmp != copy && (q->validate(tmp, pos) == QValidator::Acceptable);
+ if (!doInterpret) {
+ v = (correctionMode == QAbstractSpinBox::CorrectToNearestValue
+ ? variantBound(minimum, v, maximum) : value);
+ }
+ }
+ if (doInterpret) {
+ v = valueFromText(tmp);
+ }
+ clearCache();
+ setValue(v, ep, true);
+ if (oldpos != pos)
+ edit->setCursorPosition(pos);
+}
+
+void QAbstractSpinBoxPrivate::clearCache() const
+{
+ cachedText.clear();
+ cachedValue.clear();
+ cachedState = QValidator::Acceptable;
+}
+
+
+// --- QSpinBoxValidator ---
+
+/*!
+ \internal
+ Constructs a QSpinBoxValidator object
+*/
+
+QSpinBoxValidator::QSpinBoxValidator(QAbstractSpinBox *qp, QAbstractSpinBoxPrivate *dp)
+ : QValidator(qp), qptr(qp), dptr(dp)
+{
+ setObjectName(QLatin1String("qt_spinboxvalidator"));
+}
+
+/*!
+ \internal
+
+ Checks for specialValueText, prefix, suffix and calls
+ the virtual QAbstractSpinBox::validate function.
+*/
+
+QValidator::State QSpinBoxValidator::validate(QString &input, int &pos) const
+{
+ if (dptr->specialValueText.size() > 0 && input == dptr->specialValueText)
+ return QValidator::Acceptable;
+
+ if (!dptr->prefix.isEmpty() && !input.startsWith(dptr->prefix)) {
+ input.prepend(dptr->prefix);
+ pos += dptr->prefix.length();
+ }
+
+ if (!dptr->suffix.isEmpty() && !input.endsWith(dptr->suffix))
+ input.append(dptr->suffix);
+
+ return qptr->validate(input, pos);
+}
+/*!
+ \internal
+ Calls the virtual QAbstractSpinBox::fixup function.
+*/
+
+void QSpinBoxValidator::fixup(QString &input) const
+{
+ qptr->fixup(input);
+}
+
+// --- global ---
+
+/*!
+ \internal
+ Adds two variants together and returns the result.
+*/
+
+QVariant operator+(const QVariant &arg1, const QVariant &arg2)
+{
+ QVariant ret;
+ if (arg1.type() != arg2.type())
+ qWarning("QAbstractSpinBox: Internal error: Different types (%s vs %s) (%s:%d)",
+ arg1.typeName(), arg2.typeName(), __FILE__, __LINE__);
+ switch (arg1.type()) {
+ case QVariant::Int: ret = QVariant(arg1.toInt() + arg2.toInt()); break;
+ case QVariant::Double: ret = QVariant(arg1.toDouble() + arg2.toDouble()); break;
+ case QVariant::DateTime: {
+ QDateTime a2 = arg2.toDateTime();
+ QDateTime a1 = arg1.toDateTime().addDays(QDATETIMEEDIT_DATETIME_MIN.daysTo(a2));
+ a1.setTime(a1.time().addMSecs(QTime().msecsTo(a2.time())));
+ ret = QVariant(a1);
+ }
+ default: break;
+ }
+ return ret;
+}
+
+
+/*!
+ \internal
+ Subtracts two variants and returns the result.
+*/
+
+QVariant operator-(const QVariant &arg1, const QVariant &arg2)
+{
+ QVariant ret;
+ if (arg1.type() != arg2.type())
+ qWarning("QAbstractSpinBox: Internal error: Different types (%s vs %s) (%s:%d)",
+ arg1.typeName(), arg2.typeName(), __FILE__, __LINE__);
+ switch (arg1.type()) {
+ case QVariant::Int: ret = QVariant(arg1.toInt() - arg2.toInt()); break;
+ case QVariant::Double: ret = QVariant(arg1.toDouble() - arg2.toDouble()); break;
+ case QVariant::DateTime: {
+ QDateTime a1 = arg1.toDateTime();
+ QDateTime a2 = arg2.toDateTime();
+ int days = a2.daysTo(a1);
+ int secs = a2.secsTo(a1);
+ int msecs = qMax(0, a1.time().msec() - a2.time().msec());
+ if (days < 0 || secs < 0 || msecs < 0) {
+ ret = arg1;
+ } else {
+ QDateTime dt = a2.addDays(days).addSecs(secs);
+ if (msecs > 0)
+ dt.setTime(dt.time().addMSecs(msecs));
+ ret = QVariant(dt);
+ }
+ }
+ default: break;
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ Multiplies \a arg1 by \a multiplier and returns the result.
+*/
+
+QVariant operator*(const QVariant &arg1, double multiplier)
+{
+ QVariant ret;
+
+ switch (arg1.type()) {
+ case QVariant::Int: ret = QVariant((int)(arg1.toInt() * multiplier)); break;
+ case QVariant::Double: ret = QVariant(arg1.toDouble() * multiplier); break;
+ case QVariant::DateTime: {
+ double days = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDateTime().date()) * multiplier;
+ int daysInt = (int)days;
+ days -= daysInt;
+ long msecs = (long)((QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) * multiplier)
+ + (days * (24 * 3600 * 1000)));
+ ret = QDateTime(QDate().addDays(int(days)), QTime().addMSecs(msecs));
+ break;
+ }
+ default: ret = arg1; break;
+ }
+
+ return ret;
+}
+
+
+
+double operator/(const QVariant &arg1, const QVariant &arg2)
+{
+ double a1 = 0;
+ double a2 = 0;
+
+ switch (arg1.type()) {
+ case QVariant::Int:
+ a1 = (double)arg1.toInt();
+ a2 = (double)arg2.toInt();
+ break;
+ case QVariant::Double:
+ a1 = arg1.toDouble();
+ a2 = arg2.toDouble();
+ break;
+ case QVariant::DateTime:
+ a1 = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDate());
+ a2 = QDATETIMEEDIT_DATE_MIN.daysTo(arg2.toDate());
+ a1 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) / (long)(3600 * 24 * 1000);
+ a2 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg2.toDateTime().time()) / (long)(3600 * 24 * 1000);
+ default: break;
+ }
+
+ return (a1 != 0 && a2 != 0) ? (a1 / a2) : 0.0;
+}
+
+int QAbstractSpinBoxPrivate::variantCompare(const QVariant &arg1, const QVariant &arg2)
+{
+ switch (arg2.type()) {
+ case QVariant::Date:
+ Q_ASSERT_X(arg1.type() == QVariant::Date, "QAbstractSpinBoxPrivate::variantCompare",
+ qPrintable(QString::fromAscii("Internal error 1 (%1)").
+ arg(QString::fromAscii(arg1.typeName()))));
+ if (arg1.toDate() == arg2.toDate()) {
+ return 0;
+ } else if (arg1.toDate() < arg2.toDate()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ case QVariant::Time:
+ Q_ASSERT_X(arg1.type() == QVariant::Time, "QAbstractSpinBoxPrivate::variantCompare",
+ qPrintable(QString::fromAscii("Internal error 2 (%1)").
+ arg(QString::fromAscii(arg1.typeName()))));
+ if (arg1.toTime() == arg2.toTime()) {
+ return 0;
+ } else if (arg1.toTime() < arg2.toTime()) {
+ return -1;
+ } else {
+ return 1;
+ }
+
+
+ case QVariant::DateTime:
+ if (arg1.toDateTime() == arg2.toDateTime()) {
+ return 0;
+ } else if (arg1.toDateTime() < arg2.toDateTime()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ case QVariant::Int:
+ if (arg1.toInt() == arg2.toInt()) {
+ return 0;
+ } else if (arg1.toInt() < arg2.toInt()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ case QVariant::Double:
+ if (arg1.toDouble() == arg2.toDouble()) {
+ return 0;
+ } else if (arg1.toDouble() < arg2.toDouble()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ case QVariant::Invalid:
+ if (arg2.type() == QVariant::Invalid)
+ return 0;
+ default:
+ Q_ASSERT_X(0, "QAbstractSpinBoxPrivate::variantCompare",
+ qPrintable(QString::fromAscii("Internal error 3 (%1 %2)").
+ arg(QString::fromAscii(arg1.typeName())).
+ arg(QString::fromAscii(arg2.typeName()))));
+ }
+ return -2;
+}
+
+QVariant QAbstractSpinBoxPrivate::variantBound(const QVariant &min,
+ const QVariant &value,
+ const QVariant &max)
+{
+ Q_ASSERT(variantCompare(min, max) <= 0);
+ if (variantCompare(min, value) < 0) {
+ const int compMax = variantCompare(value, max);
+ return (compMax < 0 ? value : max);
+ } else {
+ return min;
+ }
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractspinbox.cpp"
+
+#endif // QT_NO_SPINBOX
diff --git a/src/widgets/widgets/qabstractspinbox.h b/src/widgets/widgets/qabstractspinbox.h
new file mode 100644
index 0000000000..fb3ae2f5ee
--- /dev/null
+++ b/src/widgets/widgets/qabstractspinbox.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSPINBOX_H
+#define QABSTRACTSPINBOX_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtGui/qvalidator.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SPINBOX
+
+class QLineEdit;
+
+class QAbstractSpinBoxPrivate;
+class QStyleOptionSpinBox;
+
+class Q_WIDGETS_EXPORT QAbstractSpinBox : public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(ButtonSymbols)
+ Q_ENUMS(CorrectionMode)
+ Q_PROPERTY(bool wrapping READ wrapping WRITE setWrapping)
+ Q_PROPERTY(bool frame READ hasFrame WRITE setFrame)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(ButtonSymbols buttonSymbols READ buttonSymbols WRITE setButtonSymbols)
+ Q_PROPERTY(QString specialValueText READ specialValueText WRITE setSpecialValueText)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(bool accelerated READ isAccelerated WRITE setAccelerated)
+ Q_PROPERTY(CorrectionMode correctionMode READ correctionMode WRITE setCorrectionMode)
+ Q_PROPERTY(bool acceptableInput READ hasAcceptableInput)
+ Q_PROPERTY(bool keyboardTracking READ keyboardTracking WRITE setKeyboardTracking)
+public:
+ explicit QAbstractSpinBox(QWidget *parent = 0);
+ ~QAbstractSpinBox();
+
+ enum StepEnabledFlag { StepNone = 0x00, StepUpEnabled = 0x01,
+ StepDownEnabled = 0x02 };
+ Q_DECLARE_FLAGS(StepEnabled, StepEnabledFlag)
+
+ enum ButtonSymbols { UpDownArrows, PlusMinus, NoButtons };
+
+ ButtonSymbols buttonSymbols() const;
+ void setButtonSymbols(ButtonSymbols bs);
+
+ enum CorrectionMode { CorrectToPreviousValue, CorrectToNearestValue };
+
+ void setCorrectionMode(CorrectionMode cm);
+ CorrectionMode correctionMode() const;
+
+ bool hasAcceptableInput() const;
+ QString text() const;
+
+ QString specialValueText() const;
+ void setSpecialValueText(const QString &txt);
+
+ bool wrapping() const;
+ void setWrapping(bool w);
+
+ void setReadOnly(bool r);
+ bool isReadOnly() const;
+
+ void setKeyboardTracking(bool kt);
+ bool keyboardTracking() const;
+
+ void setAlignment(Qt::Alignment flag);
+ Qt::Alignment alignment() const;
+
+ void setFrame(bool);
+ bool hasFrame() const;
+
+ void setAccelerated(bool on);
+ bool isAccelerated() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ void interpretText();
+ bool event(QEvent *event);
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery) const;
+
+ virtual QValidator::State validate(QString &input, int &pos) const;
+ virtual void fixup(QString &input) const;
+
+ virtual void stepBy(int steps);
+public Q_SLOTS:
+ void stepUp();
+ void stepDown();
+ void selectAll();
+ virtual void clear();
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *event);
+#endif
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void changeEvent(QEvent *event);
+ void closeEvent(QCloseEvent *event);
+ void hideEvent(QHideEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void timerEvent(QTimerEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void showEvent(QShowEvent *event);
+ void initStyleOption(QStyleOptionSpinBox *option) const;
+
+ QLineEdit *lineEdit() const;
+ void setLineEdit(QLineEdit *edit);
+
+ virtual StepEnabled stepEnabled() const;
+Q_SIGNALS:
+ void editingFinished();
+protected:
+ QAbstractSpinBox(QAbstractSpinBoxPrivate &dd, QWidget *parent = 0);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_editorTextChanged(const QString &))
+ Q_PRIVATE_SLOT(d_func(), void _q_editorCursorPositionChanged(int, int))
+
+ Q_DECLARE_PRIVATE(QAbstractSpinBox)
+ Q_DISABLE_COPY(QAbstractSpinBox)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSpinBox::StepEnabled)
+
+#endif // QT_NO_SPINBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTSPINBOX_H
diff --git a/src/widgets/widgets/qabstractspinbox_p.h b/src/widgets/widgets/qabstractspinbox_p.h
new file mode 100644
index 0000000000..33d4e32875
--- /dev/null
+++ b/src/widgets/widgets/qabstractspinbox_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSPINBOX_P_H
+#define QABSTRACTSPINBOX_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 "QtWidgets/qabstractspinbox.h"
+
+#ifndef QT_NO_SPINBOX
+
+#include "QtWidgets/qlineedit.h"
+#include "QtWidgets/qstyleoption.h"
+#include "QtGui/qvalidator.h"
+#include "QtCore/qdatetime.h"
+#include "QtCore/qvariant.h"
+#include "private/qwidget_p.h"
+#include "private/qdatetime_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QVariant operator+(const QVariant &arg1, const QVariant &arg2);
+QVariant operator-(const QVariant &arg1, const QVariant &arg2);
+QVariant operator*(const QVariant &arg1, double multiplier);
+double operator/(const QVariant &arg1, const QVariant &arg2);
+
+enum EmitPolicy {
+ EmitIfChanged,
+ AlwaysEmit,
+ NeverEmit
+};
+
+enum Button {
+ None = 0x000,
+ Keyboard = 0x001,
+ Mouse = 0x002,
+ Wheel = 0x004,
+ ButtonMask = 0x008,
+ Up = 0x010,
+ Down = 0x020,
+ DirectionMask = 0x040
+};
+class QSpinBoxValidator;
+class QAbstractSpinBoxPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractSpinBox)
+public:
+ QAbstractSpinBoxPrivate();
+ ~QAbstractSpinBoxPrivate();
+
+ void init();
+ void reset();
+ void updateState(bool up, bool fromKeyboard = false);
+ QString stripped(const QString &text, int *pos = 0) const;
+ bool specialValue() const;
+ virtual QVariant getZeroVariant() const;
+ virtual void setRange(const QVariant &min, const QVariant &max);
+ void setValue(const QVariant &val, EmitPolicy ep, bool updateEdit = true);
+ virtual QVariant bound(const QVariant &val, const QVariant &old = QVariant(), int steps = 0) const;
+ virtual void updateEdit();
+
+ virtual void emitSignals(EmitPolicy ep, const QVariant &old);
+ virtual void interpret(EmitPolicy ep);
+ virtual QString textFromValue(const QVariant &n) const;
+ virtual QVariant valueFromText(const QString &input) const;
+
+ void _q_editorTextChanged(const QString &);
+ virtual void _q_editorCursorPositionChanged(int oldpos, int newpos);
+
+ virtual QStyle::SubControl newHoverControl(const QPoint &pos);
+ bool updateHoverControl(const QPoint &pos);
+
+ virtual void clearCache() const;
+ virtual void updateEditFieldGeometry();
+
+ static int variantCompare(const QVariant &arg1, const QVariant &arg2);
+ static QVariant variantBound(const QVariant &min, const QVariant &value, const QVariant &max);
+
+ QLineEdit *edit;
+ QString prefix, suffix, specialValueText;
+ QVariant value, minimum, maximum, singleStep;
+ QVariant::Type type;
+ int spinClickTimerId, spinClickTimerInterval, spinClickThresholdTimerId, spinClickThresholdTimerInterval;
+ int effectiveSpinRepeatRate;
+ uint buttonState;
+ mutable QString cachedText;
+ mutable QVariant cachedValue;
+ mutable QValidator::State cachedState;
+ mutable QSize cachedSizeHint, cachedMinimumSizeHint;
+ uint pendingEmit : 1;
+ uint readOnly : 1;
+ uint wrapping : 1;
+ uint ignoreCursorPositionChanged : 1;
+ uint frame : 1;
+ uint accelerate : 1;
+ uint keyboardTracking : 1;
+ uint cleared : 1;
+ uint ignoreUpdateEdit : 1;
+ QAbstractSpinBox::CorrectionMode correctionMode;
+ int acceleration;
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+ QAbstractSpinBox::ButtonSymbols buttonSymbols;
+ QSpinBoxValidator *validator;
+};
+
+class QSpinBoxValidator : public QValidator
+{
+public:
+ QSpinBoxValidator(QAbstractSpinBox *qptr, QAbstractSpinBoxPrivate *dptr);
+ QValidator::State validate(QString &input, int &) const;
+ void fixup(QString &) const;
+private:
+ QAbstractSpinBox *qptr;
+ QAbstractSpinBoxPrivate *dptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SPINBOX
+
+#endif // QABSTRACTSPINBOX_P_H
diff --git a/src/widgets/widgets/qbuttongroup.cpp b/src/widgets/widgets/qbuttongroup.cpp
new file mode 100644
index 0000000000..1caa33f2f7
--- /dev/null
+++ b/src/widgets/widgets/qbuttongroup.cpp
@@ -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 QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+/*!
+ \class QButtonGroup
+ \brief The QButtonGroup class provides a container to organize groups of
+ button widgets.
+
+ \ingroup organizers
+ \ingroup geomanagement
+
+ QButtonGroup provides an abstract container into which button widgets can
+ be placed. It does not provide a visual representation of this container
+ (see QGroupBox for a container widget), but instead manages the states of
+ each of the buttons in the group.
+
+ An \l {QButtonGroup::exclusive} {exclusive} button group switches
+ off all checkable (toggle) buttons except the one that was
+ clicked. By default, a button group is exclusive. The buttons in a
+ button group are usually checkable QPushButton's, \l{QCheckBox}es
+ (normally for non-exclusive button groups), or \l{QRadioButton}s.
+ If you create an exclusive button group, you should ensure that
+ one of the buttons in the group is initially checked; otherwise,
+ the group will initially be in a state where no buttons are
+ checked.
+
+ A button is added to the group with addButton(). It can be removed
+ from the group with removeButton(). If the group is exclusive, the
+ currently checked button is available as checkedButton(). If a
+ button is clicked the buttonClicked() signal is emitted. For a
+ checkable button in an exclusive group this means that the button
+ was checked. The list of buttons in the group is returned by
+ buttons().
+
+ In addition, QButtonGroup can map between integers and buttons.
+ You can assign an integer id to a button with setId(), and
+ retrieve it with id(). The id of the currently checked button is
+ available with checkedId(), and there is an overloaded signal
+ buttonClicked() which emits the id of the button. The id \c {-1}
+ is reserved by QButtonGroup to mean "no such button". The purpose
+ of the mapping mechanism is to simplify the representation of enum
+ values in a user interface.
+
+ \sa QGroupBox QPushButton, QCheckBox, QRadioButton
+*/
+
+/*!
+ \fn QButtonGroup::QButtonGroup(QObject *parent)
+
+ Constructs a new, empty button group with the given \a parent.
+
+ \sa addButton() setExclusive()
+*/
+
+/*!
+ \fn QButtonGroup::~QButtonGroup()
+
+ Destroys the button group.
+*/
+
+/*!
+ \property QButtonGroup::exclusive
+ \brief whether the button group is exclusive
+
+ If this property is true then only one button in the group can be checked
+ at any given time. The user can click on any button to check it, and that
+ button will replace the existing one as the checked button in the group.
+
+ In an exclusive group, the user cannot uncheck the currently checked button
+ by clicking on it; instead, another button in the group must be clicked
+ to set the new checked button for that group.
+
+ By default, this property is true.
+*/
+
+/*!
+ \fn void QButtonGroup::buttonClicked(QAbstractButton *button)
+
+ This signal is emitted when the given \a button is clicked. A
+ button is clicked when it is first pressed and then released, when
+ its shortcut key is typed, or programmatically when
+ QAbstractButton::click() or QAbstractButton::animateClick() is
+ called.
+
+
+ \sa checkedButton(), QAbstractButton::clicked()
+*/
+
+/*!
+ \fn void QButtonGroup::buttonClicked(int id)
+
+ This signal is emitted when a button with the given \a id is
+ clicked.
+
+ \sa checkedButton(), QAbstractButton::clicked()
+*/
+
+/*!
+ \fn void QButtonGroup::buttonPressed(QAbstractButton *button)
+ \since 4.2
+
+ This signal is emitted when the given \a button is pressed down.
+
+ \sa QAbstractButton::pressed()
+*/
+
+/*!
+ \fn void QButtonGroup::buttonPressed(int id)
+ \since 4.2
+
+ This signal is emitted when a button with the given \a id is
+ pressed down.
+
+ \sa QAbstractButton::pressed()
+*/
+
+/*!
+ \fn void QButtonGroup::buttonReleased(QAbstractButton *button)
+ \since 4.2
+
+ This signal is emitted when the given \a button is released.
+
+ \sa QAbstractButton::released()
+*/
+
+/*!
+ \fn void QButtonGroup::buttonReleased(int id)
+ \since 4.2
+
+ This signal is emitted when a button with the given \a id is
+ released.
+
+ \sa QAbstractButton::released()
+*/
+
+/*!
+ \fn void QButtonGroup::addButton(QAbstractButton *button);
+
+ Adds the given \a button to the end of the group's internal list
+ of buttons. An id will be assigned to the button by this
+ QButtonGroup. Automatically assigned ids are guaranteed to be
+ negative, starting with -2. If you are also assigning your own
+ ids, use positive values to avoid conflicts.
+
+ \sa removeButton() buttons()
+*/
+
+/*!
+ \fn void QButtonGroup::addButton(QAbstractButton *button, int id);
+
+ Adds the given \a button to the button group, with the given \a
+ id. It is recommended to assign only positive ids.
+
+ \sa removeButton() buttons()
+*/
+
+/*!
+ \fn void QButtonGroup::removeButton(QAbstractButton *button);
+
+ Removes the given \a button from the button group.
+
+ \sa addButton() buttons()
+*/
+
+/*!
+ \fn QList<QAbstractButton*> QButtonGroup::buttons() const
+
+ Returns the list of this groups's buttons. This may be empty.
+
+ \sa addButton(), removeButton()
+*/
+
+/*!
+ \fn QAbstractButton *QButtonGroup::checkedButton() const;
+
+ Returns the button group's checked button, or 0 if no buttons are
+ checked.
+
+ \sa buttonClicked()
+*/
+
+/*!
+ \fn QAbstractButton *QButtonGroup::button(int id) const;
+ \since 4.1
+
+ Returns the button with the specified \a id, or 0 if no such button
+ exists.
+*/
+
+/*!
+ \fn void QButtonGroup::setId(QAbstractButton *button, int id)
+ \since 4.1
+
+ Sets the \a id for the specified \a button. Note that \a id can
+ not be -1.
+
+ \sa id()
+*/
+
+/*!
+ \fn int QButtonGroup::id(QAbstractButton *button) const;
+ \since 4.1
+
+ Returns the id for the specified \a button, or -1 if no such button
+ exists.
+
+
+ \sa setId()
+*/
+
+/*!
+ \fn int QButtonGroup::checkedId() const;
+ \since 4.1
+
+ Returns the id of the checkedButton(), or -1 if no button is checked.
+
+ \sa setId()
+*/
+
+
+/*! \fn void QButtonGroup::insert(QAbstractButton *b)
+
+ Use addButton() instead.
+*/
+
+/*! \fn void QButtonGroup::remove(QAbstractButton *b)
+
+ Use removeButton() instead.
+*/
diff --git a/src/widgets/widgets/qbuttongroup.h b/src/widgets/widgets/qbuttongroup.h
new file mode 100644
index 0000000000..e3ef34644e
--- /dev/null
+++ b/src/widgets/widgets/qbuttongroup.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBUTTONGROUP_H
+#define QBUTTONGROUP_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_BUTTONGROUP
+
+class QAbstractButton;
+class QAbstractButtonPrivate;
+class QButtonGroupPrivate;
+
+class Q_WIDGETS_EXPORT QButtonGroup : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool exclusive READ exclusive WRITE setExclusive)
+public:
+ explicit QButtonGroup(QObject *parent = 0);
+ ~QButtonGroup();
+
+ void setExclusive(bool);
+ bool exclusive() const;
+
+ void addButton(QAbstractButton *);
+ void addButton(QAbstractButton *, int id);
+ void removeButton(QAbstractButton *);
+
+ QList<QAbstractButton*> buttons() const;
+
+ QAbstractButton * checkedButton() const;
+ // no setter on purpose!
+
+ QAbstractButton *button(int id) const;
+ void setId(QAbstractButton *button, int id);
+ int id(QAbstractButton *button) const;
+ int checkedId() const;
+
+Q_SIGNALS:
+ void buttonClicked(QAbstractButton *);
+ void buttonClicked(int);
+ void buttonPressed(QAbstractButton *);
+ void buttonPressed(int);
+ void buttonReleased(QAbstractButton *);
+ void buttonReleased(int);
+
+#ifdef QT3_SUPPORT
+public:
+ inline QT3_SUPPORT void insert(QAbstractButton *b) { addButton(b); }
+ inline QT3_SUPPORT void remove(QAbstractButton *b) { removeButton(b); }
+#endif
+
+private:
+ Q_DISABLE_COPY(QButtonGroup)
+ Q_DECLARE_PRIVATE(QButtonGroup)
+ friend class QAbstractButton;
+ friend class QAbstractButtonPrivate;
+};
+
+#endif // QT_NO_BUTTONGROUP
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBUTTONGROUP_H
diff --git a/src/widgets/widgets/qcalendartextnavigator_p.h b/src/widgets/widgets/qcalendartextnavigator_p.h
new file mode 100644
index 0000000000..b602c6d51e
--- /dev/null
+++ b/src/widgets/widgets/qcalendartextnavigator_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCALENDARTEXTNAVIGATOR_P_H
+#define QCALENDARTEXTNAVIGATOR_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 <QtCore/qobject.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qbasictimer.h>
+
+#ifndef QT_NO_CALENDARWIDGET
+
+QT_BEGIN_NAMESPACE
+
+class QLabel;
+class QCalendarDateValidator;
+class QFrame;
+
+class QCalendarTextNavigator: public QObject
+{
+ Q_OBJECT
+public:
+ QCalendarTextNavigator(QObject *parent = 0)
+ : QObject(parent), m_dateText(0), m_dateFrame(0), m_dateValidator(0), m_widget(0), m_editDelay(1500), m_date(QDate::currentDate()) { }
+
+ QWidget *widget() const;
+ void setWidget(QWidget *widget);
+
+ int dateEditAcceptDelay() const;
+ void setDateEditAcceptDelay(int delay);
+
+ QDate date() const;
+ void setDate(const QDate &date);
+
+ bool eventFilter(QObject *o, QEvent *e);
+ void timerEvent(QTimerEvent *e);
+
+signals:
+ void dateChanged(const QDate &date);
+ void editingFinished();
+
+private:
+ void applyDate();
+ void updateDateLabel();
+ void createDateLabel();
+ void removeDateLabel();
+
+ QLabel *m_dateText;
+ QFrame *m_dateFrame;
+ QBasicTimer m_acceptTimer;
+ QCalendarDateValidator *m_dateValidator;
+ QWidget *m_widget;
+ int m_editDelay;
+
+ QDate m_date;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CALENDARWIDGET
+
+#endif
+
diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp
new file mode 100644
index 0000000000..583e163cee
--- /dev/null
+++ b/src/widgets/widgets/qcalendarwidget.cpp
@@ -0,0 +1,3104 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcalendarwidget.h"
+
+#ifndef QT_NO_CALENDARWIDGET
+
+#include <qabstractitemmodel.h>
+#include <qitemdelegate.h>
+#include <qdatetime.h>
+#include <qtableview.h>
+#include <qlayout.h>
+#include <qevent.h>
+#include <qtextformat.h>
+#include <qheaderview.h>
+#include <private/qwidget_p.h>
+#include <qpushbutton.h>
+#include <qtoolbutton.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qmenu.h>
+#include <qapplication.h>
+#include <qbasictimer.h>
+#include <qstylepainter.h>
+#include <private/qcalendartextnavigator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+enum {
+ RowCount = 6,
+ ColumnCount = 7,
+ HeaderColumn = 0,
+ HeaderRow = 0,
+ MinimumDayOffset = 1
+};
+
+class QCalendarDateSectionValidator
+{
+public:
+
+ enum Section {
+ NextSection,
+ ThisSection,
+ PrevSection
+ };
+
+ QCalendarDateSectionValidator() {}
+ virtual ~QCalendarDateSectionValidator() {}
+ virtual Section handleKey(int key) = 0;
+ virtual QDate applyToDate(const QDate &date) const = 0;
+ virtual void setDate(const QDate &date) = 0;
+ virtual QString text() const = 0;
+ virtual QString text(const QDate &date, int repeat) const = 0;
+
+ QLocale m_locale;
+
+protected:
+ QString highlightString(const QString &str, int pos) const;
+private:
+};
+
+QString QCalendarDateSectionValidator::highlightString(const QString &str, int pos) const
+{
+ if (pos == 0)
+ return QLatin1String("<b>") + str + QLatin1String("</b>");
+ int startPos = str.length() - pos;
+ return str.mid(0, startPos) + QLatin1String("<b>") + str.mid(startPos, pos) + QLatin1String("</b>");
+
+}
+
+class QCalendarDayValidator : public QCalendarDateSectionValidator
+{
+
+public:
+ QCalendarDayValidator();
+ virtual Section handleKey(int key);
+ virtual QDate applyToDate(const QDate &date) const;
+ virtual void setDate(const QDate &date);
+ virtual QString text() const;
+ virtual QString text(const QDate &date, int repeat) const;
+private:
+ int m_pos;
+ int m_day;
+ int m_oldDay;
+};
+
+QCalendarDayValidator::QCalendarDayValidator()
+ : QCalendarDateSectionValidator(), m_pos(0), m_day(1), m_oldDay(1)
+{
+}
+
+QCalendarDateSectionValidator::Section QCalendarDayValidator::handleKey(int key)
+{
+ if (key == Qt::Key_Right || key == Qt::Key_Left) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Up) {
+ m_pos = 0;
+ ++m_day;
+ if (m_day > 31)
+ m_day = 1;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Down) {
+ m_pos = 0;
+ --m_day;
+ if (m_day < 1)
+ m_day = 31;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
+ --m_pos;
+ if (m_pos < 0)
+ m_pos = 1;
+
+ if (m_pos == 0)
+ m_day = m_oldDay;
+ else
+ m_day = m_day / 10;
+ //m_day = m_oldDay / 10 * 10 + m_day / 10;
+
+ if (m_pos == 0)
+ return QCalendarDateSectionValidator::PrevSection;
+ return QCalendarDateSectionValidator::ThisSection;
+ }
+ if (key < Qt::Key_0 || key > Qt::Key_9)
+ return QCalendarDateSectionValidator::ThisSection;
+ int pressedKey = key - Qt::Key_0;
+ if (m_pos == 0)
+ m_day = pressedKey;
+ else
+ m_day = m_day % 10 * 10 + pressedKey;
+ if (m_day > 31)
+ m_day = 31;
+ ++m_pos;
+ if (m_pos > 1) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::NextSection;
+ }
+ return QCalendarDateSectionValidator::ThisSection;
+}
+
+QDate QCalendarDayValidator::applyToDate(const QDate &date) const
+{
+ int day = m_day;
+ if (day < 1)
+ day = 1;
+ else if (day > 31)
+ day = 31;
+ if (day > date.daysInMonth())
+ day = date.daysInMonth();
+ return QDate(date.year(), date.month(), day);
+}
+
+void QCalendarDayValidator::setDate(const QDate &date)
+{
+ m_day = m_oldDay = date.day();
+ m_pos = 0;
+}
+
+QString QCalendarDayValidator::text() const
+{
+ QString str;
+ if (m_day / 10 == 0)
+ str += QLatin1Char('0');
+ str += QString::number(m_day);
+ return highlightString(str, m_pos);
+}
+
+QString QCalendarDayValidator::text(const QDate &date, int repeat) const
+{
+ if (repeat <= 1) {
+ return QString::number(date.day());
+ } else if (repeat == 2) {
+ QString str;
+ if (date.day() / 10 == 0)
+ str += QLatin1Char('0');
+ return str + QString::number(date.day());
+ } else if (repeat == 3) {
+ return m_locale.dayName(date.dayOfWeek(), QLocale::ShortFormat);
+ } else if (repeat >= 4) {
+ return m_locale.dayName(date.dayOfWeek(), QLocale::LongFormat);
+ }
+ return QString();
+}
+
+//////////////////////////////////
+
+class QCalendarMonthValidator : public QCalendarDateSectionValidator
+{
+
+public:
+ QCalendarMonthValidator();
+ virtual Section handleKey(int key);
+ virtual QDate applyToDate(const QDate &date) const;
+ virtual void setDate(const QDate &date);
+ virtual QString text() const;
+ virtual QString text(const QDate &date, int repeat) const;
+private:
+ int m_pos;
+ int m_month;
+ int m_oldMonth;
+};
+
+QCalendarMonthValidator::QCalendarMonthValidator()
+ : QCalendarDateSectionValidator(), m_pos(0), m_month(1), m_oldMonth(1)
+{
+}
+
+QCalendarDateSectionValidator::Section QCalendarMonthValidator::handleKey(int key)
+{
+ if (key == Qt::Key_Right || key == Qt::Key_Left) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Up) {
+ m_pos = 0;
+ ++m_month;
+ if (m_month > 12)
+ m_month = 1;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Down) {
+ m_pos = 0;
+ --m_month;
+ if (m_month < 1)
+ m_month = 12;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
+ --m_pos;
+ if (m_pos < 0)
+ m_pos = 1;
+
+ if (m_pos == 0)
+ m_month = m_oldMonth;
+ else
+ m_month = m_month / 10;
+ //m_month = m_oldMonth / 10 * 10 + m_month / 10;
+
+ if (m_pos == 0)
+ return QCalendarDateSectionValidator::PrevSection;
+ return QCalendarDateSectionValidator::ThisSection;
+ }
+ if (key < Qt::Key_0 || key > Qt::Key_9)
+ return QCalendarDateSectionValidator::ThisSection;
+ int pressedKey = key - Qt::Key_0;
+ if (m_pos == 0)
+ m_month = pressedKey;
+ else
+ m_month = m_month % 10 * 10 + pressedKey;
+ if (m_month > 12)
+ m_month = 12;
+ ++m_pos;
+ if (m_pos > 1) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::NextSection;
+ }
+ return QCalendarDateSectionValidator::ThisSection;
+}
+
+QDate QCalendarMonthValidator::applyToDate(const QDate &date) const
+{
+ int month = m_month;
+ if (month < 1)
+ month = 1;
+ else if (month > 12)
+ month = 12;
+ QDate newDate(date.year(), m_month, 1);
+ int day = date.day();
+ if (day > newDate.daysInMonth())
+ day = newDate.daysInMonth();
+ return QDate(date.year(), month, day);
+}
+
+void QCalendarMonthValidator::setDate(const QDate &date)
+{
+ m_month = m_oldMonth = date.month();
+ m_pos = 0;
+}
+
+QString QCalendarMonthValidator::text() const
+{
+ QString str;
+ if (m_month / 10 == 0)
+ str += QLatin1Char('0');
+ str += QString::number(m_month);
+ return highlightString(str, m_pos);
+}
+
+QString QCalendarMonthValidator::text(const QDate &date, int repeat) const
+{
+ if (repeat <= 1) {
+ return QString::number(date.month());
+ } else if (repeat == 2) {
+ QString str;
+ if (date.month() / 10 == 0)
+ str += QLatin1Char('0');
+ return str + QString::number(date.month());
+ } else if (repeat == 3) {
+ return m_locale.standaloneMonthName(date.month(), QLocale::ShortFormat);
+ } else /*if (repeat >= 4)*/ {
+ return m_locale.standaloneMonthName(date.month(), QLocale::LongFormat);
+ }
+}
+
+//////////////////////////////////
+
+class QCalendarYearValidator : public QCalendarDateSectionValidator
+{
+
+public:
+ QCalendarYearValidator();
+ virtual Section handleKey(int key);
+ virtual QDate applyToDate(const QDate &date) const;
+ virtual void setDate(const QDate &date);
+ virtual QString text() const;
+ virtual QString text(const QDate &date, int repeat) const;
+private:
+ int pow10(int n);
+ int m_pos;
+ int m_year;
+ int m_oldYear;
+};
+
+QCalendarYearValidator::QCalendarYearValidator()
+ : QCalendarDateSectionValidator(), m_pos(0), m_year(2000), m_oldYear(2000)
+{
+}
+
+int QCalendarYearValidator::pow10(int n)
+{
+ int power = 1;
+ for (int i = 0; i < n; i++)
+ power *= 10;
+ return power;
+}
+
+QCalendarDateSectionValidator::Section QCalendarYearValidator::handleKey(int key)
+{
+ if (key == Qt::Key_Right || key == Qt::Key_Left) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Up) {
+ m_pos = 0;
+ ++m_year;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Down) {
+ m_pos = 0;
+ --m_year;
+ return QCalendarDateSectionValidator::ThisSection;
+ } else if (key == Qt::Key_Back || key == Qt::Key_Backspace) {
+ --m_pos;
+ if (m_pos < 0)
+ m_pos = 3;
+
+ int pow = pow10(m_pos);
+ m_year = m_oldYear / pow * pow + m_year % (pow * 10) / 10;
+
+ if (m_pos == 0)
+ return QCalendarDateSectionValidator::PrevSection;
+ return QCalendarDateSectionValidator::ThisSection;
+ }
+ if (key < Qt::Key_0 || key > Qt::Key_9)
+ return QCalendarDateSectionValidator::ThisSection;
+ int pressedKey = key - Qt::Key_0;
+ int pow = pow10(m_pos);
+ m_year = m_year / (pow * 10) * (pow * 10) + m_year % pow * 10 + pressedKey;
+ ++m_pos;
+ if (m_pos > 3) {
+ m_pos = 0;
+ return QCalendarDateSectionValidator::NextSection;
+ }
+ return QCalendarDateSectionValidator::ThisSection;
+}
+
+QDate QCalendarYearValidator::applyToDate(const QDate &date) const
+{
+ int year = m_year;
+ if (year < 1)
+ year = 1;
+ QDate newDate(year, date.month(), 1);
+ int day = date.day();
+ if (day > newDate.daysInMonth())
+ day = newDate.daysInMonth();
+ return QDate(year, date.month(), day);
+}
+
+void QCalendarYearValidator::setDate(const QDate &date)
+{
+ m_year = m_oldYear = date.year();
+ m_pos = 0;
+}
+
+QString QCalendarYearValidator::text() const
+{
+ QString str;
+ int pow = 10;
+ for (int i = 0; i < 3; i++) {
+ if (m_year / pow == 0)
+ str += QLatin1Char('0');
+ pow *= 10;
+ }
+ str += QString::number(m_year);
+ return highlightString(str, m_pos);
+}
+
+QString QCalendarYearValidator::text(const QDate &date, int repeat) const
+{
+ if (repeat < 4) {
+ QString str;
+ int year = date.year() % 100;
+ if (year / 10 == 0)
+ str = QLatin1Char('0');
+ return str + QString::number(year);
+ }
+ return QString::number(date.year());
+}
+
+///////////////////////////////////
+
+class QCalendarDateValidator
+{
+public:
+ QCalendarDateValidator();
+ ~QCalendarDateValidator();
+
+ void handleKeyEvent(QKeyEvent *keyEvent);
+ QString currentText() const;
+ QDate currentDate() const { return m_currentDate; }
+ void setFormat(const QString &format);
+ void setInitialDate(const QDate &date);
+
+ void setLocale(const QLocale &locale);
+
+private:
+
+ struct SectionToken {
+ SectionToken(QCalendarDateSectionValidator *val, int rep) : validator(val), repeat(rep) {}
+ QCalendarDateSectionValidator *validator;
+ int repeat;
+ };
+
+ void toNextToken();
+ void toPreviousToken();
+ void applyToDate();
+
+ int countRepeat(const QString &str, int index) const;
+ void clear();
+
+ QStringList m_separators;
+ QList<SectionToken *> m_tokens;
+ QCalendarDateSectionValidator *m_yearValidator;
+ QCalendarDateSectionValidator *m_monthValidator;
+ QCalendarDateSectionValidator *m_dayValidator;
+
+ SectionToken *m_currentToken;
+
+ QDate m_initialDate;
+ QDate m_currentDate;
+
+ QCalendarDateSectionValidator::Section m_lastSectionMove;
+};
+
+QCalendarDateValidator::QCalendarDateValidator()
+ : m_currentToken(0), m_lastSectionMove(QCalendarDateSectionValidator::ThisSection)
+{
+ m_initialDate = m_currentDate = QDate::currentDate();
+ m_yearValidator = new QCalendarYearValidator();
+ m_monthValidator = new QCalendarMonthValidator();
+ m_dayValidator = new QCalendarDayValidator();
+}
+
+void QCalendarDateValidator::setLocale(const QLocale &locale)
+{
+ m_yearValidator->m_locale = locale;
+ m_monthValidator->m_locale = locale;
+ m_dayValidator->m_locale = locale;
+}
+
+QCalendarDateValidator::~QCalendarDateValidator()
+{
+ delete m_yearValidator;
+ delete m_monthValidator;
+ delete m_dayValidator;
+ clear();
+}
+
+// from qdatetime.cpp
+int QCalendarDateValidator::countRepeat(const QString &str, int index) const
+{
+ Q_ASSERT(index >= 0 && index < str.size());
+ int count = 1;
+ const QChar ch = str.at(index);
+ while (index + count < str.size() && str.at(index + count) == ch)
+ ++count;
+ return count;
+}
+
+void QCalendarDateValidator::setInitialDate(const QDate &date)
+{
+ m_yearValidator->setDate(date);
+ m_monthValidator->setDate(date);
+ m_dayValidator->setDate(date);
+ m_initialDate = date;
+ m_currentDate = date;
+ m_lastSectionMove = QCalendarDateSectionValidator::ThisSection;
+}
+
+QString QCalendarDateValidator::currentText() const
+{
+ QString str;
+ QStringListIterator itSep(m_separators);
+ QListIterator<SectionToken *> itTok(m_tokens);
+ while (itSep.hasNext()) {
+ str += itSep.next();
+ if (itTok.hasNext()) {
+ SectionToken *token = itTok.next();
+ QCalendarDateSectionValidator *validator = token->validator;
+ if (m_currentToken == token)
+ str += validator->text();
+ else
+ str += validator->text(m_currentDate, token->repeat);
+ }
+ }
+ return str;
+}
+
+void QCalendarDateValidator::clear()
+{
+ QListIterator<SectionToken *> it(m_tokens);
+ while (it.hasNext())
+ delete it.next();
+
+ m_tokens.clear();
+ m_separators.clear();
+
+ m_currentToken = 0;
+}
+
+void QCalendarDateValidator::setFormat(const QString &format)
+{
+ clear();
+
+ int pos = 0;
+ const QLatin1Char quote('\'');
+ bool quoting = false;
+ QString separator;
+ while (pos < format.size()) {
+ QString mid = format.mid(pos);
+ int offset = 1;
+
+ if (mid.startsWith(quote)) {
+ quoting = !quoting;
+ } else {
+ const QChar nextChar = format.at(pos);
+ if (quoting) {
+ separator += nextChar;
+ } else {
+ SectionToken *token = 0;
+ if (nextChar == QLatin1Char('d')) {
+ offset = qMin(4, countRepeat(format, pos));
+ token = new SectionToken(m_dayValidator, offset);
+ } else if (nextChar == QLatin1Char('M')) {
+ offset = qMin(4, countRepeat(format, pos));
+ token = new SectionToken(m_monthValidator, offset);
+ } else if (nextChar == QLatin1Char('y')) {
+ offset = qMin(4, countRepeat(format, pos));
+ token = new SectionToken(m_yearValidator, offset);
+ } else {
+ separator += nextChar;
+ }
+ if (token) {
+ m_tokens.append(token);
+ m_separators.append(separator);
+ separator = QString();
+ if (!m_currentToken)
+ m_currentToken = token;
+
+ }
+ }
+ }
+ pos += offset;
+ }
+ m_separators += separator;
+}
+
+void QCalendarDateValidator::applyToDate()
+{
+ m_currentDate = m_yearValidator->applyToDate(m_currentDate);
+ m_currentDate = m_monthValidator->applyToDate(m_currentDate);
+ m_currentDate = m_dayValidator->applyToDate(m_currentDate);
+}
+
+void QCalendarDateValidator::toNextToken()
+{
+ const int idx = m_tokens.indexOf(m_currentToken);
+ if (idx == -1)
+ return;
+ if (idx + 1 >= m_tokens.count())
+ m_currentToken = m_tokens.first();
+ else
+ m_currentToken = m_tokens.at(idx + 1);
+}
+
+void QCalendarDateValidator::toPreviousToken()
+{
+ const int idx = m_tokens.indexOf(m_currentToken);
+ if (idx == -1)
+ return;
+ if (idx - 1 < 0)
+ m_currentToken = m_tokens.last();
+ else
+ m_currentToken = m_tokens.at(idx - 1);
+}
+
+void QCalendarDateValidator::handleKeyEvent(QKeyEvent *keyEvent)
+{
+ if (!m_currentToken)
+ return;
+
+ int key = keyEvent->key();
+ if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection) {
+ if (key == Qt::Key_Back || key == Qt::Key_Backspace)
+ toPreviousToken();
+ }
+ if (key == Qt::Key_Right)
+ toNextToken();
+ else if (key == Qt::Key_Left)
+ toPreviousToken();
+
+ m_lastSectionMove = m_currentToken->validator->handleKey(key);
+
+ applyToDate();
+ if (m_lastSectionMove == QCalendarDateSectionValidator::NextSection)
+ toNextToken();
+ else if (m_lastSectionMove == QCalendarDateSectionValidator::PrevSection)
+ toPreviousToken();
+}
+
+QWidget *QCalendarTextNavigator::widget() const
+{
+ return m_widget;
+}
+
+void QCalendarTextNavigator::setWidget(QWidget *widget)
+{
+ m_widget = widget;
+}
+
+QDate QCalendarTextNavigator::date() const
+{
+ return m_date;
+}
+
+void QCalendarTextNavigator::setDate(const QDate &date)
+{
+ m_date = date;
+}
+
+void QCalendarTextNavigator::updateDateLabel()
+{
+ if (!m_widget)
+ return;
+
+ m_acceptTimer.start(m_editDelay, this);
+
+ m_dateText->setText(m_dateValidator->currentText());
+
+ QSize s = m_dateFrame->sizeHint();
+ QRect r = m_widget->geometry(); // later, just the table section
+ QRect newRect((r.width() - s.width()) / 2, (r.height() - s.height()) / 2, s.width(), s.height());
+ m_dateFrame->setGeometry(newRect);
+ // need to set palette after geometry update as phonestyle sets transparency
+ // effect in move event.
+ QPalette p = m_dateFrame->palette();
+ p.setBrush(QPalette::Window, m_dateFrame->window()->palette().brush(QPalette::Window));
+ m_dateFrame->setPalette(p);
+
+ m_dateFrame->raise();
+ m_dateFrame->show();
+}
+
+void QCalendarTextNavigator::applyDate()
+{
+ QDate date = m_dateValidator->currentDate();
+ if (m_date == date)
+ return;
+
+ m_date = date;
+ emit dateChanged(date);
+}
+
+void QCalendarTextNavigator::createDateLabel()
+{
+ if (m_dateFrame)
+ return;
+ m_dateFrame = new QFrame(m_widget);
+ QVBoxLayout *vl = new QVBoxLayout;
+ m_dateText = new QLabel;
+ vl->addWidget(m_dateText);
+ m_dateFrame->setLayout(vl);
+ m_dateFrame->setFrameShadow(QFrame::Plain);
+ m_dateFrame->setFrameShape(QFrame::Box);
+ m_dateValidator = new QCalendarDateValidator();
+ m_dateValidator->setLocale(m_widget->locale());
+ m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
+ m_dateValidator->setInitialDate(m_date);
+
+ m_dateFrame->setAutoFillBackground(true);
+ m_dateFrame->setBackgroundRole(QPalette::Window);
+}
+
+void QCalendarTextNavigator::removeDateLabel()
+{
+ if (!m_dateFrame)
+ return;
+ m_acceptTimer.stop();
+ m_dateFrame->hide();
+ m_dateFrame->deleteLater();
+ delete m_dateValidator;
+ m_dateFrame = 0;
+ m_dateText = 0;
+ m_dateValidator = 0;
+}
+
+bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
+{
+ if (m_widget) {
+ if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
+ QKeyEvent* ke = (QKeyEvent*)e;
+ if ((ke->text().length() > 0 && ke->text()[0].isPrint()) || m_dateFrame) {
+ if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Select) {
+ applyDate();
+ emit editingFinished();
+ removeDateLabel();
+ } else if (ke->key() == Qt::Key_Escape) {
+ removeDateLabel();
+ } else if (e->type() == QEvent::KeyPress) {
+ createDateLabel();
+ m_dateValidator->handleKeyEvent(ke);
+ updateDateLabel();
+ }
+ ke->accept();
+ return true;
+ }
+ // If we are navigating let the user finish his date in old locate.
+ // If we change our mind and want it to update immediately simply uncomment below
+ /*
+ } else if (e->type() == QEvent::LocaleChange) {
+ if (m_dateValidator) {
+ m_dateValidator->setLocale(m_widget->locale());
+ m_dateValidator->setFormat(m_widget->locale().dateFormat(QLocale::ShortFormat));
+ updateDateLabel();
+ }
+ */
+ }
+ }
+ return QObject::eventFilter(o,e);
+}
+
+void QCalendarTextNavigator::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == m_acceptTimer.timerId()) {
+ applyDate();
+ removeDateLabel();
+ }
+}
+
+int QCalendarTextNavigator::dateEditAcceptDelay() const
+{
+ return m_editDelay;
+}
+
+void QCalendarTextNavigator::setDateEditAcceptDelay(int delay)
+{
+ m_editDelay = delay;
+}
+
+class QCalendarView;
+
+class QCalendarModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ QCalendarModel(QObject *parent = 0);
+
+ int rowCount(const QModelIndex &) const
+ { return RowCount + m_firstRow; }
+ int columnCount(const QModelIndex &) const
+ { return ColumnCount + m_firstColumn; }
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
+ {
+ beginInsertRows(parent, row, row + count - 1);
+ endInsertRows();
+ return true;
+ }
+ bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
+ {
+ beginInsertColumns(parent, column, column + count - 1);
+ endInsertColumns();
+ return true;
+ }
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
+ {
+ beginRemoveRows(parent, row, row + count - 1);
+ endRemoveRows();
+ return true;
+ }
+ bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
+ {
+ beginRemoveColumns(parent, column, column + count - 1);
+ endRemoveColumns();
+ return true;
+ }
+
+ void showMonth(int year, int month);
+ void setDate(const QDate &d);
+
+ void setMinimumDate(const QDate &date);
+ void setMaximumDate(const QDate &date);
+
+ void setRange(const QDate &min, const QDate &max);
+
+ void setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format);
+
+ void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
+ Qt::DayOfWeek firstColumnDay() const;
+
+ bool weekNumbersShown() const;
+ void setWeekNumbersShown(bool show);
+
+ QTextCharFormat formatForCell(int row, int col) const;
+ Qt::DayOfWeek dayOfWeekForColumn(int section) const;
+ int columnForDayOfWeek(Qt::DayOfWeek day) const;
+ QDate dateForCell(int row, int column) const;
+ void cellForDate(const QDate &date, int *row, int *column) const;
+ QString dayName(Qt::DayOfWeek day) const;
+
+ void setView(QCalendarView *view)
+ { m_view = view; }
+
+ void internalUpdate();
+ QDate referenceDate() const;
+ int columnForFirstOfMonth(const QDate &date) const;
+
+ int m_firstColumn;
+ int m_firstRow;
+ QDate m_date;
+ QDate m_minimumDate;
+ QDate m_maximumDate;
+ int m_shownYear;
+ int m_shownMonth;
+ Qt::DayOfWeek m_firstDay;
+ QCalendarWidget::HorizontalHeaderFormat m_horizontalHeaderFormat;
+ bool m_weekNumbersShown;
+ QMap<Qt::DayOfWeek, QTextCharFormat> m_dayFormats;
+ QMap<QDate, QTextCharFormat> m_dateFormats;
+ QTextCharFormat m_headerFormat;
+ QCalendarView *m_view;
+};
+
+class QCalendarView : public QTableView
+{
+ Q_OBJECT
+public:
+ QCalendarView(QWidget *parent = 0);
+
+ void internalUpdate() { updateGeometries(); }
+ void setReadOnly(bool enable);
+ virtual void keyboardSearch(const QString & search) { Q_UNUSED(search) }
+
+signals:
+ void showDate(const QDate &date);
+ void changeDate(const QDate &date, bool changeMonth);
+ void clicked(const QDate &date);
+ void editingFinished();
+protected:
+ QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *event);
+#endif
+ void keyPressEvent(QKeyEvent *event);
+ bool event(QEvent *event);
+
+ QDate handleMouseEvent(QMouseEvent *event);
+public:
+ bool readOnly;
+private:
+ bool validDateClicked;
+#ifdef QT_KEYPAD_NAVIGATION
+ QDate origDate;
+#endif
+};
+
+QCalendarModel::QCalendarModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+ m_date = QDate::currentDate();
+ m_minimumDate = QDate::fromJulianDay(1);
+ m_maximumDate = QDate(7999, 12, 31);
+ m_shownYear = m_date.year();
+ m_shownMonth = m_date.month();
+ m_firstDay = Qt::Sunday;
+ m_horizontalHeaderFormat = QCalendarWidget::ShortDayNames;
+ m_weekNumbersShown = true;
+ m_firstColumn = 1;
+ m_firstRow = 1;
+ m_view = 0;
+}
+
+Qt::DayOfWeek QCalendarModel::dayOfWeekForColumn(int column) const
+{
+ int col = column - m_firstColumn;
+ if (col < 0 || col > 6)
+ return Qt::Sunday;
+ int day = m_firstDay + col;
+ if (day > 7)
+ day -= 7;
+ return Qt::DayOfWeek(day);
+}
+
+int QCalendarModel::columnForDayOfWeek(Qt::DayOfWeek day) const
+{
+ if (day < 1 || day > 7)
+ return -1;
+ int column = (int)day - (int)m_firstDay;
+ if (column < 0)
+ column += 7;
+ return column + m_firstColumn;
+}
+
+/*
+This simple algorithm tries to generate a valid date from the month shown.
+Some months don't contain a first day (e.g. Jan of -4713 year,
+so QDate (-4713, 1, 1) would be invalid). In that case we try to generate
+another valid date for that month. Later, returned date's day is the number of cells
+calendar widget will reserve for days before referenceDate. (E.g. if returned date's
+day is 16, that day will be placed in 3rd or 4th row, not in the 1st or 2nd row).
+Depending on referenceData we can change behaviour of Oct 1582. If referenceDate is 1st
+of Oct we render 1 Oct in 1st or 2nd row. If referenceDate is 17 of Oct we show always 16
+dates before 17 of Oct, and since this month contains the hole 5-14 Oct, the first of Oct
+will be rendered in 2nd or 3rd row, showing more dates from previous month.
+*/
+QDate QCalendarModel::referenceDate() const
+{
+ int refDay = 1;
+ while (refDay <= 31) {
+ QDate refDate(m_shownYear, m_shownMonth, refDay);
+ if (refDate.isValid())
+ return refDate;
+ refDay += 1;
+ }
+ return QDate();
+}
+
+int QCalendarModel::columnForFirstOfMonth(const QDate &date) const
+{
+ return (columnForDayOfWeek(static_cast<Qt::DayOfWeek>(date.dayOfWeek())) - (date.day() % 7) + 8) % 7;
+}
+
+QDate QCalendarModel::dateForCell(int row, int column) const
+{
+ if (row < m_firstRow || row > m_firstRow + RowCount - 1 ||
+ column < m_firstColumn || column > m_firstColumn + ColumnCount - 1)
+ return QDate();
+ const QDate refDate = referenceDate();
+ if (!refDate.isValid())
+ return QDate();
+
+ const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
+ if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
+ row -= 1;
+
+ const int requestedDay = 7 * (row - m_firstRow) + column - columnForFirstOfShownMonth - refDate.day() + 1;
+ return refDate.addDays(requestedDay);
+}
+
+void QCalendarModel::cellForDate(const QDate &date, int *row, int *column) const
+{
+ if (!row && !column)
+ return;
+
+ if (row)
+ *row = -1;
+ if (column)
+ *column = -1;
+
+ const QDate refDate = referenceDate();
+ if (!refDate.isValid())
+ return;
+
+ const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
+ const int requestedPosition = refDate.daysTo(date) - m_firstColumn + columnForFirstOfShownMonth + refDate.day() - 1;
+
+ int c = requestedPosition % 7;
+ int r = requestedPosition / 7;
+ if (c < 0) {
+ c += 7;
+ r -= 1;
+ }
+
+ if (columnForFirstOfShownMonth - m_firstColumn < MinimumDayOffset)
+ r += 1;
+
+ if (r < 0 || r > RowCount - 1 || c < 0 || c > ColumnCount - 1)
+ return;
+
+ if (row)
+ *row = r + m_firstRow;
+ if (column)
+ *column = c + m_firstColumn;
+}
+
+QString QCalendarModel::dayName(Qt::DayOfWeek day) const
+{
+ switch (m_horizontalHeaderFormat) {
+ case QCalendarWidget::SingleLetterDayNames: {
+ QString standaloneDayName = m_view->locale().standaloneDayName(day, QLocale::NarrowFormat);
+ if (standaloneDayName == m_view->locale().dayName(day, QLocale::NarrowFormat))
+ return standaloneDayName.left(1);
+ return standaloneDayName;
+ }
+ case QCalendarWidget::ShortDayNames:
+ return m_view->locale().dayName(day, QLocale::ShortFormat);
+ case QCalendarWidget::LongDayNames:
+ return m_view->locale().dayName(day, QLocale::LongFormat);
+ default:
+ break;
+ }
+ return QString();
+}
+
+QTextCharFormat QCalendarModel::formatForCell(int row, int col) const
+{
+ QPalette pal;
+ QPalette::ColorGroup cg = QPalette::Active;
+ if (m_view) {
+ pal = m_view->palette();
+ if (!m_view->isEnabled())
+ cg = QPalette::Disabled;
+ else if (!m_view->isActiveWindow())
+ cg = QPalette::Inactive;
+ }
+
+ QTextCharFormat format;
+ format.setFont(m_view->font());
+ bool header = (m_weekNumbersShown && col == HeaderColumn)
+ || (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow);
+ format.setBackground(pal.brush(cg, header ? QPalette::AlternateBase : QPalette::Base));
+ format.setForeground(pal.brush(cg, QPalette::Text));
+ if (header) {
+ format.merge(m_headerFormat);
+ }
+
+ if (col >= m_firstColumn && col < m_firstColumn + ColumnCount) {
+ Qt::DayOfWeek dayOfWeek = dayOfWeekForColumn(col);
+ if (m_dayFormats.contains(dayOfWeek))
+ format.merge(m_dayFormats.value(dayOfWeek));
+ }
+
+ if (!header) {
+ QDate date = dateForCell(row, col);
+ format.merge(m_dateFormats.value(date));
+ if(date < m_minimumDate || date > m_maximumDate)
+ format.setBackground(pal.brush(cg, QPalette::Window));
+ if (m_shownMonth != date.month())
+ format.setForeground(pal.brush(QPalette::Disabled, QPalette::Text));
+ }
+ return format;
+}
+
+QVariant QCalendarModel::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::TextAlignmentRole)
+ return (int) Qt::AlignCenter;
+
+ int row = index.row();
+ int column = index.column();
+
+ if(role == Qt::DisplayRole) {
+ if (m_weekNumbersShown && column == HeaderColumn
+ && row >= m_firstRow && row < m_firstRow + RowCount) {
+ QDate date = dateForCell(row, columnForDayOfWeek(Qt::Monday));
+ if (date.isValid())
+ return date.weekNumber();
+ }
+ if (m_horizontalHeaderFormat != QCalendarWidget::NoHorizontalHeader && row == HeaderRow
+ && column >= m_firstColumn && column < m_firstColumn + ColumnCount)
+ return dayName(dayOfWeekForColumn(column));
+ QDate date = dateForCell(row, column);
+ if (date.isValid())
+ return date.day();
+ return QString();
+ }
+
+ QTextCharFormat fmt = formatForCell(row, column);
+ if (role == Qt::BackgroundColorRole)
+ return fmt.background().color();
+ if (role == Qt::TextColorRole)
+ return fmt.foreground().color();
+ if (role == Qt::FontRole)
+ return fmt.font();
+ if (role == Qt::ToolTipRole)
+ return fmt.toolTip();
+ return QVariant();
+}
+
+Qt::ItemFlags QCalendarModel::flags(const QModelIndex &index) const
+{
+ QDate date = dateForCell(index.row(), index.column());
+ if (!date.isValid())
+ return QAbstractTableModel::flags(index);
+ if (date < m_minimumDate)
+ return 0;
+ if (date > m_maximumDate)
+ return 0;
+ return QAbstractTableModel::flags(index);
+}
+
+void QCalendarModel::setDate(const QDate &d)
+{
+ m_date = d;
+ if (m_date < m_minimumDate)
+ m_date = m_minimumDate;
+ else if (m_date > m_maximumDate)
+ m_date = m_maximumDate;
+}
+
+void QCalendarModel::showMonth(int year, int month)
+{
+ if (m_shownYear == year && m_shownMonth == month)
+ return;
+
+ m_shownYear = year;
+ m_shownMonth = month;
+
+ internalUpdate();
+}
+
+void QCalendarModel::setMinimumDate(const QDate &d)
+{
+ if (!d.isValid() || d == m_minimumDate)
+ return;
+
+ m_minimumDate = d;
+ if (m_maximumDate < m_minimumDate)
+ m_maximumDate = m_minimumDate;
+ if (m_date < m_minimumDate)
+ m_date = m_minimumDate;
+ internalUpdate();
+}
+
+void QCalendarModel::setMaximumDate(const QDate &d)
+{
+ if (!d.isValid() || d == m_maximumDate)
+ return;
+
+ m_maximumDate = d;
+ if (m_minimumDate > m_maximumDate)
+ m_minimumDate = m_maximumDate;
+ if (m_date > m_maximumDate)
+ m_date = m_maximumDate;
+ internalUpdate();
+}
+
+void QCalendarModel::setRange(const QDate &min, const QDate &max)
+{
+ m_minimumDate = min;
+ m_maximumDate = max;
+ if (m_minimumDate > m_maximumDate)
+ qSwap(m_minimumDate, m_maximumDate);
+ if (m_date < m_minimumDate)
+ m_date = m_minimumDate;
+ if (m_date > m_maximumDate)
+ m_date = m_maximumDate;
+ internalUpdate();
+}
+
+void QCalendarModel::internalUpdate()
+{
+ QModelIndex begin = index(0, 0);
+ QModelIndex end = index(m_firstRow + RowCount - 1, m_firstColumn + ColumnCount - 1);
+ emit dataChanged(begin, end);
+ emit headerDataChanged(Qt::Vertical, 0, m_firstRow + RowCount - 1);
+ emit headerDataChanged(Qt::Horizontal, 0, m_firstColumn + ColumnCount - 1);
+}
+
+void QCalendarModel::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
+{
+ if (m_horizontalHeaderFormat == format)
+ return;
+
+ int oldFormat = m_horizontalHeaderFormat;
+ m_horizontalHeaderFormat = format;
+ if (oldFormat == QCalendarWidget::NoHorizontalHeader) {
+ m_firstRow = 1;
+ insertRow(0);
+ } else if (m_horizontalHeaderFormat == QCalendarWidget::NoHorizontalHeader) {
+ m_firstRow = 0;
+ removeRow(0);
+ }
+ internalUpdate();
+}
+
+void QCalendarModel::setFirstColumnDay(Qt::DayOfWeek dayOfWeek)
+{
+ if (m_firstDay == dayOfWeek)
+ return;
+
+ m_firstDay = dayOfWeek;
+ internalUpdate();
+}
+
+Qt::DayOfWeek QCalendarModel::firstColumnDay() const
+{
+ return m_firstDay;
+}
+
+bool QCalendarModel::weekNumbersShown() const
+{
+ return m_weekNumbersShown;
+}
+
+void QCalendarModel::setWeekNumbersShown(bool show)
+{
+ if (m_weekNumbersShown == show)
+ return;
+
+ m_weekNumbersShown = show;
+ if (show) {
+ m_firstColumn = 1;
+ insertColumn(0);
+ } else {
+ m_firstColumn = 0;
+ removeColumn(0);
+ }
+ internalUpdate();
+}
+
+QCalendarView::QCalendarView(QWidget *parent)
+ : QTableView(parent),
+ readOnly(false),
+ validDateClicked(false)
+{
+ setTabKeyNavigation(false);
+ setShowGrid(false);
+ verticalHeader()->setVisible(false);
+ horizontalHeader()->setVisible(false);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+QModelIndex QCalendarView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel)
+ return QTableView::moveCursor(cursorAction, modifiers);
+
+ if (readOnly)
+ return currentIndex();
+
+ QModelIndex index = currentIndex();
+ QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
+ switch (cursorAction) {
+ case QAbstractItemView::MoveUp:
+ currentDate = currentDate.addDays(-7);
+ break;
+ case QAbstractItemView::MoveDown:
+ currentDate = currentDate.addDays(7);
+ break;
+ case QAbstractItemView::MoveLeft:
+ currentDate = currentDate.addDays(isRightToLeft() ? 1 : -1);
+ break;
+ case QAbstractItemView::MoveRight:
+ currentDate = currentDate.addDays(isRightToLeft() ? -1 : 1);
+ break;
+ case QAbstractItemView::MoveHome:
+ currentDate = QDate(currentDate.year(), currentDate.month(), 1);
+ break;
+ case QAbstractItemView::MoveEnd:
+ currentDate = QDate(currentDate.year(), currentDate.month(), currentDate.daysInMonth());
+ break;
+ case QAbstractItemView::MovePageUp:
+ currentDate = currentDate.addMonths(-1);
+ break;
+ case QAbstractItemView::MovePageDown:
+ currentDate = currentDate.addMonths(1);
+ break;
+ case QAbstractItemView::MoveNext:
+ case QAbstractItemView::MovePrevious:
+ return currentIndex();
+ default:
+ break;
+ }
+ emit changeDate(currentDate, true);
+ return currentIndex();
+}
+
+void QCalendarView::keyPressEvent(QKeyEvent *event)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (event->key() == Qt::Key_Select) {
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus()) {
+ setEditFocus(true);
+ return;
+ }
+ }
+ } else if (event->key() == Qt::Key_Back) {
+ if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
+ if (qobject_cast<QCalendarModel *>(model())) {
+ emit changeDate(origDate, true); //changes selection back to origDate, but doesn't activate
+ setEditFocus(false);
+ return;
+ }
+ }
+ }
+#endif
+
+ if (!readOnly) {
+ switch (event->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Select:
+ emit editingFinished();
+ return;
+ default:
+ break;
+ }
+ }
+ QTableView::keyPressEvent(event);
+}
+
+#ifndef QT_NO_WHEELEVENT
+void QCalendarView::wheelEvent(QWheelEvent *event)
+{
+ const int numDegrees = event->delta() / 8;
+ const int numSteps = numDegrees / 15;
+ const QModelIndex index = currentIndex();
+ QDate currentDate = static_cast<QCalendarModel*>(model())->dateForCell(index.row(), index.column());
+ currentDate = currentDate.addMonths(-numSteps);
+ emit showDate(currentDate);
+}
+#endif
+
+bool QCalendarView::event(QEvent *event)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (event->type() == QEvent::FocusIn) {
+ if (QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model())) {
+ origDate = calendarModel->m_date;
+ }
+ }
+#endif
+
+ return QTableView::event(event);
+}
+
+QDate QCalendarView::handleMouseEvent(QMouseEvent *event)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel)
+ return QDate();
+
+ QPoint pos = event->pos();
+ QModelIndex index = indexAt(pos);
+ QDate date = calendarModel->dateForCell(index.row(), index.column());
+ if (date.isValid() && date >= calendarModel->m_minimumDate
+ && date <= calendarModel->m_maximumDate) {
+ return date;
+ }
+ return QDate();
+}
+
+void QCalendarView::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel) {
+ QTableView::mouseDoubleClickEvent(event);
+ return;
+ }
+
+ if (readOnly)
+ return;
+
+ QDate date = handleMouseEvent(event);
+ validDateClicked = false;
+ if (date == calendarModel->m_date && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) {
+ emit editingFinished();
+ }
+}
+
+void QCalendarView::mousePressEvent(QMouseEvent *event)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel) {
+ QTableView::mousePressEvent(event);
+ return;
+ }
+
+ if (readOnly)
+ return;
+
+ if (event->button() != Qt::LeftButton)
+ return;
+
+ QDate date = handleMouseEvent(event);
+ if (date.isValid()) {
+ validDateClicked = true;
+ int row = -1, col = -1;
+ static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
+ if (row != -1 && col != -1) {
+ selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
+ }
+ } else {
+ validDateClicked = false;
+ event->ignore();
+ }
+}
+
+void QCalendarView::mouseMoveEvent(QMouseEvent *event)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel) {
+ QTableView::mouseMoveEvent(event);
+ return;
+ }
+
+ if (readOnly)
+ return;
+
+ if (validDateClicked) {
+ QDate date = handleMouseEvent(event);
+ if (date.isValid()) {
+ int row = -1, col = -1;
+ static_cast<QCalendarModel *>(model())->cellForDate(date, &row, &col);
+ if (row != -1 && col != -1) {
+ selectionModel()->setCurrentIndex(model()->index(row, col), QItemSelectionModel::NoUpdate);
+ }
+ }
+ } else {
+ event->ignore();
+ }
+}
+
+void QCalendarView::mouseReleaseEvent(QMouseEvent *event)
+{
+ QCalendarModel *calendarModel = qobject_cast<QCalendarModel *>(model());
+ if (!calendarModel) {
+ QTableView::mouseReleaseEvent(event);
+ return;
+ }
+
+ if (event->button() != Qt::LeftButton)
+ return;
+
+ if (readOnly)
+ return;
+
+ if (validDateClicked) {
+ QDate date = handleMouseEvent(event);
+ if (date.isValid()) {
+ emit changeDate(date, true);
+ emit clicked(date);
+ if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick))
+ emit editingFinished();
+ }
+ validDateClicked = false;
+ } else {
+ event->ignore();
+ }
+}
+
+class QCalendarDelegate : public QItemDelegate
+{
+ Q_OBJECT
+public:
+ QCalendarDelegate(QCalendarWidgetPrivate *w, QObject *parent = 0)
+ : QItemDelegate(parent), calendarWidgetPrivate(w)
+ { }
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
+
+private:
+ QCalendarWidgetPrivate *calendarWidgetPrivate;
+ mutable QStyleOptionViewItemV4 storedOption;
+};
+
+//Private tool button class
+class QCalToolButton: public QToolButton
+{
+public:
+ QCalToolButton(QWidget * parent)
+ : QToolButton(parent)
+ { }
+protected:
+ void paintEvent(QPaintEvent *e)
+ {
+ Q_UNUSED(e)
+
+#ifndef Q_WS_MAC
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+
+ if (opt.state & QStyle::State_MouseOver || isDown()) {
+ //act as normal button
+ setPalette(QPalette());
+ } else {
+ //set the highlight color for button text
+ QPalette toolPalette = palette();
+ toolPalette.setColor(QPalette::ButtonText, toolPalette.color(QPalette::HighlightedText));
+ setPalette(toolPalette);
+ }
+#endif
+ QToolButton::paintEvent(e);
+ }
+};
+
+class QPrevNextCalButton : public QToolButton
+{
+ Q_OBJECT
+public:
+ QPrevNextCalButton(QWidget *parent) : QToolButton(parent) {}
+protected:
+ void paintEvent(QPaintEvent *) {
+ QStylePainter painter(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ opt.state &= ~QStyle::State_HasFocus;
+ painter.drawComplexControl(QStyle::CC_ToolButton, opt);
+ }
+};
+
+class QCalendarWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QCalendarWidget)
+public:
+ QCalendarWidgetPrivate();
+
+ void showMonth(int year, int month);
+ void update();
+ void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
+
+ void _q_slotShowDate(const QDate &date);
+ void _q_slotChangeDate(const QDate &date);
+ void _q_slotChangeDate(const QDate &date, bool changeMonth);
+ void _q_editingFinished();
+ void _q_monthChanged(QAction*);
+ void _q_prevMonthClicked();
+ void _q_nextMonthClicked();
+ void _q_yearEditingFinished();
+ void _q_yearClicked();
+
+ void createNavigationBar(QWidget *widget);
+ void updateButtonIcons();
+ void updateMonthMenu();
+ void updateMonthMenuNames();
+ void updateNavigationBar();
+ void updateCurrentPage(const QDate &newDate);
+ inline QDate getCurrentDate();
+ void setNavigatorEnabled(bool enable);
+
+ QCalendarModel *m_model;
+ QCalendarView *m_view;
+ QCalendarDelegate *m_delegate;
+ QItemSelectionModel *m_selection;
+ QCalendarTextNavigator *m_navigator;
+ bool m_dateEditEnabled;
+
+ QToolButton *nextMonth;
+ QToolButton *prevMonth;
+ QCalToolButton *monthButton;
+ QMenu *monthMenu;
+ QMap<int, QAction *> monthToAction;
+ QCalToolButton *yearButton;
+ QSpinBox *yearEdit;
+ QWidget *navBarBackground;
+ QSpacerItem *spaceHolder;
+
+ bool navBarVisible;
+ mutable QSize cachedSizeHint;
+ Qt::FocusPolicy oldFocusPolicy;
+};
+
+void QCalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QDate date = calendarWidgetPrivate->m_model->dateForCell(index.row(), index.column());
+ if (date.isValid()) {
+ storedOption = option;
+ QRect rect = option.rect;
+ calendarWidgetPrivate->paintCell(painter, rect, date);
+ } else {
+ QItemDelegate::paint(painter, option, index);
+ }
+}
+
+void QCalendarDelegate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
+{
+ storedOption.rect = rect;
+ int row = -1;
+ int col = -1;
+ calendarWidgetPrivate->m_model->cellForDate(date, &row, &col);
+ QModelIndex idx = calendarWidgetPrivate->m_model->index(row, col);
+ QItemDelegate::paint(painter, storedOption, idx);
+}
+
+QCalendarWidgetPrivate::QCalendarWidgetPrivate()
+ : QWidgetPrivate()
+{
+ m_model = 0;
+ m_view = 0;
+ m_delegate = 0;
+ m_selection = 0;
+ m_navigator = 0;
+ m_dateEditEnabled = false;
+ navBarVisible = true;
+ oldFocusPolicy = Qt::StrongFocus;
+}
+
+void QCalendarWidgetPrivate::setNavigatorEnabled(bool enable)
+{
+ Q_Q(QCalendarWidget);
+
+ bool navigatorEnabled = (m_navigator->widget() != 0);
+ if (enable == navigatorEnabled)
+ return;
+
+ if (enable) {
+ m_navigator->setWidget(q);
+ q->connect(m_navigator, SIGNAL(dateChanged(QDate)),
+ q, SLOT(_q_slotChangeDate(QDate)));
+ q->connect(m_navigator, SIGNAL(editingFinished()),
+ q, SLOT(_q_editingFinished()));
+ m_view->installEventFilter(m_navigator);
+ } else {
+ m_navigator->setWidget(0);
+ q->disconnect(m_navigator, SIGNAL(dateChanged(QDate)),
+ q, SLOT(_q_slotChangeDate(QDate)));
+ q->disconnect(m_navigator, SIGNAL(editingFinished()),
+ q, SLOT(_q_editingFinished()));
+ m_view->removeEventFilter(m_navigator);
+ }
+}
+
+void QCalendarWidgetPrivate::createNavigationBar(QWidget *widget)
+{
+ Q_Q(QCalendarWidget);
+ navBarBackground = new QWidget(widget);
+ navBarBackground->setObjectName(QLatin1String("qt_calendar_navigationbar"));
+ navBarBackground->setAutoFillBackground(true);
+ navBarBackground->setBackgroundRole(QPalette::Highlight);
+
+ prevMonth = new QPrevNextCalButton(navBarBackground);
+ nextMonth = new QPrevNextCalButton(navBarBackground);
+ prevMonth->setAutoRaise(true);
+ nextMonth->setAutoRaise(true);
+ prevMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ nextMonth->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ nextMonth->setAutoRaise(true);
+ updateButtonIcons();
+ prevMonth->setAutoRepeat(true);
+ nextMonth->setAutoRepeat(true);
+
+ monthButton = new QCalToolButton(navBarBackground);
+ monthButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ monthButton->setAutoRaise(true);
+ monthButton->setPopupMode(QToolButton::InstantPopup);
+ monthMenu = new QMenu(monthButton);
+ for (int i = 1; i <= 12; i++) {
+ QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
+ QAction *act = monthMenu->addAction(monthName);
+ act->setData(i);
+ monthToAction[i] = act;
+ }
+ monthButton->setMenu(monthMenu);
+ yearButton = new QCalToolButton(navBarBackground);
+ yearButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ yearButton->setAutoRaise(true);
+ yearEdit = new QSpinBox(navBarBackground);
+
+ QFont font = q->font();
+ font.setBold(true);
+ monthButton->setFont(font);
+ yearButton->setFont(font);
+ yearEdit->setFrame(false);
+ yearEdit->setMinimum(m_model->m_minimumDate.year());
+ yearEdit->setMaximum(m_model->m_maximumDate.year());
+ yearEdit->hide();
+ spaceHolder = new QSpacerItem(0,0);
+
+ QHBoxLayout *headerLayout = new QHBoxLayout;
+ headerLayout->setMargin(0);
+ headerLayout->setSpacing(0);
+ headerLayout->addWidget(prevMonth);
+ headerLayout->insertStretch(headerLayout->count());
+ headerLayout->addWidget(monthButton);
+ headerLayout->addItem(spaceHolder);
+ headerLayout->addWidget(yearButton);
+ headerLayout->insertStretch(headerLayout->count());
+ headerLayout->addWidget(nextMonth);
+ navBarBackground->setLayout(headerLayout);
+
+ yearEdit->setFocusPolicy(Qt::StrongFocus);
+ prevMonth->setFocusPolicy(Qt::NoFocus);
+ nextMonth->setFocusPolicy(Qt::NoFocus);
+ yearButton->setFocusPolicy(Qt::NoFocus);
+ monthButton->setFocusPolicy(Qt::NoFocus);
+
+ //set names for the header controls.
+ prevMonth->setObjectName(QLatin1String("qt_calendar_prevmonth"));
+ nextMonth->setObjectName(QLatin1String("qt_calendar_nextmonth"));
+ monthButton->setObjectName(QLatin1String("qt_calendar_monthbutton"));
+ yearButton->setObjectName(QLatin1String("qt_calendar_yearbutton"));
+ yearEdit->setObjectName(QLatin1String("qt_calendar_yearedit"));
+
+ updateMonthMenu();
+ showMonth(m_model->m_date.year(), m_model->m_date.month());
+}
+
+void QCalendarWidgetPrivate::updateButtonIcons()
+{
+ Q_Q(QCalendarWidget);
+ prevMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowRight : QStyle::SP_ArrowLeft, 0, q));
+ nextMonth->setIcon(q->style()->standardIcon(q->isRightToLeft() ? QStyle::SP_ArrowLeft : QStyle::SP_ArrowRight, 0, q));
+}
+
+void QCalendarWidgetPrivate::updateMonthMenu()
+{
+ int beg = 1, end = 12;
+ bool prevEnabled = true;
+ bool nextEnabled = true;
+ if (m_model->m_shownYear == m_model->m_minimumDate.year()) {
+ beg = m_model->m_minimumDate.month();
+ if (m_model->m_shownMonth == m_model->m_minimumDate.month())
+ prevEnabled = false;
+ }
+ if (m_model->m_shownYear == m_model->m_maximumDate.year()) {
+ end = m_model->m_maximumDate.month();
+ if (m_model->m_shownMonth == m_model->m_maximumDate.month())
+ nextEnabled = false;
+ }
+ prevMonth->setEnabled(prevEnabled);
+ nextMonth->setEnabled(nextEnabled);
+ for (int i = 1; i <= 12; i++) {
+ bool monthEnabled = true;
+ if (i < beg || i > end)
+ monthEnabled = false;
+ monthToAction[i]->setEnabled(monthEnabled);
+ }
+}
+
+void QCalendarWidgetPrivate::updateMonthMenuNames()
+{
+ Q_Q(QCalendarWidget);
+
+ for (int i = 1; i <= 12; i++) {
+ QString monthName(q->locale().standaloneMonthName(i, QLocale::LongFormat));
+ monthToAction[i]->setText(monthName);
+ }
+}
+
+void QCalendarWidgetPrivate::updateCurrentPage(const QDate &date)
+{
+ Q_Q(QCalendarWidget);
+
+ QDate newDate = date;
+ QDate minDate = q->minimumDate();
+ QDate maxDate = q->maximumDate();
+ if (minDate.isValid()&& minDate.daysTo(newDate) < 0)
+ newDate = minDate;
+ if (maxDate.isValid()&& maxDate.daysTo(newDate) > 0)
+ newDate = maxDate;
+ showMonth(newDate.year(), newDate.month());
+ int row = -1, col = -1;
+ m_model->cellForDate(newDate, &row, &col);
+ if (row != -1 && col != -1)
+ {
+ m_view->selectionModel()->setCurrentIndex(m_model->index(row, col),
+ QItemSelectionModel::NoUpdate);
+ }
+}
+
+void QCalendarWidgetPrivate::_q_monthChanged(QAction *act)
+{
+ monthButton->setText(act->text());
+ QDate currentDate = getCurrentDate();
+ QDate newDate = currentDate.addMonths(act->data().toInt()-currentDate.month());
+ updateCurrentPage(newDate);
+}
+
+QDate QCalendarWidgetPrivate::getCurrentDate()
+{
+ QModelIndex index = m_view->currentIndex();
+ return m_model->dateForCell(index.row(), index.column());
+}
+
+void QCalendarWidgetPrivate::_q_prevMonthClicked()
+{
+ QDate currentDate = getCurrentDate().addMonths(-1);
+ updateCurrentPage(currentDate);
+}
+
+void QCalendarWidgetPrivate::_q_nextMonthClicked()
+{
+ QDate currentDate = getCurrentDate().addMonths(1);
+ updateCurrentPage(currentDate);
+}
+
+void QCalendarWidgetPrivate::_q_yearEditingFinished()
+{
+ Q_Q(QCalendarWidget);
+ yearButton->setText(yearEdit->text());
+ yearEdit->hide();
+ q->setFocusPolicy(oldFocusPolicy);
+ qApp->removeEventFilter(q);
+ spaceHolder->changeSize(0, 0);
+ yearButton->show();
+ QDate currentDate = getCurrentDate();
+ currentDate = currentDate.addYears(yearEdit->text().toInt() - currentDate.year());
+ updateCurrentPage(currentDate);
+}
+
+void QCalendarWidgetPrivate::_q_yearClicked()
+{
+ Q_Q(QCalendarWidget);
+ //show the spinbox on top of the button
+ yearEdit->setGeometry(yearButton->x(), yearButton->y(),
+ yearEdit->sizeHint().width(), yearButton->height());
+ spaceHolder->changeSize(yearButton->width(), 0);
+ yearButton->hide();
+ oldFocusPolicy = q->focusPolicy();
+ q->setFocusPolicy(Qt::NoFocus);
+ yearEdit->show();
+ qApp->installEventFilter(q);
+ yearEdit->raise();
+ yearEdit->selectAll();
+ yearEdit->setFocus(Qt::MouseFocusReason);
+}
+
+void QCalendarWidgetPrivate::showMonth(int year, int month)
+{
+ if (m_model->m_shownYear == year && m_model->m_shownMonth == month)
+ return;
+ Q_Q(QCalendarWidget);
+ m_model->showMonth(year, month);
+ updateNavigationBar();
+ emit q->currentPageChanged(year, month);
+ m_view->internalUpdate();
+ cachedSizeHint = QSize();
+ update();
+ updateMonthMenu();
+}
+
+void QCalendarWidgetPrivate::updateNavigationBar()
+{
+ Q_Q(QCalendarWidget);
+
+ QString monthName = q->locale().standaloneMonthName(m_model->m_shownMonth, QLocale::LongFormat);
+
+ monthButton->setText(monthName);
+ yearButton->setText(QString::number(m_model->m_shownYear));
+ yearEdit->setValue(m_model->m_shownYear);
+}
+
+void QCalendarWidgetPrivate::update()
+{
+ QDate currentDate = m_model->m_date;
+ int row, column;
+ m_model->cellForDate(currentDate, &row, &column);
+ QModelIndex idx;
+ m_selection->clear();
+ if (row != -1 && column != -1) {
+ idx = m_model->index(row, column);
+ m_selection->setCurrentIndex(idx, QItemSelectionModel::SelectCurrent);
+ }
+}
+
+void QCalendarWidgetPrivate::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
+{
+ Q_Q(const QCalendarWidget);
+ q->paintCell(painter, rect, date);
+}
+
+void QCalendarWidgetPrivate::_q_slotShowDate(const QDate &date)
+{
+ updateCurrentPage(date);
+}
+
+void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date)
+{
+ _q_slotChangeDate(date, true);
+}
+
+void QCalendarWidgetPrivate::_q_slotChangeDate(const QDate &date, bool changeMonth)
+{
+ QDate oldDate = m_model->m_date;
+ m_model->setDate(date);
+ QDate newDate = m_model->m_date;
+ if (changeMonth)
+ showMonth(newDate.year(), newDate.month());
+ if (oldDate != newDate) {
+ update();
+ Q_Q(QCalendarWidget);
+ m_navigator->setDate(newDate);
+ emit q->selectionChanged();
+ }
+}
+
+void QCalendarWidgetPrivate::_q_editingFinished()
+{
+ Q_Q(QCalendarWidget);
+ emit q->activated(m_model->m_date);
+}
+
+/*!
+ \class QCalendarWidget
+ \brief The QCalendarWidget class provides a monthly based
+ calendar widget allowing the user to select a date.
+ \since 4.2
+
+ \ingroup advanced
+
+ \image cleanlooks-calendarwidget.png
+
+ The widget is initialized with the current month and year, but
+ QCalendarWidget provides several public slots to change the year
+ and month that is shown.
+
+ By default, today's date is selected, and the user can select a
+ date using both mouse and keyboard. The currently selected date
+ can be retrieved using the selectedDate() function. It is
+ possible to constrain the user selection to a given date range by
+ setting the minimumDate and maximumDate properties.
+ Alternatively, both properties can be set in one go using the
+ setDateRange() convenience slot. Set the \l selectionMode
+ property to NoSelection to prohibit the user from selecting at
+ all. Note that a date also can be selected programmatically using
+ the setSelectedDate() slot.
+
+ The currently displayed month and year can be retrieved using the
+ monthShown() and yearShown() functions, respectively.
+
+ A newly created calendar widget uses abbreviated day names, and
+ both Saturdays and Sundays are marked in red. The calendar grid is
+ not visible. The week numbers are displayed, and the first column
+ day is Sunday.
+
+ The notation of the days can be altered to a single letter
+ abbreviations ("M" for "Monday") by setting the
+ horizontalHeaderFormat property to
+ QCalendarWidget::SingleLetterDayNames. Setting the same property
+ to QCalendarWidget::LongDayNames makes the header display the
+ complete day names. The week numbers can be removed by setting
+ the verticalHeaderFormat property to
+ QCalendarWidget::NoVerticalHeader. The calendar grid can be
+ turned on by setting the gridVisible property to true using the
+ setGridVisible() function:
+
+ \table
+ \row \o
+ \image qcalendarwidget-grid.png
+ \row \o
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 0
+ \endtable
+
+ Finally, the day in the first column can be altered using the
+ setFirstDayOfWeek() function.
+
+ The QCalendarWidget class also provides three signals,
+ selectionChanged(), activated() and currentPageChanged() making it
+ possible to respond to user interaction.
+
+ The rendering of the headers, weekdays or single days can be
+ largely customized by setting QTextCharFormat's for some special
+ weekday, a special date or for the rendering of the headers.
+
+ Only a subset of the properties in QTextCharFormat are used by the
+ calendar widget. Currently, the foreground, background and font
+ properties are used to determine the rendering of individual cells
+ in the widget.
+
+ \sa QDate, QDateEdit, QTextCharFormat
+*/
+
+/*!
+ \enum QCalendarWidget::SelectionMode
+
+ This enum describes the types of selection offered to the user for
+ selecting dates in the calendar.
+
+ \value NoSelection Dates cannot be selected.
+ \value SingleSelection Single dates can be selected.
+
+ \sa selectionMode
+*/
+
+/*!
+ Constructs a calendar widget with the given \a parent.
+
+ The widget is initialized with the current month and year, and the
+ currently selected date is today.
+
+ \sa setCurrentPage()
+*/
+QCalendarWidget::QCalendarWidget(QWidget *parent)
+ : QWidget(*new QCalendarWidgetPrivate, parent, 0)
+{
+ Q_D(QCalendarWidget);
+
+ setAutoFillBackground(true);
+ setBackgroundRole(QPalette::Window);
+
+ QVBoxLayout *layoutV = new QVBoxLayout(this);
+ layoutV->setMargin(0);
+ d->m_model = new QCalendarModel(this);
+ QTextCharFormat fmt;
+ fmt.setForeground(QBrush(Qt::red));
+ d->m_model->m_dayFormats.insert(Qt::Saturday, fmt);
+ d->m_model->m_dayFormats.insert(Qt::Sunday, fmt);
+ d->m_view = new QCalendarView(this);
+ d->m_view->setObjectName(QLatin1String("qt_calendar_calendarview"));
+ d->m_view->setModel(d->m_model);
+ d->m_model->setView(d->m_view);
+ d->m_view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ d->m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ d->m_view->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
+ d->m_view->horizontalHeader()->setClickable(false);
+ d->m_view->verticalHeader()->setResizeMode(QHeaderView::Stretch);
+ d->m_view->verticalHeader()->setClickable(false);
+ d->m_selection = d->m_view->selectionModel();
+ d->createNavigationBar(this);
+ d->m_view->setFrameStyle(QFrame::NoFrame);
+ d->m_delegate = new QCalendarDelegate(d, this);
+ d->m_view->setItemDelegate(d->m_delegate);
+ d->update();
+ d->updateNavigationBar();
+ setFocusPolicy(Qt::StrongFocus);
+ setFocusProxy(d->m_view);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+
+ connect(d->m_view, SIGNAL(showDate(QDate)),
+ this, SLOT(_q_slotShowDate(QDate)));
+ connect(d->m_view, SIGNAL(changeDate(QDate,bool)),
+ this, SLOT(_q_slotChangeDate(QDate,bool)));
+ connect(d->m_view, SIGNAL(clicked(QDate)),
+ this, SIGNAL(clicked(QDate)));
+ connect(d->m_view, SIGNAL(editingFinished()),
+ this, SLOT(_q_editingFinished()));
+
+ connect(d->prevMonth, SIGNAL(clicked(bool)),
+ this, SLOT(_q_prevMonthClicked()));
+ connect(d->nextMonth, SIGNAL(clicked(bool)),
+ this, SLOT(_q_nextMonthClicked()));
+ connect(d->yearButton, SIGNAL(clicked(bool)),
+ this, SLOT(_q_yearClicked()));
+ connect(d->monthMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(_q_monthChanged(QAction*)));
+ connect(d->yearEdit, SIGNAL(editingFinished()),
+ this, SLOT(_q_yearEditingFinished()));
+
+ layoutV->setMargin(0);
+ layoutV->setSpacing(0);
+ layoutV->addWidget(d->navBarBackground);
+ layoutV->addWidget(d->m_view);
+
+ d->m_navigator = new QCalendarTextNavigator(this);
+ setDateEditEnabled(true);
+}
+
+/*!
+ Destroys the calendar widget.
+*/
+QCalendarWidget::~QCalendarWidget()
+{
+}
+
+/*!
+ \reimp
+*/
+QSize QCalendarWidget::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+/*!
+ \reimp
+*/
+QSize QCalendarWidget::minimumSizeHint() const
+{
+ Q_D(const QCalendarWidget);
+ if (d->cachedSizeHint.isValid())
+ return d->cachedSizeHint;
+
+ ensurePolished();
+
+ int w = 0;
+ int h = 0;
+
+ int end = 53;
+ int rows = 7;
+ int cols = 8;
+
+ const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2;
+
+ if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
+ rows = 6;
+ } else {
+ for (int i = 1; i <= 7; i++) {
+ QFontMetrics fm(d->m_model->formatForCell(0, i).font());
+ w = qMax(w, fm.width(d->m_model->dayName(d->m_model->dayOfWeekForColumn(i))) + marginH);
+ h = qMax(h, fm.height());
+ }
+ }
+
+ if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) {
+ cols = 7;
+ } else {
+ for (int i = 1; i <= 6; i++) {
+ QFontMetrics fm(d->m_model->formatForCell(i, 0).font());
+ for (int j = 1; j < end; j++)
+ w = qMax(w, fm.width(QString::number(j)) + marginH);
+ h = qMax(h, fm.height());
+ }
+ }
+
+ QFontMetrics fm(d->m_model->formatForCell(1, 1).font());
+ for (int i = 1; i <= end; i++) {
+ w = qMax(w, fm.width(QString::number(i)) + marginH);
+ h = qMax(h, fm.height());
+ }
+
+ if (d->m_view->showGrid()) {
+ // hardcoded in tableview
+ w += 1;
+ h += 1;
+ }
+
+ w += 1; // default column span
+
+ h = qMax(h, d->m_view->verticalHeader()->minimumSectionSize());
+ w = qMax(w, d->m_view->horizontalHeader()->minimumSectionSize());
+
+ //add the size of the header.
+ QSize headerSize(0, 0);
+ if (d->navBarVisible) {
+ int headerH = d->navBarBackground->sizeHint().height();
+ int headerW = 0;
+
+ headerW += d->prevMonth->sizeHint().width();
+ headerW += d->nextMonth->sizeHint().width();
+
+ QFontMetrics fm = d->monthButton->fontMetrics();
+ int monthW = 0;
+ for (int i = 1; i < 12; i++) {
+ QString monthName = locale().standaloneMonthName(i, QLocale::LongFormat);
+ monthW = qMax(monthW, fm.boundingRect(monthName).width());
+ }
+ const int buttonDecoMargin = d->monthButton->sizeHint().width() - fm.boundingRect(d->monthButton->text()).width();
+ headerW += monthW + buttonDecoMargin;
+
+ fm = d->yearButton->fontMetrics();
+ headerW += fm.boundingRect(QLatin1String("5555")).width() + buttonDecoMargin;
+
+ headerSize = QSize(headerW, headerH);
+ }
+ w *= cols;
+ w = qMax(headerSize.width(), w);
+ h = (h * rows) + headerSize.height();
+ d->cachedSizeHint = QSize(w, h);
+ return d->cachedSizeHint;
+}
+
+/*!
+ Paints the cell specified by the given \a date, using the given \a painter and \a rect.
+*/
+
+void QCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
+{
+ Q_D(const QCalendarWidget);
+ d->m_delegate->paintCell(painter, rect, date);
+}
+
+/*!
+ \property QCalendarWidget::selectedDate
+ \brief the currently selected date.
+
+ The selected date must be within the date range specified by the
+ minimumDate and maximumDate properties. By default, the selected
+ date is the current date.
+
+ \sa setDateRange()
+*/
+
+QDate QCalendarWidget::selectedDate() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_date;
+}
+
+void QCalendarWidget::setSelectedDate(const QDate &date)
+{
+ Q_D(QCalendarWidget);
+ if (d->m_model->m_date == date && date == d->getCurrentDate())
+ return;
+
+ if (!date.isValid())
+ return;
+
+ d->m_model->setDate(date);
+ d->update();
+ QDate newDate = d->m_model->m_date;
+ d->showMonth(newDate.year(), newDate.month());
+ emit selectionChanged();
+}
+
+/*!
+ Returns the year of the currently displayed month. Months are
+ numbered from 1 to 12.
+
+ \sa monthShown(), setCurrentPage()
+*/
+
+int QCalendarWidget::yearShown() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_shownYear;
+}
+
+/*!
+ Returns the currently displayed month. Months are numbered from 1 to
+ 12.
+
+ \sa yearShown(), setCurrentPage()
+*/
+
+int QCalendarWidget::monthShown() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_shownMonth;
+}
+
+/*!
+ Displays the given \a month of the given \a year without changing
+ the selected date. Use the setSelectedDate() function to alter the
+ selected date.
+
+ The currently displayed month and year can be retrieved using the
+ monthShown() and yearShown() functions respectively.
+
+ \sa yearShown(), monthShown(), showPreviousMonth(), showNextMonth(),
+ showPreviousYear(), showNextYear()
+*/
+
+void QCalendarWidget::setCurrentPage(int year, int month)
+{
+ Q_D(QCalendarWidget);
+ QDate currentDate = d->getCurrentDate();
+ int day = currentDate.day();
+ int daysInMonths = QDate(year, month, 1).daysInMonth();
+ if (day > daysInMonths)
+ day = daysInMonths;
+
+ d->showMonth(year, month);
+
+ QDate newDate(year, month, day);
+ int row = -1, col = -1;
+ d->m_model->cellForDate(newDate, &row, &col);
+ if (row != -1 && col != -1) {
+ d->m_view->selectionModel()->setCurrentIndex(d->m_model->index(row, col),
+ QItemSelectionModel::NoUpdate);
+ }
+}
+
+/*!
+ Shows the next month relative to the currently displayed
+ month. Note that the selected date is not changed.
+
+ \sa showPreviousMonth(), setCurrentPage(), setSelectedDate()
+*/
+
+void QCalendarWidget::showNextMonth()
+{
+ int year = yearShown();
+ int month = monthShown();
+ if (month == 12) {
+ ++year;
+ month = 1;
+ } else {
+ ++month;
+ }
+ setCurrentPage(year, month);
+}
+
+/*!
+ Shows the previous month relative to the currently displayed
+ month. Note that the selected date is not changed.
+
+ \sa showNextMonth(), setCurrentPage(), setSelectedDate()
+*/
+
+void QCalendarWidget::showPreviousMonth()
+{
+ int year = yearShown();
+ int month = monthShown();
+ if (month == 1) {
+ --year;
+ month = 12;
+ } else {
+ --month;
+ }
+ setCurrentPage(year, month);
+}
+
+/*!
+ Shows the currently displayed month in the \e next year relative
+ to the currently displayed year. Note that the selected date is
+ not changed.
+
+ \sa showPreviousYear(), setCurrentPage(), setSelectedDate()
+*/
+
+void QCalendarWidget::showNextYear()
+{
+ int year = yearShown();
+ int month = monthShown();
+ ++year;
+ setCurrentPage(year, month);
+}
+
+/*!
+ Shows the currently displayed month in the \e previous year
+ relative to the currently displayed year. Note that the selected
+ date is not changed.
+
+ \sa showNextYear(), setCurrentPage(), setSelectedDate()
+*/
+
+void QCalendarWidget::showPreviousYear()
+{
+ int year = yearShown();
+ int month = monthShown();
+ --year;
+ setCurrentPage(year, month);
+}
+
+/*!
+ Shows the month of the selected date.
+
+ \sa selectedDate(), setCurrentPage()
+*/
+void QCalendarWidget::showSelectedDate()
+{
+ QDate currentDate = selectedDate();
+ setCurrentPage(currentDate.year(), currentDate.month());
+}
+
+/*!
+ Shows the month of the today's date.
+
+ \sa selectedDate(), setCurrentPage()
+*/
+void QCalendarWidget::showToday()
+{
+ QDate currentDate = QDate::currentDate();
+ setCurrentPage(currentDate.year(), currentDate.month());
+}
+
+/*!
+ \property QCalendarWidget::minimumDate
+ \brief the minimum date of the currently specified date range.
+
+ The user will not be able to select a date that is before the
+ currently set minimum date.
+
+ \table
+ \row
+ \o \image qcalendarwidget-minimum.png
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 1
+ \endtable
+
+ By default, the minimum date is the earliest date that the QDate
+ class can handle.
+
+ When setting a minimum date, the maximumDate and selectedDate
+ properties are adjusted if the selection range becomes invalid. If
+ the provided date is not a valid QDate object, the
+ setMinimumDate() function does nothing.
+
+ \sa setDateRange()
+*/
+
+QDate QCalendarWidget::minimumDate() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_minimumDate;
+}
+
+void QCalendarWidget::setMinimumDate(const QDate &date)
+{
+ Q_D(QCalendarWidget);
+ if (!date.isValid() || d->m_model->m_minimumDate == date)
+ return;
+
+ QDate oldDate = d->m_model->m_date;
+ d->m_model->setMinimumDate(date);
+ d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
+ d->updateMonthMenu();
+ QDate newDate = d->m_model->m_date;
+ if (oldDate != newDate) {
+ d->update();
+ d->showMonth(newDate.year(), newDate.month());
+ d->m_navigator->setDate(newDate);
+ emit selectionChanged();
+ }
+}
+
+/*!
+ \property QCalendarWidget::maximumDate
+ \brief the maximum date of the currently specified date range.
+
+ The user will not be able to select a date which is after the
+ currently set maximum date.
+
+ \table
+ \row
+ \o \image qcalendarwidget-maximum.png
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 2
+ \endtable
+
+ By default, the maximum date is the last day the QDate class can
+ handle.
+
+ When setting a maximum date, the minimumDate and selectedDate
+ properties are adjusted if the selection range becomes invalid. If
+ the provided date is not a valid QDate object, the
+ setMaximumDate() function does nothing.
+
+ \sa setDateRange()
+*/
+
+QDate QCalendarWidget::maximumDate() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_maximumDate;
+}
+
+void QCalendarWidget::setMaximumDate(const QDate &date)
+{
+ Q_D(QCalendarWidget);
+ if (!date.isValid() || d->m_model->m_maximumDate == date)
+ return;
+
+ QDate oldDate = d->m_model->m_date;
+ d->m_model->setMaximumDate(date);
+ d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
+ d->updateMonthMenu();
+ QDate newDate = d->m_model->m_date;
+ if (oldDate != newDate) {
+ d->update();
+ d->showMonth(newDate.year(), newDate.month());
+ d->m_navigator->setDate(newDate);
+ emit selectionChanged();
+ }
+}
+
+/*!
+ Defines a date range by setting the minimumDate and maximumDate
+ properties.
+
+ The date range restricts the user selection, i.e. the user can
+ only select dates within the specified date range. Note that
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 3
+
+ is analogous to
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 4
+
+ If either the \a min or \a max parameters are not valid QDate
+ objects, this function does nothing.
+
+ \sa setMinimumDate(), setMaximumDate()
+*/
+
+void QCalendarWidget::setDateRange(const QDate &min, const QDate &max)
+{
+ Q_D(QCalendarWidget);
+ if (d->m_model->m_minimumDate == min && d->m_model->m_maximumDate == max)
+ return;
+ if (!min.isValid() || !max.isValid())
+ return;
+
+ QDate oldDate = d->m_model->m_date;
+ d->m_model->setRange(min, max);
+ d->yearEdit->setMinimum(d->m_model->m_minimumDate.year());
+ d->yearEdit->setMaximum(d->m_model->m_maximumDate.year());
+ d->updateMonthMenu();
+ QDate newDate = d->m_model->m_date;
+ if (oldDate != newDate) {
+ d->update();
+ d->showMonth(newDate.year(), newDate.month());
+ d->m_navigator->setDate(newDate);
+ emit selectionChanged();
+ }
+}
+
+
+/*! \enum QCalendarWidget::HorizontalHeaderFormat
+
+ This enum type defines the various formats the horizontal header can display.
+
+ \value SingleLetterDayNames The header displays a single letter abbreviation for day names (e.g. M for Monday).
+ \value ShortDayNames The header displays a short abbreviation for day names (e.g. Mon for Monday).
+ \value LongDayNames The header displays complete day names (e.g. Monday).
+ \value NoHorizontalHeader The header is hidden.
+
+ \sa horizontalHeaderFormat(), VerticalHeaderFormat
+*/
+
+/*!
+ \property QCalendarWidget::horizontalHeaderFormat
+ \brief the format of the horizontal header.
+
+ The default value is QCalendarWidget::ShortDayNames.
+*/
+
+void QCalendarWidget::setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat format)
+{
+ Q_D(QCalendarWidget);
+ if (d->m_model->m_horizontalHeaderFormat == format)
+ return;
+
+ d->m_model->setHorizontalHeaderFormat(format);
+ d->cachedSizeHint = QSize();
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+QCalendarWidget::HorizontalHeaderFormat QCalendarWidget::horizontalHeaderFormat() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_horizontalHeaderFormat;
+}
+
+
+/*!
+ \enum QCalendarWidget::VerticalHeaderFormat
+
+ This enum type defines the various formats the vertical header can display.
+
+ \value ISOWeekNumbers The header displays ISO week numbers as described by \l QDate::weekNumber().
+ \value NoVerticalHeader The header is hidden.
+
+ \sa verticalHeaderFormat(), HorizontalHeaderFormat
+*/
+
+/*!
+ \property QCalendarWidget::verticalHeaderFormat
+ \brief the format of the vertical header.
+
+ The default value is QCalendarWidget::ISOWeekNumber.
+*/
+
+QCalendarWidget::VerticalHeaderFormat QCalendarWidget::verticalHeaderFormat() const
+{
+ Q_D(const QCalendarWidget);
+ bool shown = d->m_model->weekNumbersShown();
+ if (shown)
+ return QCalendarWidget::ISOWeekNumbers;
+ return QCalendarWidget::NoVerticalHeader;
+}
+
+void QCalendarWidget::setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat format)
+{
+ Q_D(QCalendarWidget);
+ bool show = false;
+ if (format == QCalendarWidget::ISOWeekNumbers)
+ show = true;
+ if (d->m_model->weekNumbersShown() == show)
+ return;
+ d->m_model->setWeekNumbersShown(show);
+ d->cachedSizeHint = QSize();
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+/*!
+ \property QCalendarWidget::gridVisible
+ \brief whether the table grid is displayed.
+
+ \table
+ \row
+ \o \inlineimage qcalendarwidget-grid.png
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_widgets_qcalendarwidget.cpp 5
+ \endtable
+
+ The default value is false.
+*/
+
+bool QCalendarWidget::isGridVisible() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_view->showGrid();
+}
+
+void QCalendarWidget::setGridVisible(bool show)
+{
+ Q_D(QCalendarWidget);
+ d->m_view->setShowGrid(show);
+ d->cachedSizeHint = QSize();
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+/*!
+ \property QCalendarWidget::selectionMode
+ \brief the type of selection the user can make in the calendar
+
+ When this property is set to SingleSelection, the user can select a date
+ within the minimum and maximum allowed dates, using either the mouse or
+ the keyboard.
+
+ When the property is set to NoSelection, the user will be unable to select
+ dates, but they can still be selected programmatically. Note that the date
+ that is selected when the property is set to NoSelection will still be
+ the selected date of the calendar.
+
+ The default value is SingleSelection.
+*/
+
+QCalendarWidget::SelectionMode QCalendarWidget::selectionMode() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_view->readOnly ? QCalendarWidget::NoSelection : QCalendarWidget::SingleSelection;
+}
+
+void QCalendarWidget::setSelectionMode(SelectionMode mode)
+{
+ Q_D(QCalendarWidget);
+ d->m_view->readOnly = (mode == QCalendarWidget::NoSelection);
+ d->setNavigatorEnabled(isDateEditEnabled() && (selectionMode() != QCalendarWidget::NoSelection));
+ d->update();
+}
+
+/*!
+ \property QCalendarWidget::firstDayOfWeek
+ \brief a value identifying the day displayed in the first column.
+
+ By default, the day displayed in the first column is Sunday
+*/
+
+void QCalendarWidget::setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
+{
+ Q_D(QCalendarWidget);
+ if ((Qt::DayOfWeek)d->m_model->firstColumnDay() == dayOfWeek)
+ return;
+
+ d->m_model->setFirstColumnDay(dayOfWeek);
+ d->update();
+}
+
+Qt::DayOfWeek QCalendarWidget::firstDayOfWeek() const
+{
+ Q_D(const QCalendarWidget);
+ return (Qt::DayOfWeek)d->m_model->firstColumnDay();
+}
+
+/*!
+ Returns the text char format for rendering the header.
+*/
+QTextCharFormat QCalendarWidget::headerTextFormat() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_headerFormat;
+}
+
+/*!
+ Sets the text char format for rendering the header to \a format.
+ If you also set a weekday text format, this format's foreground and
+ background color will take precedence over the header's format.
+ The other formatting information will still be decided by
+ the header's format.
+*/
+void QCalendarWidget::setHeaderTextFormat(const QTextCharFormat &format)
+{
+ Q_D(QCalendarWidget);
+ d->m_model->m_headerFormat = format;
+ d->cachedSizeHint = QSize();
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+/*!
+ Returns the text char format for rendering of day in the week \a dayOfWeek.
+
+ \sa headerTextFormat()
+*/
+QTextCharFormat QCalendarWidget::weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_dayFormats.value(dayOfWeek);
+}
+
+/*!
+ Sets the text char format for rendering of day in the week \a dayOfWeek to \a format.
+ The format will take precedence over the header format in case of foreground
+ and background color. Other text formatting information is taken from the headers format.
+
+ \sa setHeaderTextFormat()
+*/
+void QCalendarWidget::setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format)
+{
+ Q_D(QCalendarWidget);
+ d->m_model->m_dayFormats[dayOfWeek] = format;
+ d->cachedSizeHint = QSize();
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+/*!
+ Returns a QMap from QDate to QTextCharFormat showing all dates
+ that use a special format that alters their rendering.
+*/
+QMap<QDate, QTextCharFormat> QCalendarWidget::dateTextFormat() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_dateFormats;
+}
+
+/*!
+ Returns a QTextCharFormat for \a date. The char format can be be
+ empty if the date is not renderd specially.
+*/
+QTextCharFormat QCalendarWidget::dateTextFormat(const QDate &date) const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_model->m_dateFormats.value(date);
+}
+
+/*!
+ Sets the format used to render the given \a date to that specified by \a format.
+
+ If \a date is null, all date formats are cleared.
+*/
+void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
+{
+ Q_D(QCalendarWidget);
+ if (date.isNull())
+ d->m_model->m_dateFormats.clear();
+ else
+ d->m_model->m_dateFormats[date] = format;
+ d->m_view->viewport()->update();
+ d->m_view->updateGeometry();
+}
+
+/*!
+ \property QCalendarWidget::dateEditEnabled
+ \brief whether the date edit popup is enabled
+ \since 4.3
+
+ If this property is enabled, pressing a non-modifier key will cause a
+ date edit to popup if the calendar widget has focus, allowing the user
+ to specify a date in the form specified by the current locale.
+
+ By default, this property is enabled.
+
+ The date edit is simpler in appearance than QDateEdit, but allows the
+ user to navigate between fields using the left and right cursor keys,
+ increment and decrement individual fields using the up and down cursor
+ keys, and enter values directly using the number keys.
+
+ \sa QCalendarWidget::dateEditAcceptDelay
+*/
+bool QCalendarWidget::isDateEditEnabled() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_dateEditEnabled;
+}
+
+void QCalendarWidget::setDateEditEnabled(bool enable)
+{
+ Q_D(QCalendarWidget);
+ if (isDateEditEnabled() == enable)
+ return;
+
+ d->m_dateEditEnabled = enable;
+
+ d->setNavigatorEnabled(enable && (selectionMode() != QCalendarWidget::NoSelection));
+}
+
+/*!
+ \property QCalendarWidget::dateEditAcceptDelay
+ \brief the time an inactive date edit is shown before its contents are accepted
+ \since 4.3
+
+ If the calendar widget's \l{dateEditEnabled}{date edit is enabled}, this
+ property specifies the amount of time (in millseconds) that the date edit
+ remains open after the most recent user input. Once this time has elapsed,
+ the date specified in the date edit is accepted and the popup is closed.
+
+ By default, the delay is defined to be 1500 milliseconds (1.5 seconds).
+*/
+int QCalendarWidget::dateEditAcceptDelay() const
+{
+ Q_D(const QCalendarWidget);
+ return d->m_navigator->dateEditAcceptDelay();
+}
+
+void QCalendarWidget::setDateEditAcceptDelay(int delay)
+{
+ Q_D(QCalendarWidget);
+ d->m_navigator->setDateEditAcceptDelay(delay);
+}
+
+/*!
+ \since 4.4
+
+ Updates the cell specified by the given \a date unless updates
+ are disabled or the cell is hidden.
+
+ \sa updateCells(), yearShown(), monthShown()
+*/
+void QCalendarWidget::updateCell(const QDate &date)
+{
+ if (!date.isValid()) {
+ qWarning("QCalendarWidget::updateCell: Invalid date");
+ return;
+ }
+
+ if (!isVisible())
+ return;
+
+ Q_D(QCalendarWidget);
+ int row, column;
+ d->m_model->cellForDate(date, &row, &column);
+ if (row == -1 || column == -1)
+ return;
+
+ QModelIndex modelIndex = d->m_model->index(row, column);
+ if (!modelIndex.isValid())
+ return;
+
+ d->m_view->viewport()->update(d->m_view->visualRect(modelIndex));
+}
+
+/*!
+ \since 4.4
+
+ Updates all visible cells unless updates are disabled.
+
+ \sa updateCell()
+*/
+void QCalendarWidget::updateCells()
+{
+ Q_D(QCalendarWidget);
+ if (isVisible())
+ d->m_view->viewport()->update();
+}
+
+/*!
+ \fn void QCalendarWidget::selectionChanged()
+
+ This signal is emitted when the currently selected date is
+ changed.
+
+ The currently selected date can be changed by the user using the
+ mouse or keyboard, or by the programmer using setSelectedDate().
+
+ \sa selectedDate()
+*/
+
+/*!
+ \fn void QCalendarWidget::currentPageChanged(int year, int month)
+
+ This signal is emitted when the currently shown month is changed.
+ The new \a year and \a month are passed as parameters.
+
+ \sa setCurrentPage()
+*/
+
+/*!
+ \fn void QCalendarWidget::activated(const QDate &date)
+
+ This signal is emitted whenever the user presses the Return or
+ Enter key or double-clicks a \a date in the calendar
+ widget.
+*/
+
+/*!
+ \fn void QCalendarWidget::clicked(const QDate &date)
+
+ This signal is emitted when a mouse button is clicked. The date
+ the mouse was clicked on is specified by \a date. The signal is
+ only emitted when clicked on a valid date, e.g., dates are not
+ outside the minimumDate() and maximumDate(). If the selection mode
+ is NoSelection, this signal will not be emitted.
+
+*/
+
+/*!
+ \property QCalendarWidget::headerVisible
+ \brief whether the navigation bar is shown or not
+
+ \obsolete
+
+ Use navigationBarVisible() instead.
+
+ By default, this property is true.
+*/
+
+/*!
+ \obsolete
+
+ Use setNavigationBarVisible() instead.
+*/
+bool QCalendarWidget::isHeaderVisible() const
+{
+ Q_D(const QCalendarWidget);
+ return d->navBarVisible;
+}
+
+/*!
+ \obsolete
+
+ Use setNavigationBarVisible() instead.
+
+*/
+void QCalendarWidget::setHeaderVisible(bool visible)
+{
+ setNavigationBarVisible(visible);
+}
+
+/*!
+ \property QCalendarWidget::navigationBarVisible
+ \brief whether the navigation bar is shown or not
+
+ \since 4.3
+
+ When this property is true (the default), the next month,
+ previous month, month selection, year selection controls are
+ shown on top.
+
+ When the property is set to false, these controls are hidden.
+*/
+
+void QCalendarWidget::setNavigationBarVisible(bool visible)
+{
+ Q_D(QCalendarWidget);
+ d->navBarVisible = visible;
+ d->cachedSizeHint = QSize();
+ d->navBarBackground->setVisible(visible);
+ updateGeometry();
+}
+
+/*!
+ \reimp
+*/
+bool QCalendarWidget::event(QEvent *event)
+{
+ Q_D(QCalendarWidget);
+ switch (event->type()) {
+ case QEvent::LayoutDirectionChange:
+ d->updateButtonIcons();
+ case QEvent::LocaleChange:
+ d->cachedSizeHint = QSize();
+ d->updateMonthMenuNames();
+ d->updateNavigationBar();
+ d->m_view->updateGeometry();
+ break;
+ case QEvent::FontChange:
+ case QEvent::ApplicationFontChange:
+ d->cachedSizeHint = QSize();
+ d->m_view->updateGeometry();
+ break;
+ case QEvent::StyleChange:
+ d->cachedSizeHint = QSize();
+ d->m_view->updateGeometry();
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
+{
+ Q_D(QCalendarWidget);
+ if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) {
+ QWidget *tlw = window();
+ QWidget *widget = static_cast<QWidget*>(watched);
+ //as we have a event filter on the whole application we first make sure that the top level widget
+ //of both this and the watched widget are the same to decide if we should finish the year edition.
+ if (widget->window() == tlw) {
+ QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos());
+ QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
+ if (!geom.contains(mousePos)) {
+ event->accept();
+ d->_q_yearEditingFinished();
+ setFocus();
+ return true;
+ }
+ }
+ }
+ return QWidget::eventFilter(watched, event);
+}
+
+/*!
+ \reimp
+*/
+void QCalendarWidget::mousePressEvent(QMouseEvent *event)
+{
+ setAttribute(Qt::WA_NoMouseReplay);
+ QWidget::mousePressEvent(event);
+ setFocus();
+}
+
+/*!
+ \reimp
+*/
+void QCalendarWidget::resizeEvent(QResizeEvent * event)
+{
+ Q_D(QCalendarWidget);
+
+ // XXX Should really use a QWidgetStack for yearEdit and yearButton,
+ // XXX here we hide the year edit when the layout is likely to break
+ // XXX the manual positioning of the yearEdit over the yearButton.
+ if(d->yearEdit->isVisible() && event->size().width() != event->oldSize().width())
+ d->_q_yearEditingFinished();
+
+ QWidget::resizeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QCalendarWidget::keyPressEvent(QKeyEvent * event)
+{
+ Q_D(QCalendarWidget);
+ if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape)
+ {
+ d->yearEdit->setValue(yearShown());
+ d->_q_yearEditingFinished();
+ return;
+ }
+ QWidget::keyPressEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "qcalendarwidget.moc"
+#include "moc_qcalendarwidget.cpp"
+
+#endif //QT_NO_CALENDARWIDGET
diff --git a/src/widgets/widgets/qcalendarwidget.h b/src/widgets/widgets/qcalendarwidget.h
new file mode 100644
index 0000000000..a80bae2f49
--- /dev/null
+++ b/src/widgets/widgets/qcalendarwidget.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCALENDARWIDGET_H
+#define QCALENDARWIDGET_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_CALENDARWIDGET
+
+class QDate;
+class QTextCharFormat;
+class QCalendarWidgetPrivate;
+
+class Q_WIDGETS_EXPORT QCalendarWidget : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS(Qt::DayOfWeek)
+ Q_ENUMS(HorizontalHeaderFormat)
+ Q_ENUMS(VerticalHeaderFormat)
+ Q_ENUMS(SelectionMode)
+ Q_PROPERTY(QDate selectedDate READ selectedDate WRITE setSelectedDate)
+ Q_PROPERTY(QDate minimumDate READ minimumDate WRITE setMinimumDate)
+ Q_PROPERTY(QDate maximumDate READ maximumDate WRITE setMaximumDate)
+ Q_PROPERTY(Qt::DayOfWeek firstDayOfWeek READ firstDayOfWeek WRITE setFirstDayOfWeek)
+ Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible)
+ Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
+ Q_PROPERTY(HorizontalHeaderFormat horizontalHeaderFormat READ horizontalHeaderFormat WRITE setHorizontalHeaderFormat)
+ Q_PROPERTY(VerticalHeaderFormat verticalHeaderFormat READ verticalHeaderFormat WRITE setVerticalHeaderFormat)
+ Q_PROPERTY(bool headerVisible READ isHeaderVisible WRITE setHeaderVisible STORED false DESIGNABLE false) // obsolete
+ Q_PROPERTY(bool navigationBarVisible READ isNavigationBarVisible WRITE setNavigationBarVisible)
+ Q_PROPERTY(bool dateEditEnabled READ isDateEditEnabled WRITE setDateEditEnabled)
+ Q_PROPERTY(int dateEditAcceptDelay READ dateEditAcceptDelay WRITE setDateEditAcceptDelay)
+
+public:
+ enum HorizontalHeaderFormat {
+ NoHorizontalHeader,
+ SingleLetterDayNames,
+ ShortDayNames,
+ LongDayNames
+ };
+
+ enum VerticalHeaderFormat {
+ NoVerticalHeader,
+ ISOWeekNumbers
+ };
+
+ enum SelectionMode {
+ NoSelection,
+ SingleSelection
+ };
+
+ explicit QCalendarWidget(QWidget *parent = 0);
+ ~QCalendarWidget();
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ QDate selectedDate() const;
+
+ int yearShown() const;
+ int monthShown() const;
+
+ QDate minimumDate() const;
+ void setMinimumDate(const QDate &date);
+
+ QDate maximumDate() const;
+ void setMaximumDate(const QDate &date);
+
+ Qt::DayOfWeek firstDayOfWeek() const;
+ void setFirstDayOfWeek(Qt::DayOfWeek dayOfWeek);
+
+ // ### Qt 5: eliminate these two
+ bool isHeaderVisible() const;
+ void setHeaderVisible(bool show);
+
+ inline bool isNavigationBarVisible() const { return isHeaderVisible(); }
+
+ bool isGridVisible() const;
+
+ SelectionMode selectionMode() const;
+ void setSelectionMode(SelectionMode mode);
+
+ HorizontalHeaderFormat horizontalHeaderFormat() const;
+ void setHorizontalHeaderFormat(HorizontalHeaderFormat format);
+
+ VerticalHeaderFormat verticalHeaderFormat() const;
+ void setVerticalHeaderFormat(VerticalHeaderFormat format);
+
+ QTextCharFormat headerTextFormat() const;
+ void setHeaderTextFormat(const QTextCharFormat &format);
+
+ QTextCharFormat weekdayTextFormat(Qt::DayOfWeek dayOfWeek) const;
+ void setWeekdayTextFormat(Qt::DayOfWeek dayOfWeek, const QTextCharFormat &format);
+
+ QMap<QDate, QTextCharFormat> dateTextFormat() const;
+ QTextCharFormat dateTextFormat(const QDate &date) const;
+ void setDateTextFormat(const QDate &date, const QTextCharFormat &format);
+
+ bool isDateEditEnabled() const;
+ void setDateEditEnabled(bool enable);
+
+ int dateEditAcceptDelay() const;
+ void setDateEditAcceptDelay(int delay);
+
+protected:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *watched, QEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void resizeEvent(QResizeEvent * event);
+ void keyPressEvent(QKeyEvent * event);
+
+ virtual void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
+ void updateCell(const QDate &date);
+ void updateCells();
+
+public Q_SLOTS:
+ void setSelectedDate(const QDate &date);
+ void setDateRange(const QDate &min, const QDate &max);
+ void setCurrentPage(int year, int month);
+ void setGridVisible(bool show);
+ void setNavigationBarVisible(bool visible);
+ void showNextMonth();
+ void showPreviousMonth();
+ void showNextYear();
+ void showPreviousYear();
+ void showSelectedDate();
+ void showToday();
+
+Q_SIGNALS:
+ void selectionChanged();
+ void clicked(const QDate &date);
+ void activated(const QDate &date);
+ void currentPageChanged(int year, int month);
+
+private:
+ Q_DECLARE_PRIVATE(QCalendarWidget)
+ Q_DISABLE_COPY(QCalendarWidget)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_slotShowDate(const QDate &date))
+ Q_PRIVATE_SLOT(d_func(), void _q_slotChangeDate(const QDate &date))
+ Q_PRIVATE_SLOT(d_func(), void _q_slotChangeDate(const QDate &date, bool changeMonth))
+ Q_PRIVATE_SLOT(d_func(), void _q_editingFinished())
+ Q_PRIVATE_SLOT(d_func(), void _q_prevMonthClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_nextMonthClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_yearEditingFinished())
+ Q_PRIVATE_SLOT(d_func(), void _q_yearClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_monthChanged(QAction *act))
+
+};
+
+#endif // QT_NO_CALENDARWIDGET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCALENDARWIDGET_H
+
diff --git a/src/widgets/widgets/qcheckbox.cpp b/src/widgets/widgets/qcheckbox.cpp
new file mode 100644
index 0000000000..c6d1317147
--- /dev/null
+++ b/src/widgets/widgets/qcheckbox.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcheckbox.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qicon.h"
+#include "qstylepainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qevent.h"
+
+#include "private/qabstractbutton_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QCheckBoxPrivate : public QAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QCheckBox)
+public:
+ QCheckBoxPrivate()
+ : QAbstractButtonPrivate(QSizePolicy::CheckBox), tristate(false), noChange(false),
+ hovering(true), publishedState(Qt::Unchecked) {}
+
+ uint tristate : 1;
+ uint noChange : 1;
+ uint hovering : 1;
+ uint publishedState : 2;
+
+ void init();
+};
+
+/*!
+ \class QCheckBox
+ \brief The QCheckBox widget provides a checkbox with a text label.
+
+ \ingroup basicwidgets
+
+
+ A QCheckBox is an option button that can be switched on (checked) or off
+ (unchecked). Checkboxes are typically used to represent features in an
+ application that can be enabled or disabled without affecting others, but
+ different types of behavior can be implemented. For example, a
+ QButtonGroup can be used to group check buttons logically, allowing
+ exclusive checkboxes. However, QButtonGroup does not provide any visual
+ representation.
+
+ The image below further illustrates the differences between exclusive and
+ non-exclusive checkboxes.
+
+ \table
+ \row \o \inlineimage checkboxes-exclusive.png
+ \o \inlineimage checkboxes-non-exclusive.png
+ \endtable
+
+ Whenever a checkbox is checked or cleared it emits the signal
+ stateChanged(). Connect to this signal if you want to trigger an action
+ each time the checkbox changes state. You can use isChecked() to query
+ whether or not a checkbox is checked.
+
+ In addition to the usual checked and unchecked states, QCheckBox optionally
+ provides a third state to indicate "no change". This is useful whenever you
+ need to give the user the option of neither checking nor unchecking a
+ checkbox. If you need this third state, enable it with setTristate(), and
+ use checkState() to query the current toggle state.
+
+ Just like QPushButton, a checkbox displays text, and optionally a small
+ icon. The icon is set with setIcon(). The text can be set in the
+ constructor or with setText(). A shortcut key can be specified by preceding
+ the preferred character with an ampersand. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qcheckbox.cpp 0
+
+ In this example the shortcut is \e{Alt+A}. See the \l{QShortcut#mnemonic}
+ {QShortcut} documentation for details (to display an actual ampersand,
+ use '&&').
+
+ Important inherited functions: text(), setText(), text(), pixmap(),
+ setPixmap(), accel(), setAccel(), isToggleButton(), setDown(), isDown(),
+ isOn(), checkState(), autoRepeat(), isExclusiveToggle(), group(),
+ setAutoRepeat(), toggle(), pressed(), released(), clicked(), toggled(),
+ checkState(), and stateChanged().
+
+ \table 100%
+ \row
+ \o \inlineimage macintosh-checkbox.png Screenshot of a Macintosh style checkbox
+ \o A checkbox shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row
+ \o \inlineimage windows-checkbox.png Screenshot of a Windows XP style checkbox
+ \o A checkbox shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row
+ \o \inlineimage plastique-checkbox.png Screenshot of a Plastique style checkbox
+ \o A checkbox shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QAbstractButton, QRadioButton, {fowler}{GUI Design Handbook: Check Box}
+*/
+
+/*!
+ \fn void QCheckBox::stateChanged(int state)
+
+ This signal is emitted whenever the check box's state changes, i.e.
+ whenever the user checks or unchecks it.
+
+ \a state contains the check box's new Qt::CheckState.
+*/
+
+/*!
+ \property QCheckBox::tristate
+ \brief whether the checkbox is a tri-state checkbox
+
+ The default is false; i.e. the checkbox has only two states.
+*/
+
+void QCheckBoxPrivate::init()
+{
+ Q_Q(QCheckBox);
+ q->setCheckable(true);
+ q->setMouseTracking(true);
+ q->setForegroundRole(QPalette::WindowText);
+ setLayoutItemMargins(QStyle::SE_CheckBoxLayoutItem);
+}
+
+/*!
+ Initializes \a option with the values from this QCheckBox. This method is
+ useful for subclasses that require a QStyleOptionButton, but do not want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QCheckBox::initStyleOption(QStyleOptionButton *option) const
+{
+ if (!option)
+ return;
+ Q_D(const QCheckBox);
+ option->initFrom(this);
+ if (d->down)
+ option->state |= QStyle::State_Sunken;
+ if (d->tristate && d->noChange)
+ option->state |= QStyle::State_NoChange;
+ else
+ option->state |= d->checked ? QStyle::State_On : QStyle::State_Off;
+ if (testAttribute(Qt::WA_Hover) && underMouse()) {
+ if (d->hovering)
+ option->state |= QStyle::State_MouseOver;
+ else
+ option->state &= ~QStyle::State_MouseOver;
+ }
+ option->text = d->text;
+ option->icon = d->icon;
+ option->iconSize = iconSize();
+}
+
+/*!
+ Constructs a checkbox with the given \a parent, but with no text.
+
+ \a parent is passed on to the QAbstractButton constructor.
+*/
+
+QCheckBox::QCheckBox(QWidget *parent)
+ : QAbstractButton (*new QCheckBoxPrivate, parent)
+{
+ Q_D(QCheckBox);
+ d->init();
+}
+
+/*!
+ Constructs a checkbox with the given \a parent and \a text.
+
+ \a parent is passed on to the QAbstractButton constructor.
+*/
+
+QCheckBox::QCheckBox(const QString &text, QWidget *parent)
+ : QAbstractButton (*new QCheckBoxPrivate, parent)
+{
+ Q_D(QCheckBox);
+ d->init();
+ setText(text);
+}
+
+void QCheckBox::setTristate(bool y)
+{
+ Q_D(QCheckBox);
+ d->tristate = y;
+}
+
+bool QCheckBox::isTristate() const
+{
+ Q_D(const QCheckBox);
+ return d->tristate;
+}
+
+
+/*!
+ Returns the check box's check state. If you do not need tristate support,
+ you can also use \l QAbstractButton::isChecked() which returns a boolean.
+
+ \sa setCheckState() Qt::CheckState
+*/
+Qt::CheckState QCheckBox::checkState() const
+{
+ Q_D(const QCheckBox);
+ if (d->tristate && d->noChange)
+ return Qt::PartiallyChecked;
+ return d->checked ? Qt::Checked : Qt::Unchecked;
+}
+
+/*!
+ Sets the check box's check state to \a state. If you do not need tristate
+ support, you can also use \l QAbstractButton::setChecked() which takes a
+ boolean.
+
+ \sa checkState() Qt::CheckState
+*/
+void QCheckBox::setCheckState(Qt::CheckState state)
+{
+ Q_D(QCheckBox);
+ if (state == Qt::PartiallyChecked) {
+ d->tristate = true;
+ d->noChange = true;
+ } else {
+ d->noChange = false;
+ }
+ d->blockRefresh = true;
+ setChecked(state != Qt::Unchecked);
+ d->blockRefresh = false;
+ d->refresh();
+ if ((uint)state != d->publishedState) {
+ d->publishedState = state;
+ emit stateChanged(state);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+QSize QCheckBox::sizeHint() const
+{
+ Q_D(const QCheckBox);
+ if (d->sizeHint.isValid())
+ return d->sizeHint;
+ ensurePolished();
+ QFontMetrics fm = fontMetrics();
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ QSize sz = style()->itemTextRect(fm, QRect(), Qt::TextShowMnemonic, false,
+ text()).size();
+ if (!opt.icon.isNull())
+ sz = QSize(sz.width() + opt.iconSize.width() + 4, qMax(sz.height(), opt.iconSize.height()));
+ d->sizeHint = (style()->sizeFromContents(QStyle::CT_CheckBox, &opt, sz, this)
+ .expandedTo(QApplication::globalStrut()));
+ return d->sizeHint;
+}
+
+
+/*!
+ \reimp
+*/
+QSize QCheckBox::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ p.drawControl(QStyle::CE_CheckBox, opt);
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QCheckBox);
+ if (testAttribute(Qt::WA_Hover)) {
+ bool hit = false;
+ if (underMouse())
+ hit = hitButton(e->pos());
+
+ if (hit != d->hovering) {
+ update(rect());
+ d->hovering = hit;
+ }
+ }
+
+ QAbstractButton::mouseMoveEvent(e);
+}
+
+
+/*!
+ \reimp
+*/
+bool QCheckBox::hitButton(const QPoint &pos) const
+{
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ return style()->subElementRect(QStyle::SE_CheckBoxClickRect, &opt, this).contains(pos);
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::checkStateSet()
+{
+ Q_D(QCheckBox);
+ d->noChange = false;
+ Qt::CheckState state = checkState();
+ if ((uint)state != d->publishedState) {
+ d->publishedState = state;
+ emit stateChanged(state);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::nextCheckState()
+{
+ Q_D(QCheckBox);
+ if (d->tristate)
+ setCheckState((Qt::CheckState)((checkState() + 1) % 3));
+ else {
+ QAbstractButton::nextCheckState();
+ QCheckBox::checkStateSet();
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QCheckBox::event(QEvent *e)
+{
+ Q_D(QCheckBox);
+ if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->setLayoutItemMargins(QStyle::SE_CheckBoxLayoutItem);
+ return QAbstractButton::event(e);
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QCheckBox::QCheckBox(QWidget *parent, const char* name)
+ : QAbstractButton (*new QCheckBoxPrivate, parent)
+{
+ Q_D(QCheckBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QCheckBox::QCheckBox(const QString &text, QWidget *parent, const char* name)
+ : QAbstractButton (*new QCheckBoxPrivate, parent)
+{
+ Q_D(QCheckBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+ setText(text);
+}
+
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qcheckbox.h b/src/widgets/widgets/qcheckbox.h
new file mode 100644
index 0000000000..b040b13be1
--- /dev/null
+++ b/src/widgets/widgets/qcheckbox.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCHECKBOX_H
+#define QCHECKBOX_H
+
+#include <QtWidgets/qabstractbutton.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QCheckBoxPrivate;
+class QStyleOptionButton;
+
+class Q_WIDGETS_EXPORT QCheckBox : public QAbstractButton
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool tristate READ isTristate WRITE setTristate)
+
+public:
+ explicit QCheckBox(QWidget *parent=0);
+ explicit QCheckBox(const QString &text, QWidget *parent=0);
+
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setTristate(bool y = true);
+ bool isTristate() const;
+
+ Qt::CheckState checkState() const;
+ void setCheckState(Qt::CheckState state);
+
+Q_SIGNALS:
+ void stateChanged(int);
+
+protected:
+ bool event(QEvent *e);
+ bool hitButton(const QPoint &pos) const;
+ void checkStateSet();
+ void nextCheckState();
+ void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void initStyleOption(QStyleOptionButton *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ enum ToggleState {
+ Off = Qt::Unchecked,
+ NoChange = Qt::PartiallyChecked,
+ On = Qt::Checked
+ };
+ inline QT3_SUPPORT ToggleState state() const
+ { return static_cast<QCheckBox::ToggleState>(static_cast<int>(checkState())); }
+ inline QT3_SUPPORT void setState(ToggleState state)
+ { setCheckState(static_cast<Qt::CheckState>(static_cast<int>(state))); }
+ inline QT3_SUPPORT void setNoChange()
+ { setCheckState(Qt::PartiallyChecked); }
+ QT3_SUPPORT_CONSTRUCTOR QCheckBox(QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QCheckBox(const QString &text, QWidget *parent, const char* name);
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QCheckBox)
+ Q_DISABLE_COPY(QCheckBox)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCHECKBOX_H
diff --git a/src/widgets/widgets/qcocoatoolbardelegate_mac.mm b/src/widgets/widgets/qcocoatoolbardelegate_mac.mm
new file mode 100644
index 0000000000..2ced5b3665
--- /dev/null
+++ b/src/widgets/widgets/qcocoatoolbardelegate_mac.mm
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <private/qcocoatoolbardelegate_mac_p.h>
+#ifdef QT_MAC_USE_COCOA
+#include <private/qmainwindowlayout_p.h>
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qcocoaview_mac_p.h>
+#include <private/qwidget_p.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+extern QWidgetPrivate *qt_widget_private(QWidget *widget);
+QT_END_NAMESPACE
+
+QT_FORWARD_DECLARE_CLASS(QMainWindowLayout);
+QT_FORWARD_DECLARE_CLASS(QToolBar);
+QT_FORWARD_DECLARE_CLASS(QCFString);
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaToolBarDelegate)
+
+- (id)initWithMainWindowLayout:(QMainWindowLayout *)layout
+{
+ self = [super init];
+ if (self) {
+ mainWindowLayout = layout;
+ }
+ return self;
+}
+
+- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
+{
+ Q_UNUSED(toolbar);
+ return [NSArray arrayWithObject:@"com.trolltech.qt.nstoolbar-qtoolbar"];
+}
+
+- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
+{
+ return [self toolbarAllowedItemIdentifiers:toolbar];
+}
+
+- (void)toolbarDidRemoveItem:(NSNotification *)notification
+{
+ NSToolbarItem *item = [[notification userInfo] valueForKey:@"item"];
+ mainWindowLayout->unifiedToolbarHash.remove(item);
+ for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
+ if (mainWindowLayout->toolbarItemsCopy.at(i) == item) {
+ // I know about it, so release it.
+ mainWindowLayout->toolbarItemsCopy.removeAt(i);
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.removeAt(i);
+ [item release];
+ break;
+ }
+ }
+}
+
+- (NSToolbarItem *)toolbar:(NSToolbar *)nstoolbar itemForItemIdentifier:(NSString *)itemIdentifier
+ willBeInsertedIntoToolbar:(BOOL)flag
+{
+ Q_UNUSED(flag);
+ Q_UNUSED(nstoolbar);
+ QToolBar *tb = mainWindowLayout->cocoaItemIDToToolbarHash.value(
+ QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(itemIdentifier));
+ NSToolbarItem *item = nil;
+ if (tb) {
+ item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+ mainWindowLayout->unifiedToolbarHash.insert(item, tb);
+ }
+ return item;
+}
+
+- (void)toolbarWillAddItem:(NSNotification *)notification
+{
+ NSToolbarItem *item = [[notification userInfo] valueForKey:@"item"];
+ QToolBar *tb = mainWindowLayout->cocoaItemIDToToolbarHash.value(
+ QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([item itemIdentifier]));
+ if (!tb)
+ return; // I can't really do anything about this.
+ [item retain];
+ [item setView:QT_PREPEND_NAMESPACE(qt_mac_nativeview_for)(tb)];
+
+ NSArray *items = [[qt_mac_window_for(mainWindowLayout->layoutState.mainWindow->window()) toolbar] items];
+ int someIndex = 0;
+ for (NSToolbarItem *i in items) {
+ if (i == item)
+ break;
+ ++someIndex;
+ }
+ mainWindowLayout->toolbarItemsCopy.insert(someIndex, item);
+
+ // This is synchronization code that was needed in Carbon, but may not be needed anymore here.
+ QToolBar *toolbar = mainWindowLayout->unifiedToolbarHash.value(item);
+ if (toolbar) {
+ int toolbarIndex = mainWindowLayout->qtoolbarsInUnifiedToolbarList.indexOf(toolbar);
+ if (someIndex != toolbarIndex) {
+ // Dang, we must be out of sync, rebuild it from the "toolbarItemsCopy"
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.clear();
+ for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
+ // This will either append the correct toolbar or an
+ // null toolbar. This is fine because this list
+ // is really only kept to make sure that things are but in the right order.
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.append(
+ mainWindowLayout->unifiedToolbarHash.value(mainWindowLayout->
+ toolbarItemsCopy.at(i)));
+ }
+ }
+ toolbar->update();
+ }
+}
+
+@end
+#endif // QT_MAC_USE_COCOA
diff --git a/src/widgets/widgets/qcocoatoolbardelegate_mac_p.h b/src/widgets/widgets/qcocoatoolbardelegate_mac_p.h
new file mode 100644
index 0000000000..813d278392
--- /dev/null
+++ b/src/widgets/widgets/qcocoatoolbardelegate_mac_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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 "qmacdefines_mac.h"
+#ifdef QT_MAC_USE_COCOA
+#import <Cocoa/Cocoa.h>
+
+QT_BEGIN_NAMESPACE
+class QMainWindowLayout;
+class QToolBar;
+QT_END_NAMESPACE
+
+@class NSToolbarItem;
+
+@interface QT_MANGLE_NAMESPACE(QCocoaToolBarDelegate) : NSObject {
+ QT_PREPEND_NAMESPACE(QMainWindowLayout) *mainWindowLayout;
+ NSToolbarItem *toolbarItem;
+}
+
+- (id)initWithMainWindowLayout:(QT_PREPEND_NAMESPACE(QMainWindowLayout) *)layout;
+@end
+#endif
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
new file mode 100644
index 0000000000..650227214a
--- /dev/null
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -0,0 +1,3319 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcombobox.h"
+
+#ifndef QT_NO_COMBOBOX
+#include <qstylepainter.h>
+#include <qlineedit.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qlistview.h>
+#include <qtableview.h>
+#include <qitemdelegate.h>
+#include <qmap.h>
+#include <qmenu.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qscrollbar.h>
+#include <qtreeview.h>
+#include <qheaderview.h>
+#include <qmath.h>
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#endif
+#include <private/qapplication_p.h>
+#include <private/qcombobox_p.h>
+#include <private/qabstractitemmodel_p.h>
+#include <private/qabstractscrollarea_p.h>
+#include <private/qsoftkeymanager_p.h>
+#include <qdebug.h>
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#endif
+#if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS) && !defined(QT_NO_STYLE_MAC)
+#include <private/qcore_mac_p.h>
+#include <QMacStyle>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+#ifndef QT_NO_EFFECTS
+# include <private/qeffects_p.h>
+#endif
+#if defined(Q_WS_S60)
+#include "private/qt_s60_p.h"
+#endif
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QComboBoxPrivate::QComboBoxPrivate()
+ : QWidgetPrivate(),
+ model(0),
+ lineEdit(0),
+ container(0),
+ insertPolicy(QComboBox::InsertAtBottom),
+ sizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow),
+ minimumContentsLength(0),
+ shownOnce(false),
+ autoCompletion(true),
+ duplicatesEnabled(false),
+ frame(true),
+ maxVisibleItems(10),
+ maxCount(INT_MAX),
+ modelColumn(0),
+ inserting(false),
+ arrowState(QStyle::State_None),
+ hoverControl(QStyle::SC_None),
+ autoCompletionCaseSensitivity(Qt::CaseInsensitive),
+ indexBeforeChange(-1)
+#ifndef QT_NO_COMPLETER
+ , completer(0)
+#endif
+{
+}
+
+QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QStyleOptionMenuItem menuOption;
+
+ QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu"));
+ QVariant value = index.data(Qt::ForegroundRole);
+ if (value.canConvert<QBrush>()) {
+ resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast<QBrush>(value));
+ resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(value));
+ resolvedpalette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
+ }
+ menuOption.palette = resolvedpalette;
+ menuOption.state = QStyle::State_None;
+ if (mCombo->window()->isActiveWindow())
+ menuOption.state = QStyle::State_Active;
+ if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
+ menuOption.state |= QStyle::State_Enabled;
+ else
+ menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
+ if (option.state & QStyle::State_Selected)
+ menuOption.state |= QStyle::State_Selected;
+ menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
+ menuOption.checked = mCombo->currentIndex() == index.row();
+ if (QComboBoxDelegate::isSeparator(index))
+ menuOption.menuItemType = QStyleOptionMenuItem::Separator;
+ else
+ menuOption.menuItemType = QStyleOptionMenuItem::Normal;
+
+ QVariant variant = index.model()->data(index, Qt::DecorationRole);
+ switch (variant.type()) {
+ case QVariant::Icon:
+ menuOption.icon = qvariant_cast<QIcon>(variant);
+ break;
+ case QVariant::Color: {
+ static QPixmap pixmap(option.decorationSize);
+ pixmap.fill(qvariant_cast<QColor>(variant));
+ menuOption.icon = pixmap;
+ break; }
+ default:
+ menuOption.icon = qvariant_cast<QPixmap>(variant);
+ break;
+ }
+ if (index.data(Qt::BackgroundRole).canConvert<QBrush>()) {
+ menuOption.palette.setBrush(QPalette::All, QPalette::Background,
+ qvariant_cast<QBrush>(index.data(Qt::BackgroundRole)));
+ }
+ menuOption.text = index.model()->data(index, Qt::DisplayRole).toString()
+ .replace(QLatin1Char('&'), QLatin1String("&&"));
+ menuOption.tabWidth = 0;
+ menuOption.maxIconWidth = option.decorationSize.width() + 4;
+ menuOption.menuRect = option.rect;
+ menuOption.rect = option.rect;
+
+ // Make sure fonts set on the combo box also overrides the font for the popup menu.
+ if (mCombo->testAttribute(Qt::WA_SetFont)
+ || mCombo->testAttribute(Qt::WA_MacSmallSize)
+ || mCombo->testAttribute(Qt::WA_MacMiniSize)
+ || mCombo->font() != qt_app_fonts_hash()->value("QComboBox", QFont()))
+ menuOption.font = mCombo->font();
+ else
+ menuOption.font = qt_app_fonts_hash()->value("QComboMenuItem", mCombo->font());
+
+ menuOption.fontMetrics = QFontMetrics(menuOption.font);
+
+ return menuOption;
+}
+
+#ifdef QT_KEYPAD_NAVIGATION
+void QComboBoxPrivate::_q_completerActivated()
+{
+ Q_Q(QComboBox);
+ if ( QApplication::keypadNavigationEnabled()
+ && q->isEditable()
+ && q->completer()
+ && q->completer()->completionMode() == QCompleter::UnfilteredPopupCompletion ) {
+ q->setEditFocus(false);
+ }
+}
+#endif
+
+void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
+{
+ Q_Q(QComboBox);
+ if (arrowState == state)
+ return;
+ arrowState = state;
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ q->update(q->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, q));
+}
+
+void QComboBoxPrivate::_q_modelReset()
+{
+ Q_Q(QComboBox);
+ if (lineEdit) {
+ lineEdit->setText(QString());
+ updateLineEditGeometry();
+ }
+ if (currentIndex.row() != indexBeforeChange)
+ _q_emitCurrentIndexChanged(currentIndex);
+ q->update();
+}
+
+void QComboBoxPrivate::_q_modelDestroyed()
+{
+ model = QAbstractItemModelPrivate::staticEmptyModel();
+}
+
+
+//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
+QRect QComboBoxPrivate::popupGeometry(int screen) const
+{
+#ifdef Q_WS_WIN
+ return QApplication::desktop()->screenGeometry(screen);
+#elif defined Q_WS_X11
+ if (X11->desktopEnvironment == DE_KDE)
+ return QApplication::desktop()->screenGeometry(screen);
+ else
+ return QApplication::desktop()->availableGeometry(screen);
+#else
+ return QApplication::desktop()->availableGeometry(screen);
+#endif
+}
+
+bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)
+{
+
+ Q_Q(QComboBox);
+ QRect lastHoverRect = hoverRect;
+ QStyle::SubControl lastHoverControl = hoverControl;
+ bool doesHover = q->testAttribute(Qt::WA_Hover);
+ if (lastHoverControl != newHoverControl(pos) && doesHover) {
+ q->update(lastHoverRect);
+ q->update(hoverRect);
+ return true;
+ }
+ return !doesHover;
+}
+
+QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QComboBox);
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q);
+ hoverRect = (hoverControl != QStyle::SC_None)
+ ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q)
+ : QRect();
+ return hoverControl;
+}
+
+/*
+ Computes a size hint based on the maximum width
+ for the items in the combobox.
+*/
+int QComboBoxPrivate::computeWidthHint() const
+{
+ Q_Q(const QComboBox);
+
+ int width = 0;
+ const int count = q->count();
+ const int iconWidth = q->iconSize().width() + 4;
+ const QFontMetrics &fontMetrics = q->fontMetrics();
+
+ for (int i = 0; i < count; ++i) {
+ const int textWidth = fontMetrics.width(q->itemText(i));
+ if (q->itemIcon(i).isNull())
+ width = (qMax(width, textWidth));
+ else
+ width = (qMax(width, textWidth + iconWidth));
+ }
+
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ QSize tmp(width, 0);
+ tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q);
+ return tmp.width();
+}
+
+QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const
+{
+ Q_Q(const QComboBox);
+ if (!sh.isValid()) {
+ bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon ? true : false;
+ int count = q->count();
+ QSize iconSize = q->iconSize();
+ const QFontMetrics &fm = q->fontMetrics();
+
+ // text width
+ if (&sh == &sizeHint || minimumContentsLength == 0) {
+ switch (sizeAdjustPolicy) {
+ case QComboBox::AdjustToContents:
+ case QComboBox::AdjustToContentsOnFirstShow:
+ if (count == 0) {
+ sh.rwidth() = 7 * fm.width(QLatin1Char('x'));
+ } else {
+ for (int i = 0; i < count; ++i) {
+ if (!q->itemIcon(i).isNull()) {
+ hasIcon = true;
+ sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width() + iconSize.width() + 4));
+ } else {
+ sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width()));
+ }
+ }
+ }
+ break;
+ case QComboBox::AdjustToMinimumContentsLength:
+ for (int i = 0; i < count && !hasIcon; ++i)
+ hasIcon = !q->itemIcon(i).isNull();
+ default:
+ ;
+ }
+ } else {
+ for (int i = 0; i < count && !hasIcon; ++i)
+ hasIcon = !q->itemIcon(i).isNull();
+ }
+ if (minimumContentsLength > 0)
+ sh.setWidth(qMax(sh.width(), minimumContentsLength * fm.width(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0)));
+
+
+ // height
+ sh.setHeight(qMax(qCeil(QFontMetricsF(fm).height()), 14) + 2);
+ if (hasIcon) {
+ sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
+ }
+
+ // add style and strut values
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q);
+ }
+ return sh.expandedTo(QApplication::globalStrut());
+}
+
+void QComboBoxPrivate::adjustComboBoxSize()
+{
+ viewContainer()->adjustSizeTimer.start(20, container);
+}
+
+void QComboBoxPrivate::updateLayoutDirection()
+{
+ Q_Q(const QComboBox);
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ Qt::LayoutDirection dir = Qt::LayoutDirection(
+ q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q));
+ if (lineEdit)
+ lineEdit->setLayoutDirection(dir);
+ if (container)
+ container->setLayoutDirection(dir);
+}
+
+
+void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent)
+{
+ if (timerEvent->timerId() == adjustSizeTimer.timerId()) {
+ adjustSizeTimer.stop();
+ if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) {
+ combo->updateGeometry();
+ combo->adjustSize();
+ combo->update();
+ }
+ }
+}
+
+void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e)
+{
+ QStyleOptionComboBox opt = comboStyleOption();
+ if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
+ QStyleOption myOpt;
+ myOpt.initFrom(this);
+ QStyleHintReturnMask mask;
+ if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt, this, &mask)) {
+ setMask(mask.region);
+ }
+ } else {
+ clearMask();
+ }
+ QFrame::resizeEvent(e);
+}
+
+void QComboBoxPrivateContainer::leaveEvent(QEvent *)
+{
+// On Mac using the Mac style we want to clear the selection
+// when the mouse moves outside the popup.
+#ifdef Q_WS_MAC
+ QStyleOptionComboBox opt = comboStyleOption();
+ if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo))
+ view->clearSelection();
+#endif
+}
+
+QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
+ : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0)
+{
+ // we need the combobox and itemview
+ Q_ASSERT(parent);
+ Q_ASSERT(itemView);
+
+ setAttribute(Qt::WA_WindowPropagation);
+ setAttribute(Qt::WA_X11NetWmWindowTypeCombo);
+
+ // setup container
+ blockMouseReleaseTimer.setSingleShot(true);
+
+ // we need a vertical layout
+ QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+ layout->setSpacing(0);
+ layout->setMargin(0);
+
+ // set item view
+ setItemView(itemView);
+
+ // add scroller arrows if style needs them
+ QStyleOptionComboBox opt = comboStyleOption();
+ const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
+ if (usePopup) {
+ top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this);
+ bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this);
+ top->hide();
+ bottom->hide();
+ } else {
+ setLineWidth(1);
+ }
+
+ setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
+
+ if (top) {
+ layout->insertWidget(0, top);
+ connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
+ }
+ if (bottom) {
+ layout->addWidget(bottom);
+ connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
+ }
+
+ // Some styles (Mac) have a margin at the top and bottom of the popup.
+ layout->insertSpacing(0, 0);
+ layout->addSpacing(0);
+ updateTopBottomMargin();
+}
+
+void QComboBoxPrivateContainer::scrollItemView(int action)
+{
+#ifndef QT_NO_SCROLLBAR
+ if (view->verticalScrollBar())
+ view->verticalScrollBar()->triggerAction(static_cast<QAbstractSlider::SliderAction>(action));
+#endif
+}
+
+/*
+ Hides or shows the scrollers when we emulate a popupmenu
+*/
+void QComboBoxPrivateContainer::updateScrollers()
+{
+#ifndef QT_NO_SCROLLBAR
+ if (!top || !bottom)
+ return;
+
+ if (isVisible() == false)
+ return;
+
+ QStyleOptionComboBox opt = comboStyleOption();
+ if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) &&
+ view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) {
+
+ bool needTop = view->verticalScrollBar()->value()
+ > (view->verticalScrollBar()->minimum() + spacing());
+ bool needBottom = view->verticalScrollBar()->value()
+ < (view->verticalScrollBar()->maximum() - spacing()*2);
+ if (needTop)
+ top->show();
+ else
+ top->hide();
+ if (needBottom)
+ bottom->show();
+ else
+ bottom->hide();
+ } else {
+ top->hide();
+ bottom->hide();
+ }
+#endif // QT_NO_SCROLLBAR
+}
+
+/*
+ Cleans up when the view is destroyed.
+*/
+void QComboBoxPrivateContainer::viewDestroyed()
+{
+ view = 0;
+ setItemView(new QComboBoxListView());
+}
+
+/*
+ Returns the item view used for the combobox popup.
+*/
+QAbstractItemView *QComboBoxPrivateContainer::itemView() const
+{
+ return view;
+}
+
+/*!
+ Sets the item view to be used for the combobox popup.
+*/
+void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
+{
+ Q_ASSERT(itemView);
+
+ // clean up old one
+ if (view) {
+ view->removeEventFilter(this);
+ view->viewport()->removeEventFilter(this);
+#ifndef QT_NO_SCROLLBAR
+ disconnect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(updateScrollers()));
+ disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
+ this, SLOT(updateScrollers()));
+#endif
+ disconnect(view, SIGNAL(destroyed()),
+ this, SLOT(viewDestroyed()));
+
+ delete view;
+ view = 0;
+ }
+
+ // setup the item view
+ view = itemView;
+ view->setParent(this);
+ view->setAttribute(Qt::WA_MacShowFocusRect, false);
+ qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 2 : 0, view);
+ view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ view->installEventFilter(this);
+ view->viewport()->installEventFilter(this);
+ view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ QStyleOptionComboBox opt = comboStyleOption();
+ const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
+#ifndef QT_NO_SCROLLBAR
+#ifndef Q_WS_S60
+ if (usePopup)
+ view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+#endif
+#endif
+ if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
+ usePopup) {
+ view->setMouseTracking(true);
+ }
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+ view->setFrameStyle(QFrame::NoFrame);
+ view->setLineWidth(0);
+ view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+#ifndef QT_NO_SCROLLBAR
+ connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
+ this, SLOT(updateScrollers()));
+ connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
+ this, SLOT(updateScrollers()));
+#endif
+ connect(view, SIGNAL(destroyed()),
+ this, SLOT(viewDestroyed()));
+
+#ifdef QT_SOFTKEYS_ENABLED
+ selectAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::SelectSoftKey, Qt::Key_Select, itemView);
+ cancelAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::CancelSoftKey, Qt::Key_Escape, itemView);
+ addAction(selectAction);
+ addAction(cancelAction);
+#endif
+}
+
+/*!
+ Returns the spacing between the items in the view.
+*/
+int QComboBoxPrivateContainer::spacing() const
+{
+ QListView *lview = qobject_cast<QListView*>(view);
+ if (lview)
+ return lview->spacing();
+#ifndef QT_NO_TABLEVIEW
+ QTableView *tview = qobject_cast<QTableView*>(view);
+ if (tview)
+ return tview->showGrid() ? 1 : 0;
+#endif
+ return 0;
+}
+
+void QComboBoxPrivateContainer::updateTopBottomMargin()
+{
+ if (!layout() || layout()->count() < 1)
+ return;
+
+ QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
+ if (!boxLayout)
+ return;
+
+ const QStyleOptionComboBox opt = comboStyleOption();
+ const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
+ const int margin = usePopup ? combo->style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, combo) : 0;
+
+ QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem();
+ if (topSpacer)
+ topSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+ QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem();
+ if (bottomSpacer && bottomSpacer != topSpacer)
+ bottomSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+ boxLayout->invalidate();
+}
+
+void QComboBoxPrivateContainer::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::StyleChange) {
+ QStyleOptionComboBox opt = comboStyleOption();
+ view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
+ combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo));
+ setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
+#ifdef QT_SOFTKEYS_ENABLED
+ } else if (e->type() == QEvent::LanguageChange) {
+ selectAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::SelectSoftKey));
+ cancelAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::CancelSoftKey));
+#endif
+ }
+
+ QWidget::changeEvent(e);
+}
+
+
+bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ switch (static_cast<QKeyEvent*>(e)->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+#endif
+ if (view->currentIndex().isValid() && (view->currentIndex().flags() & Qt::ItemIsEnabled) ) {
+ combo->hidePopup();
+ emit itemSelected(view->currentIndex());
+ }
+ return true;
+ case Qt::Key_Down:
+ if (!(static_cast<QKeyEvent*>(e)->modifiers() & Qt::AltModifier))
+ break;
+ // fall through
+ case Qt::Key_F4:
+ case Qt::Key_Escape:
+ combo->hidePopup();
+ return true;
+ default:
+ break;
+ }
+ break;
+ case QEvent::MouseMove:
+ if (isVisible()) {
+ QMouseEvent *m = static_cast<QMouseEvent *>(e);
+ QWidget *widget = static_cast<QWidget *>(o);
+ QPoint vector = widget->mapToGlobal(m->pos()) - initialClickPosition;
+ if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive())
+ blockMouseReleaseTimer.stop();
+ QModelIndex indexUnderMouse = view->indexAt(m->pos());
+ if (indexUnderMouse.isValid()
+ && !QComboBoxDelegate::isSeparator(indexUnderMouse)) {
+ view->setCurrentIndex(indexUnderMouse);
+ }
+ }
+ break;
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *m = static_cast<QMouseEvent *>(e);
+ if (isVisible() && view->rect().contains(m->pos()) && view->currentIndex().isValid()
+ && !blockMouseReleaseTimer.isActive()
+ && (view->currentIndex().flags() & Qt::ItemIsEnabled)
+ && (view->currentIndex().flags() & Qt::ItemIsSelectable)) {
+ combo->hidePopup();
+ emit itemSelected(view->currentIndex());
+ return true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return QFrame::eventFilter(o, e);
+}
+
+void QComboBoxPrivateContainer::showEvent(QShowEvent *)
+{
+ combo->update();
+}
+
+void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
+{
+ emit resetButton();
+ combo->update();
+#ifndef QT_NO_GRAPHICSVIEW
+ // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly.
+ // Hiding/showing the QComboBox after this will unexpectedly show the popup as well.
+ // Re-hiding the popup container makes sure it is explicitly hidden.
+ if (QGraphicsProxyWidget *proxy = graphicsProxyWidget())
+ proxy->hide();
+#endif
+}
+
+void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
+{
+
+ QStyleOptionComboBox opt = comboStyleOption();
+ opt.subControls = QStyle::SC_All;
+ opt.activeSubControls = QStyle::SC_ComboBoxArrow;
+ QStyle::SubControl sc = combo->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
+ combo->mapFromGlobal(e->globalPos()),
+ combo);
+ if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow)
+ || (!combo->isEditable() && sc != QStyle::SC_None))
+ setAttribute(Qt::WA_NoMouseReplay);
+ combo->hidePopup();
+}
+
+void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_UNUSED(e);
+ if (!blockMouseReleaseTimer.isActive()){
+ combo->hidePopup();
+ emit resetButton();
+ }
+}
+
+QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
+{
+ // ### This should use QComboBox's initStyleOption(), but it's protected
+ // perhaps, we could cheat by having the QCombo private instead?
+ QStyleOptionComboBox opt;
+ opt.initFrom(combo);
+ opt.subControls = QStyle::SC_All;
+ opt.activeSubControls = QStyle::SC_None;
+ opt.editable = combo->isEditable();
+ return opt;
+}
+
+/*!
+ \enum QComboBox::InsertPolicy
+
+ This enum specifies what the QComboBox should do when a new string is
+ entered by the user.
+
+ \value NoInsert The string will not be inserted into the combobox.
+ \value InsertAtTop The string will be inserted as the first item in the combobox.
+ \value InsertAtCurrent The current item will be \e replaced by the string.
+ \value InsertAtBottom The string will be inserted after the last item in the combobox.
+ \value InsertAfterCurrent The string is inserted after the current item in the combobox.
+ \value InsertBeforeCurrent The string is inserted before the current item in the combobox.
+ \value InsertAlphabetically The string is inserted in the alphabetic order in the combobox.
+ \omitvalue NoInsertion
+ \omitvalue AtTop
+ \omitvalue AtCurrent
+ \omitvalue AtBottom
+ \omitvalue AfterCurrent
+ \omitvalue BeforeCurrent
+*/
+
+/*!
+ \enum QComboBox::SizeAdjustPolicy
+
+ This enum specifies how the size hint of the QComboBox should
+ adjust when new content is added or content changes.
+
+ \value AdjustToContents The combobox will always adjust to the contents
+ \value AdjustToContentsOnFirstShow The combobox will adjust to its contents the first time it is shown.
+ \value AdjustToMinimumContentsLength Use AdjustToContents or AdjustToContentsOnFirstShow instead.
+ \value AdjustToMinimumContentsLengthWithIcon The combobox will adjust to \l minimumContentsLength plus space for an icon. For performance reasons use this policy on large models.
+*/
+
+/*!
+ \fn void QComboBox::activated(int index)
+
+ This signal is sent when the user chooses an item in the combobox.
+ The item's \a index is passed. Note that this signal is sent even
+ when the choice is not changed. If you need to know when the
+ choice actually changes, use signal currentIndexChanged().
+
+*/
+
+/*!
+ \fn void QComboBox::activated(const QString &text)
+
+ This signal is sent when the user chooses an item in the combobox.
+ The item's \a text is passed. Note that this signal is sent even
+ when the choice is not changed. If you need to know when the
+ choice actually changes, use signal currentIndexChanged().
+
+*/
+
+/*!
+ \fn void QComboBox::highlighted(int index)
+
+ This signal is sent when an item in the combobox popup list is
+ highlighted by the user. The item's \a index is passed.
+*/
+
+/*!
+ \fn void QComboBox::highlighted(const QString &text)
+
+ This signal is sent when an item in the combobox popup list is
+ highlighted by the user. The item's \a text is passed.
+*/
+
+/*!
+ \fn void QComboBox::currentIndexChanged(int index)
+ \since 4.1
+
+ This signal is sent whenever the currentIndex in the combobox
+ changes either through user interaction or programmatically. The
+ item's \a index is passed or -1 if the combobox becomes empty or the
+ currentIndex was reset.
+*/
+
+/*!
+ \fn void QComboBox::currentIndexChanged(const QString &text)
+ \since 4.1
+
+ This signal is sent whenever the currentIndex in the combobox
+ changes either through user interaction or programmatically. The
+ item's \a text is passed.
+*/
+
+/*!
+ Constructs a combobox with the given \a parent, using the default
+ model QStandardItemModel.
+*/
+QComboBox::QComboBox(QWidget *parent)
+ : QWidget(*new QComboBoxPrivate(), parent, 0)
+{
+ Q_D(QComboBox);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
+ : QWidget(dd, parent, 0)
+{
+ Q_D(QComboBox);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QComboBox::QComboBox(QWidget *parent, const char *name)
+ : QWidget(*new QComboBoxPrivate(), parent, 0)
+{
+ Q_D(QComboBox);
+ d->init();
+ setObjectName(QString::fromAscii(name));
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QComboBox::QComboBox(bool rw, QWidget *parent, const char *name)
+ : QWidget(*new QComboBoxPrivate(), parent, 0)
+{
+ Q_D(QComboBox);
+ d->init();
+ setEditable(rw);
+ setObjectName(QString::fromAscii(name));
+}
+
+#endif //QT3_SUPPORT
+
+/*!
+ \class QComboBox
+ \brief The QComboBox widget is a combined button and popup list.
+
+ \ingroup basicwidgets
+
+
+ A QComboBox provides a means of presenting a list of options to the user
+ in a way that takes up the minimum amount of screen space.
+
+ A combobox is a selection widget that displays the current item,
+ and can pop up a list of selectable items. A combobox may be editable,
+ allowing the user to modify each item in the list.
+
+ Comboboxes can contain pixmaps as well as strings; the
+ insertItem() and setItemText() functions are suitably overloaded.
+ For editable comboboxes, the function clearEditText() is provided,
+ to clear the displayed string without changing the combobox's
+ contents.
+
+ There are two signals emitted if the current item of a combobox
+ changes, currentIndexChanged() and activated().
+ currentIndexChanged() is always emitted regardless if the change
+ was done programmatically or by user interaction, while
+ activated() is only emitted when the change is caused by user
+ interaction. The highlighted() signal is emitted when the user
+ highlights an item in the combobox popup list. All three signals
+ exist in two versions, one with a QString argument and one with an
+ \c int argument. If the user selects or highlights a pixmap, only
+ the \c int signals are emitted. Whenever the text of an editable
+ combobox is changed the editTextChanged() signal is emitted.
+
+ When the user enters a new string in an editable combobox, the
+ widget may or may not insert it, and it can insert it in several
+ locations. The default policy is is \l AtBottom but you can change
+ this using setInsertPolicy().
+
+ It is possible to constrain the input to an editable combobox
+ using QValidator; see setValidator(). By default, any input is
+ accepted.
+
+ A combobox can be populated using the insert functions,
+ insertItem() and insertItems() for example. Items can be
+ changed with setItemText(). An item can be removed with
+ removeItem() and all items can be removed with clear(). The text
+ of the current item is returned by currentText(), and the text of
+ a numbered item is returned with text(). The current item can be
+ set with setCurrentIndex(). The number of items in the combobox is
+ returned by count(); the maximum number of items can be set with
+ setMaxCount(). You can allow editing using setEditable(). For
+ editable comboboxes you can set auto-completion using
+ setCompleter() and whether or not the user can add duplicates
+ is set with setDuplicatesEnabled().
+
+ QComboBox uses the \l{Model/View Programming}{model/view
+ framework} for its popup list and to store its items. By default
+ a QStandardItemModel stores the items and a QListView subclass
+ displays the popuplist. You can access the model and view directly
+ (with model() and view()), but QComboBox also provides functions
+ to set and get item data (e.g., setItemData() and itemText()). You
+ can also set a new model and view (with setModel() and setView()).
+ For the text and icon in the combobox label, the data in the model
+ that has the Qt::DisplayRole and Qt::DecorationRole is used. Note
+ that you cannot alter the \l{QAbstractItemView::}{SelectionMode}
+ of the view(), e.g., by using
+ \l{QAbstractItemView::}{setSelectionMode()}.
+
+ \image qstyle-comboboxes.png Comboboxes in the different built-in styles.
+
+ \sa QLineEdit, QSpinBox, QRadioButton, QButtonGroup,
+ {fowler}{GUI Design Handbook: Combo Box, Drop-Down List Box}
+*/
+
+void QComboBoxPrivate::init()
+{
+ Q_Q(QComboBox);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,
+ QSizePolicy::ComboBox));
+ setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
+ q->setModel(new QStandardItemModel(0, 1, q));
+ if (!q->isEditable())
+ q->setAttribute(Qt::WA_InputMethodEnabled, false);
+ else
+ q->setAttribute(Qt::WA_InputMethodEnabled);
+}
+
+QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
+{
+ if (container)
+ return container;
+
+ Q_Q(QComboBox);
+ container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q);
+ container->itemView()->setModel(model);
+ container->itemView()->setTextElideMode(Qt::ElideMiddle);
+ updateDelegate(true);
+ updateLayoutDirection();
+ updateViewContainerPaletteAndOpacity();
+ QObject::connect(container, SIGNAL(itemSelected(QModelIndex)),
+ q, SLOT(_q_itemSelected(QModelIndex)));
+ QObject::connect(container->itemView()->selectionModel(),
+ SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ q, SLOT(_q_emitHighlighted(QModelIndex)));
+ QObject::connect(container, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
+ return container;
+}
+
+
+void QComboBoxPrivate::_q_resetButton()
+{
+ updateArrow(QStyle::State_None);
+}
+
+void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ Q_Q(QComboBox);
+ if (inserting || topLeft.parent() != root)
+ return;
+
+ if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
+ sizeHint = QSize();
+ adjustComboBoxSize();
+ q->updateGeometry();
+ }
+
+ if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
+ if (lineEdit) {
+ lineEdit->setText(q->itemText(currentIndex.row()));
+ updateLineEditGeometry();
+ }
+ q->update();
+ }
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(q, 0, QAccessible::NameChanged);
+#endif
+}
+
+void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_Q(QComboBox);
+ if (inserting || parent != root)
+ return;
+
+ if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
+ sizeHint = QSize();
+ adjustComboBoxSize();
+ q->updateGeometry();
+ }
+
+ // set current index if combo was previously empty
+ if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid()) {
+ q->setCurrentIndex(0);
+ // need to emit changed if model updated index "silently"
+ } else if (currentIndex.row() != indexBeforeChange) {
+ q->update();
+ _q_emitCurrentIndexChanged(currentIndex);
+ }
+}
+
+void QComboBoxPrivate::_q_updateIndexBeforeChange()
+{
+ indexBeforeChange = currentIndex.row();
+}
+
+void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
+{
+ Q_Q(QComboBox);
+ if (parent != root)
+ return;
+
+ if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
+ sizeHint = QSize();
+ adjustComboBoxSize();
+ q->updateGeometry();
+ }
+
+ // model has changed the currentIndex
+ if (currentIndex.row() != indexBeforeChange) {
+ if (!currentIndex.isValid() && q->count()) {
+ q->setCurrentIndex(qMin(q->count() - 1, qMax(indexBeforeChange, 0)));
+ return;
+ }
+ if (lineEdit) {
+ lineEdit->setText(q->itemText(currentIndex.row()));
+ updateLineEditGeometry();
+ }
+ q->update();
+ _q_emitCurrentIndexChanged(currentIndex);
+ }
+}
+
+
+void QComboBoxPrivate::updateViewContainerPaletteAndOpacity()
+{
+ if (!container)
+ return;
+ Q_Q(QComboBox);
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+#ifndef QT_NO_MENU
+ if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
+ QMenu menu;
+ menu.ensurePolished();
+ container->setPalette(menu.palette());
+ container->setWindowOpacity(menu.windowOpacity());
+ } else
+#endif
+ {
+ container->setPalette(q->palette());
+ container->setWindowOpacity(1.0);
+ }
+ if (lineEdit)
+ lineEdit->setPalette(q->palette());
+}
+
+/*!
+ Initialize \a option with the values from this QComboBox. This method
+ is useful for subclasses when they need a QStyleOptionComboBox, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QComboBox::initStyleOption(QStyleOptionComboBox *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QComboBox);
+ option->initFrom(this);
+ option->editable = isEditable();
+ option->frame = d->frame;
+ if (hasFocus() && !option->editable)
+ option->state |= QStyle::State_Selected;
+ option->subControls = QStyle::SC_All;
+ if (d->arrowState == QStyle::State_Sunken) {
+ option->activeSubControls = QStyle::SC_ComboBoxArrow;
+ option->state |= d->arrowState;
+ } else {
+ option->activeSubControls = d->hoverControl;
+ }
+ if (d->currentIndex.isValid()) {
+ option->currentText = currentText();
+ option->currentIcon = d->itemIcon(d->currentIndex);
+ }
+ option->iconSize = iconSize();
+ if (d->container && d->container->isVisible())
+ option->state |= QStyle::State_On;
+}
+
+void QComboBoxPrivate::updateLineEditGeometry()
+{
+ if (!lineEdit)
+ return;
+
+ Q_Q(QComboBox);
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ QRect editRect = q->style()->subControlRect(QStyle::CC_ComboBox, &opt,
+ QStyle::SC_ComboBoxEditField, q);
+ if (!q->itemIcon(q->currentIndex()).isNull()) {
+ QRect comboRect(editRect);
+ editRect.setWidth(editRect.width() - q->iconSize().width() - 4);
+ editRect = QStyle::alignedRect(q->layoutDirection(), Qt::AlignRight,
+ editRect.size(), comboRect);
+ }
+ lineEdit->setGeometry(editRect);
+}
+
+Qt::MatchFlags QComboBoxPrivate::matchFlags() const
+{
+ // Base how duplicates are determined on the autocompletion case sensitivity
+ Qt::MatchFlags flags = Qt::MatchFixedString;
+#ifndef QT_NO_COMPLETER
+ if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive)
+#endif
+ flags |= Qt::MatchCaseSensitive;
+ return flags;
+}
+
+
+void QComboBoxPrivate::_q_editingFinished()
+{
+ Q_Q(QComboBox);
+ if (lineEdit && !lineEdit->text().isEmpty()) {
+ //here we just check if the current item was entered
+ const int index = q_func()->findText(lineEdit->text(), matchFlags());
+ if (index != -1 && itemText(currentIndex) != lineEdit->text()) {
+ q->setCurrentIndex(index);
+ emitActivated(currentIndex);
+ }
+ }
+
+}
+
+void QComboBoxPrivate::_q_returnPressed()
+{
+ Q_Q(QComboBox);
+ if (lineEdit && !lineEdit->text().isEmpty()) {
+ if (q->count() >= maxCount && !(this->insertPolicy == QComboBox::InsertAtCurrent))
+ return;
+ lineEdit->deselect();
+ lineEdit->end(false);
+ QString text = lineEdit->text();
+ // check for duplicates (if not enabled) and quit
+ int index = -1;
+ if (!duplicatesEnabled) {
+ index = q->findText(text, matchFlags());
+ if (index != -1) {
+ q->setCurrentIndex(index);
+ emitActivated(currentIndex);
+ return;
+ }
+ }
+ switch (insertPolicy) {
+ case QComboBox::InsertAtTop:
+ index = 0;
+ break;
+ case QComboBox::InsertAtBottom:
+ index = q->count();
+ break;
+ case QComboBox::InsertAtCurrent:
+ case QComboBox::InsertAfterCurrent:
+ case QComboBox::InsertBeforeCurrent:
+ if (!q->count() || !currentIndex.isValid())
+ index = 0;
+ else if (insertPolicy == QComboBox::InsertAtCurrent)
+ q->setItemText(q->currentIndex(), text);
+ else if (insertPolicy == QComboBox::InsertAfterCurrent)
+ index = q->currentIndex() + 1;
+ else if (insertPolicy == QComboBox::InsertBeforeCurrent)
+ index = q->currentIndex();
+ break;
+ case QComboBox::InsertAlphabetically:
+ index = 0;
+ for (int i=0; i< q->count(); i++, index++ ) {
+ if (text.toLower() < q->itemText(i).toLower())
+ break;
+ }
+ break;
+ case QComboBox::NoInsert:
+ default:
+ break;
+ }
+ if (index >= 0) {
+ q->insertItem(index, text);
+ q->setCurrentIndex(index);
+ emitActivated(currentIndex);
+ }
+ }
+}
+
+void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item)
+{
+ Q_Q(QComboBox);
+ if (item != currentIndex) {
+ setCurrentIndex(item);
+ } else if (lineEdit) {
+ lineEdit->selectAll();
+ lineEdit->setText(q->itemText(currentIndex.row()));
+ }
+ emitActivated(currentIndex);
+}
+
+void QComboBoxPrivate::emitActivated(const QModelIndex &index)
+{
+ Q_Q(QComboBox);
+ if (!index.isValid())
+ return;
+ QString text(itemText(index));
+ emit q->activated(index.row());
+ emit q->activated(text);
+}
+
+void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index)
+{
+ Q_Q(QComboBox);
+ if (!index.isValid())
+ return;
+ QString text(itemText(index));
+ emit q->highlighted(index.row());
+ emit q->highlighted(text);
+}
+
+void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index)
+{
+ Q_Q(QComboBox);
+ emit q->currentIndexChanged(index.row());
+ emit q->currentIndexChanged(itemText(index));
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(q, 0, QAccessible::NameChanged);
+#endif
+}
+
+QString QComboBoxPrivate::itemText(const QModelIndex &index) const
+{
+ return index.isValid() ? model->data(index, itemRole()).toString() : QString();
+}
+
+int QComboBoxPrivate::itemRole() const
+{
+ return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole;
+}
+
+/*!
+ Destroys the combobox.
+*/
+QComboBox::~QComboBox()
+{
+ // ### check delegateparent and delete delegate if us?
+ Q_D(QComboBox);
+
+ QT_TRY {
+ disconnect(d->model, SIGNAL(destroyed()),
+ this, SLOT(_q_modelDestroyed()));
+ } QT_CATCH(...) {
+ ; // objects can't throw in destructor
+ }
+}
+
+/*!
+ \property QComboBox::maxVisibleItems
+ \brief the maximum allowed size on screen of the combo box, measured in items
+
+ By default, this property has a value of 10.
+
+ \note This property is ignored for non-editable comboboxes in styles that returns
+ true for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style.
+*/
+int QComboBox::maxVisibleItems() const
+{
+ Q_D(const QComboBox);
+ return d->maxVisibleItems;
+}
+
+void QComboBox::setMaxVisibleItems(int maxItems)
+{
+ Q_D(QComboBox);
+ if (maxItems < 0) {
+ qWarning("QComboBox::setMaxVisibleItems: "
+ "Invalid max visible items (%d) must be >= 0", maxItems);
+ return;
+ }
+ d->maxVisibleItems = maxItems;
+}
+
+/*!
+ \property QComboBox::count
+ \brief the number of items in the combobox
+
+ By default, for an empty combo box, this property has a value of 0.
+*/
+int QComboBox::count() const
+{
+ Q_D(const QComboBox);
+ return d->model->rowCount(d->root);
+}
+
+/*!
+ \property QComboBox::maxCount
+ \brief the maximum number of items allowed in the combobox
+
+ \note If you set the maximum number to be less then the current
+ amount of items in the combobox, the extra items will be
+ truncated. This also applies if you have set an external model on
+ the combobox.
+
+ By default, this property's value is derived from the highest
+ signed integer available (typically 2147483647).
+*/
+void QComboBox::setMaxCount(int max)
+{
+ Q_D(QComboBox);
+ if (max < 0) {
+ qWarning("QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max);
+ return;
+ }
+
+ if (max < count())
+ d->model->removeRows(max, count() - max, d->root);
+
+ d->maxCount = max;
+}
+
+int QComboBox::maxCount() const
+{
+ Q_D(const QComboBox);
+ return d->maxCount;
+}
+
+#ifndef QT_NO_COMPLETER
+
+/*!
+ \property QComboBox::autoCompletion
+ \brief whether the combobox provides auto-completion for editable items
+ \since 4.1
+ \obsolete
+
+ Use setCompleter() instead.
+
+ By default, this property is true.
+
+ \sa editable
+*/
+
+/*!
+ \obsolete
+
+ Use setCompleter() instead.
+*/
+bool QComboBox::autoCompletion() const
+{
+ Q_D(const QComboBox);
+ return d->autoCompletion;
+}
+
+/*!
+ \obsolete
+
+ Use setCompleter() instead.
+*/
+void QComboBox::setAutoCompletion(bool enable)
+{
+ Q_D(QComboBox);
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !enable && isEditable())
+ qWarning("QComboBox::setAutoCompletion: auto completion is mandatory when combo box editable");
+#endif
+
+ d->autoCompletion = enable;
+ if (!d->lineEdit)
+ return;
+ if (enable) {
+ if (d->lineEdit->completer())
+ return;
+ d->completer = new QCompleter(d->model, d->lineEdit);
+ d->completer->setCaseSensitivity(d->autoCompletionCaseSensitivity);
+ d->completer->setCompletionMode(QCompleter::InlineCompletion);
+ d->completer->setCompletionColumn(d->modelColumn);
+ d->lineEdit->setCompleter(d->completer);
+ d->completer->setWidget(this);
+ } else {
+ d->lineEdit->setCompleter(0);
+ }
+}
+
+/*!
+ \property QComboBox::autoCompletionCaseSensitivity
+ \brief whether string comparisons are case-sensitive or case-insensitive for auto-completion
+ \obsolete
+
+ By default, this property is Qt::CaseInsensitive.
+
+ Use setCompleter() instead. Case sensitivity of the auto completion can be
+ changed using QCompleter::setCaseSensitivity().
+
+ \sa autoCompletion
+*/
+
+/*!
+ \obsolete
+
+ Use setCompleter() and QCompleter::setCaseSensitivity() instead.
+*/
+Qt::CaseSensitivity QComboBox::autoCompletionCaseSensitivity() const
+{
+ Q_D(const QComboBox);
+ return d->autoCompletionCaseSensitivity;
+}
+
+/*!
+ \obsolete
+
+ Use setCompleter() and QCompleter::setCaseSensitivity() instead.
+*/
+void QComboBox::setAutoCompletionCaseSensitivity(Qt::CaseSensitivity sensitivity)
+{
+ Q_D(QComboBox);
+ d->autoCompletionCaseSensitivity = sensitivity;
+ if (d->lineEdit && d->lineEdit->completer())
+ d->lineEdit->completer()->setCaseSensitivity(sensitivity);
+}
+
+#endif // QT_NO_COMPLETER
+
+/*!
+ \property QComboBox::duplicatesEnabled
+ \brief whether the user can enter duplicate items into the combobox
+
+ Note that it is always possible to programmatically insert duplicate items into the
+ combobox.
+
+ By default, this property is false (duplicates are not allowed).
+*/
+bool QComboBox::duplicatesEnabled() const
+{
+ Q_D(const QComboBox);
+ return d->duplicatesEnabled;
+}
+
+void QComboBox::setDuplicatesEnabled(bool enable)
+{
+ Q_D(QComboBox);
+ d->duplicatesEnabled = enable;
+}
+
+/*! \fn int QComboBox::findText(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly|Qt::MatchCaseSensitive) const
+
+ Returns the index of the item containing the given \a text; otherwise
+ returns -1.
+
+ The \a flags specify how the items in the combobox are searched.
+*/
+
+/*!
+ Returns the index of the item containing the given \a data for the
+ given \a role; otherwise returns -1.
+
+ The \a flags specify how the items in the combobox are searched.
+*/
+int QComboBox::findData(const QVariant &data, int role, Qt::MatchFlags flags) const
+{
+ Q_D(const QComboBox);
+ QModelIndexList result;
+ QModelIndex start = d->model->index(0, d->modelColumn, d->root);
+ result = d->model->match(start, role, data, 1, flags);
+ if (result.isEmpty())
+ return -1;
+ return result.first().row();
+}
+
+/*!
+ \property QComboBox::insertPolicy
+ \brief the policy used to determine where user-inserted items should
+ appear in the combobox
+
+ The default value is \l AtBottom, indicating that new items will appear
+ at the bottom of the list of items.
+
+ \sa InsertPolicy
+*/
+
+QComboBox::InsertPolicy QComboBox::insertPolicy() const
+{
+ Q_D(const QComboBox);
+ return d->insertPolicy;
+}
+
+void QComboBox::setInsertPolicy(InsertPolicy policy)
+{
+ Q_D(QComboBox);
+ d->insertPolicy = policy;
+}
+
+/*!
+ \property QComboBox::sizeAdjustPolicy
+ \brief the policy describing how the size of the combobox changes
+ when the content changes
+
+ The default value is \l AdjustToContentsOnFirstShow.
+
+ \sa SizeAdjustPolicy
+*/
+
+QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy() const
+{
+ Q_D(const QComboBox);
+ return d->sizeAdjustPolicy;
+}
+
+void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy)
+{
+ Q_D(QComboBox);
+ if (policy == d->sizeAdjustPolicy)
+ return;
+
+ d->sizeAdjustPolicy = policy;
+ d->sizeHint = QSize();
+ d->adjustComboBoxSize();
+ updateGeometry();
+}
+
+/*!
+ \property QComboBox::minimumContentsLength
+ \brief the minimum number of characters that should fit into the combobox.
+
+ The default value is 0.
+
+ If this property is set to a positive value, the
+ minimumSizeHint() and sizeHint() take it into account.
+
+ \sa sizeAdjustPolicy
+*/
+int QComboBox::minimumContentsLength() const
+{
+ Q_D(const QComboBox);
+ return d->minimumContentsLength;
+}
+
+void QComboBox::setMinimumContentsLength(int characters)
+{
+ Q_D(QComboBox);
+ if (characters == d->minimumContentsLength || characters < 0)
+ return;
+
+ d->minimumContentsLength = characters;
+
+ if (d->sizeAdjustPolicy == AdjustToContents
+ || d->sizeAdjustPolicy == AdjustToMinimumContentsLength
+ || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) {
+ d->sizeHint = QSize();
+ d->adjustComboBoxSize();
+ updateGeometry();
+ }
+}
+
+/*!
+ \property QComboBox::iconSize
+ \brief the size of the icons shown in the combobox.
+
+ Unless explicitly set this returns the default value of the
+ current style. This size is the maximum size that icons can have;
+ icons of smaller size are not scaled up.
+*/
+
+QSize QComboBox::iconSize() const
+{
+ Q_D(const QComboBox);
+ if (d->iconSize.isValid())
+ return d->iconSize;
+
+ int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ return QSize(iconWidth, iconWidth);
+}
+
+void QComboBox::setIconSize(const QSize &size)
+{
+ Q_D(QComboBox);
+ if (size == d->iconSize)
+ return;
+
+ view()->setIconSize(size);
+ d->iconSize = size;
+ d->sizeHint = QSize();
+ updateGeometry();
+}
+
+/*!
+ \property QComboBox::editable
+ \brief whether the combo box can be edited by the user
+
+ By default, this property is false.
+*/
+bool QComboBox::isEditable() const
+{
+ Q_D(const QComboBox);
+ return d->lineEdit != 0;
+}
+
+/*! \internal
+ update the default delegate
+ depending on the style's SH_ComboBox_Popup hint, we use a different default delegate.
+
+ but we do not change the delegate is the combobox use a custom delegate,
+ unless \a force is set to true.
+ */
+void QComboBoxPrivate::updateDelegate(bool force)
+{
+ Q_Q(QComboBox);
+ QStyleOptionComboBox opt;
+ q->initStyleOption(&opt);
+ if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
+ if (force || qobject_cast<QComboBoxDelegate *>(q->itemDelegate()))
+ q->setItemDelegate(new QComboMenuDelegate(q->view(), q));
+ } else {
+ if (force || qobject_cast<QComboMenuDelegate *>(q->itemDelegate()))
+ q->setItemDelegate(new QComboBoxDelegate(q->view(), q));
+ }
+}
+
+QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const
+{
+ QVariant decoration = model->data(index, Qt::DecorationRole);
+ if (decoration.type() == QVariant::Pixmap)
+ return QIcon(qvariant_cast<QPixmap>(decoration));
+ else
+ return qvariant_cast<QIcon>(decoration);
+}
+
+void QComboBox::setEditable(bool editable)
+{
+ Q_D(QComboBox);
+ if (isEditable() == editable)
+ return;
+
+ d->updateDelegate();
+
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ if (editable) {
+ if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
+ d->viewContainer()->updateScrollers();
+ view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ }
+ QLineEdit *le = new QLineEdit(this);
+ setLineEdit(le);
+ } else {
+ if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
+ d->viewContainer()->updateScrollers();
+ view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ }
+ setAttribute(Qt::WA_InputMethodEnabled, false);
+ d->lineEdit->hide();
+ d->lineEdit->deleteLater();
+ d->lineEdit = 0;
+ }
+
+ d->viewContainer()->updateTopBottomMargin();
+ if (!testAttribute(Qt::WA_Resized))
+ adjustSize();
+}
+
+/*!
+ Sets the line \a edit to use instead of the current line edit widget.
+
+ The combo box takes ownership of the line edit.
+*/
+void QComboBox::setLineEdit(QLineEdit *edit)
+{
+ Q_D(QComboBox);
+ if (!edit) {
+ qWarning("QComboBox::setLineEdit: cannot set a 0 line edit");
+ return;
+ }
+
+ if (edit == d->lineEdit)
+ return;
+
+ edit->setText(currentText());
+ delete d->lineEdit;
+
+ d->lineEdit = edit;
+ if (d->lineEdit->parent() != this)
+ d->lineEdit->setParent(this);
+ connect(d->lineEdit, SIGNAL(returnPressed()), this, SLOT(_q_returnPressed()));
+ connect(d->lineEdit, SIGNAL(editingFinished()), this, SLOT(_q_editingFinished()));
+ connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString)));
+#ifdef QT3_SUPPORT
+ connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
+#endif
+ d->lineEdit->setFrame(false);
+ d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
+ d->lineEdit->setFocusProxy(this);
+ d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
+#ifndef QT_NO_COMPLETER
+ setAutoCompletion(d->autoCompletion);
+#endif
+
+#ifdef QT_KEYPAD_NAVIGATION
+#ifndef QT_NO_COMPLETER
+ if (QApplication::keypadNavigationEnabled()) {
+ // Editable combo boxes will have a completer that is set to UnfilteredPopupCompletion.
+ // This means that when the user enters edit mode they are immediately presented with a
+ // list of possible completions.
+ setAutoCompletion(true);
+ if (d->completer) {
+ d->completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
+ connect(d->completer, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated()));
+ }
+ }
+#endif
+#endif
+
+ setAttribute(Qt::WA_InputMethodEnabled);
+ d->updateLayoutDirection();
+ d->updateLineEditGeometry();
+ if (isVisible())
+ d->lineEdit->show();
+
+ update();
+}
+
+/*!
+ Returns the line edit used to edit items in the combobox, or 0 if there
+ is no line edit.
+
+ Only editable combo boxes have a line edit.
+*/
+QLineEdit *QComboBox::lineEdit() const
+{
+ Q_D(const QComboBox);
+ return d->lineEdit;
+}
+
+#ifndef QT_NO_VALIDATOR
+/*!
+ \fn void QComboBox::setValidator(const QValidator *validator)
+
+ Sets the \a validator to use instead of the current validator.
+*/
+
+void QComboBox::setValidator(const QValidator *v)
+{
+ Q_D(QComboBox);
+ if (d->lineEdit)
+ d->lineEdit->setValidator(v);
+}
+
+/*!
+ Returns the validator that is used to constrain text input for the
+ combobox.
+
+ \sa editable
+*/
+const QValidator *QComboBox::validator() const
+{
+ Q_D(const QComboBox);
+ return d->lineEdit ? d->lineEdit->validator() : 0;
+}
+#endif // QT_NO_VALIDATOR
+
+#ifndef QT_NO_COMPLETER
+
+/*!
+ \fn void QComboBox::setCompleter(QCompleter *completer)
+ \since 4.2
+
+ Sets the \a completer to use instead of the current completer.
+ If \a completer is 0, auto completion is disabled.
+
+ By default, for an editable combo box, a QCompleter that
+ performs case insensitive inline completion is automatically created.
+*/
+void QComboBox::setCompleter(QCompleter *c)
+{
+ Q_D(QComboBox);
+ if (!d->lineEdit)
+ return;
+ d->lineEdit->setCompleter(c);
+ if (c)
+ c->setWidget(this);
+}
+
+/*!
+ \since 4.2
+
+ Returns the completer that is used to auto complete text input for the
+ combobox.
+
+ \sa editable
+*/
+QCompleter *QComboBox::completer() const
+{
+ Q_D(const QComboBox);
+ return d->lineEdit ? d->lineEdit->completer() : 0;
+}
+
+#endif // QT_NO_COMPLETER
+
+/*!
+ Returns the item delegate used by the popup list view.
+
+ \sa setItemDelegate()
+*/
+QAbstractItemDelegate *QComboBox::itemDelegate() const
+{
+ return view()->itemDelegate();
+}
+
+/*!
+ Sets the item \a delegate for the popup list view.
+ The combobox takes ownership of the delegate.
+
+ \warning You should not share the same instance of a delegate between comboboxes,
+ widget mappers or views. Doing so can cause incorrect or unintuitive editing behavior
+ since each view connected to a given delegate may receive the
+ \l{QAbstractItemDelegate::}{closeEditor()} signal, and attempt to access, modify or
+ close an editor that has already been closed.
+
+ \sa itemDelegate()
+*/
+void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate)
+{
+ if (!delegate) {
+ qWarning("QComboBox::setItemDelegate: cannot set a 0 delegate");
+ return;
+ }
+ delete view()->itemDelegate();
+ view()->setItemDelegate(delegate);
+}
+
+/*!
+ Returns the model used by the combobox.
+*/
+
+QAbstractItemModel *QComboBox::model() const
+{
+ Q_D(const QComboBox);
+ if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) {
+ QComboBox *that = const_cast<QComboBox*>(this);
+ that->setModel(new QStandardItemModel(0, 1, that));
+ }
+ return d->model;
+}
+
+/*!
+ Sets the model to be \a model. \a model must not be 0.
+ If you want to clear the contents of a model, call clear().
+
+ \sa clear()
+*/
+void QComboBox::setModel(QAbstractItemModel *model)
+{
+ Q_D(QComboBox);
+
+ if (!model) {
+ qWarning("QComboBox::setModel: cannot set a 0 model");
+ return;
+ }
+
+#ifndef QT_NO_COMPLETER
+ if (d->lineEdit && d->lineEdit->completer()
+ && d->lineEdit->completer() == d->completer)
+ d->lineEdit->completer()->setModel(model);
+#endif
+ if (d->model) {
+ disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ disconnect(d->model, SIGNAL(destroyed()),
+ this, SLOT(_q_modelDestroyed()));
+ disconnect(d->model, SIGNAL(modelAboutToBeReset()),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ disconnect(d->model, SIGNAL(modelReset()),
+ this, SLOT(_q_modelReset()));
+ if (d->model->QObject::parent() == this)
+ delete d->model;
+ }
+
+ d->model = model;
+
+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ connect(model, SIGNAL(destroyed()),
+ this, SLOT(_q_modelDestroyed()));
+ connect(model, SIGNAL(modelAboutToBeReset()),
+ this, SLOT(_q_updateIndexBeforeChange()));
+ connect(model, SIGNAL(modelReset()),
+ this, SLOT(_q_modelReset()));
+
+ if (d->container)
+ d->container->itemView()->setModel(model);
+
+ bool currentReset = false;
+
+ if (count()) {
+ for (int pos=0; pos < count(); pos++) {
+ if (d->model->index(pos, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled) {
+ setCurrentIndex(pos);
+ currentReset = true;
+ break;
+ }
+ }
+ }
+
+ if (!currentReset)
+ setCurrentIndex(-1);
+
+ d->modelChanged();
+}
+
+/*!
+ Returns the root model item index for the items in the combobox.
+
+ \sa setRootModelIndex()
+*/
+
+QModelIndex QComboBox::rootModelIndex() const
+{
+ Q_D(const QComboBox);
+ return QModelIndex(d->root);
+}
+
+/*!
+ Sets the root model item \a index for the items in the combobox.
+
+ \sa rootModelIndex()
+*/
+void QComboBox::setRootModelIndex(const QModelIndex &index)
+{
+ Q_D(QComboBox);
+ d->root = QPersistentModelIndex(index);
+ view()->setRootIndex(index);
+ update();
+}
+
+/*!
+ \property QComboBox::currentIndex
+ \brief the index of the current item in the combobox.
+
+ The current index can change when inserting or removing items.
+
+ By default, for an empty combo box or a combo box in which no current
+ item is set, this property has a value of -1.
+*/
+int QComboBox::currentIndex() const
+{
+ Q_D(const QComboBox);
+ return d->currentIndex.row();
+}
+
+void QComboBox::setCurrentIndex(int index)
+{
+ Q_D(QComboBox);
+ QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
+ d->setCurrentIndex(mi);
+}
+
+void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi)
+{
+ Q_Q(QComboBox);
+
+ QModelIndex normalized;
+ if (mi.column() != modelColumn)
+ normalized = model->index(mi.row(), modelColumn, mi.parent());
+ if (!normalized.isValid())
+ normalized = mi; // Fallback to passed index.
+
+ bool indexChanged = (normalized != currentIndex);
+ if (indexChanged)
+ currentIndex = QPersistentModelIndex(normalized);
+ if (lineEdit) {
+ QString newText = q->itemText(normalized.row());
+ if (lineEdit->text() != newText)
+ lineEdit->setText(newText);
+ updateLineEditGeometry();
+ }
+ if (indexChanged) {
+ q->update();
+ _q_emitCurrentIndexChanged(currentIndex);
+ }
+}
+
+/*!
+ \property QComboBox::currentText
+ \brief the text of the current item
+
+ By default, for an empty combo box or a combo box in which no current
+ item is set, this property contains an empty string.
+*/
+QString QComboBox::currentText() const
+{
+ Q_D(const QComboBox);
+ if (d->lineEdit)
+ return d->lineEdit->text();
+ else if (d->currentIndex.isValid())
+ return d->itemText(d->currentIndex);
+ else
+ return QString();
+}
+
+/*!
+ Returns the text for the given \a index in the combobox.
+*/
+QString QComboBox::itemText(int index) const
+{
+ Q_D(const QComboBox);
+ QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
+ return d->itemText(mi);
+}
+
+/*!
+ Returns the icon for the given \a index in the combobox.
+*/
+QIcon QComboBox::itemIcon(int index) const
+{
+ Q_D(const QComboBox);
+ QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
+ return d->itemIcon(mi);
+}
+
+/*!
+ Returns the data for the given \a role in the given \a index in the
+ combobox, or QVariant::Invalid if there is no data for this role.
+*/
+QVariant QComboBox::itemData(int index, int role) const
+{
+ Q_D(const QComboBox);
+ QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
+ return d->model->data(mi, role);
+}
+
+/*!
+ \fn void QComboBox::insertItem(int index, const QString &text, const QVariant &userData)
+
+ Inserts the \a text and \a userData (stored in the Qt::UserRole)
+ into the combobox at the given \a index.
+
+ If the index is equal to or higher than the total number of items,
+ the new item is appended to the list of existing items. If the
+ index is zero or negative, the new item is prepended to the list
+ of existing items.
+
+ \sa insertItems()
+*/
+
+/*!
+
+ Inserts the \a icon, \a text and \a userData (stored in the
+ Qt::UserRole) into the combobox at the given \a index.
+
+ If the index is equal to or higher than the total number of items,
+ the new item is appended to the list of existing items. If the
+ index is zero or negative, the new item is prepended to the list
+ of existing items.
+
+ \sa insertItems()
+*/
+void QComboBox::insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userData)
+{
+ Q_D(QComboBox);
+ int itemCount = count();
+ index = qBound(0, index, itemCount);
+ if (index >= d->maxCount)
+ return;
+
+ // For the common case where we are using the built in QStandardItemModel
+ // construct a QStandardItem, reducing the number of expensive signals from the model
+ if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
+ QStandardItem *item = new QStandardItem(text);
+ if (!icon.isNull()) item->setData(icon, Qt::DecorationRole);
+ if (userData.isValid()) item->setData(userData, Qt::UserRole);
+ m->insertRow(index, item);
+ ++itemCount;
+ } else {
+ d->inserting = true;
+ if (d->model->insertRows(index, 1, d->root)) {
+ QModelIndex item = d->model->index(index, d->modelColumn, d->root);
+ if (icon.isNull() && !userData.isValid()) {
+ d->model->setData(item, text, Qt::EditRole);
+ } else {
+ QMap<int, QVariant> values;
+ if (!text.isNull()) values.insert(Qt::EditRole, text);
+ if (!icon.isNull()) values.insert(Qt::DecorationRole, icon);
+ if (userData.isValid()) values.insert(Qt::UserRole, userData);
+ if (!values.isEmpty()) d->model->setItemData(item, values);
+ }
+ d->inserting = false;
+ d->_q_rowsInserted(d->root, index, index);
+ ++itemCount;
+ } else {
+ d->inserting = false;
+ }
+ }
+
+ if (itemCount > d->maxCount)
+ d->model->removeRows(itemCount - 1, itemCount - d->maxCount, d->root);
+}
+
+/*!
+ Inserts the strings from the \a list into the combobox as separate items,
+ starting at the \a index specified.
+
+ If the index is equal to or higher than the total number of items, the new items
+ are appended to the list of existing items. If the index is zero or negative, the
+ new items are prepended to the list of existing items.
+
+ \sa insertItem()
+ */
+void QComboBox::insertItems(int index, const QStringList &list)
+{
+ Q_D(QComboBox);
+ if (list.isEmpty())
+ return;
+ index = qBound(0, index, count());
+ int insertCount = qMin(d->maxCount - index, list.count());
+ if (insertCount <= 0)
+ return;
+ // For the common case where we are using the built in QStandardItemModel
+ // construct a QStandardItem, reducing the number of expensive signals from the model
+ if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
+ QList<QStandardItem *> items;
+ QStandardItem *hiddenRoot = m->invisibleRootItem();
+ for (int i = 0; i < insertCount; ++i)
+ items.append(new QStandardItem(list.at(i)));
+ hiddenRoot->insertRows(index, items);
+ } else {
+ d->inserting = true;
+ if (d->model->insertRows(index, insertCount, d->root)) {
+ QModelIndex item;
+ for (int i = 0; i < insertCount; ++i) {
+ item = d->model->index(i+index, d->modelColumn, d->root);
+ d->model->setData(item, list.at(i), Qt::EditRole);
+ }
+ d->inserting = false;
+ d->_q_rowsInserted(d->root, index, index + insertCount - 1);
+ } else {
+ d->inserting = false;
+ }
+ }
+
+ int mc = count();
+ if (mc > d->maxCount)
+ d->model->removeRows(d->maxCount, mc - d->maxCount, d->root);
+}
+
+/*!
+ \since 4.4
+
+ Inserts a separator item into the combobox at the given \a index.
+
+ If the index is equal to or higher than the total number of items, the new item
+ is appended to the list of existing items. If the index is zero or negative, the
+ new item is prepended to the list of existing items.
+
+ \sa insertItem()
+*/
+void QComboBox::insertSeparator(int index)
+{
+ Q_D(QComboBox);
+ int itemCount = count();
+ index = qBound(0, index, itemCount);
+ if (index >= d->maxCount)
+ return;
+ insertItem(index, QIcon(), QString());
+ QComboBoxDelegate::setSeparator(d->model, d->model->index(index, 0, d->root));
+}
+
+/*!
+ Removes the item at the given \a index from the combobox.
+ This will update the current index if the index is removed.
+
+ This function does nothing if \a index is out of range.
+*/
+void QComboBox::removeItem(int index)
+{
+ Q_D(QComboBox);
+ if (index < 0 || index >= count())
+ return;
+ d->model->removeRows(index, 1, d->root);
+}
+
+/*!
+ Sets the \a text for the item on the given \a index in the combobox.
+*/
+void QComboBox::setItemText(int index, const QString &text)
+{
+ Q_D(const QComboBox);
+ QModelIndex item = d->model->index(index, d->modelColumn, d->root);
+ if (item.isValid()) {
+ d->model->setData(item, text, Qt::EditRole);
+ }
+}
+
+/*!
+ Sets the \a icon for the item on the given \a index in the combobox.
+*/
+void QComboBox::setItemIcon(int index, const QIcon &icon)
+{
+ Q_D(const QComboBox);
+ QModelIndex item = d->model->index(index, d->modelColumn, d->root);
+ if (item.isValid()) {
+ d->model->setData(item, icon, Qt::DecorationRole);
+ }
+}
+
+/*!
+ Sets the data \a role for the item on the given \a index in the combobox
+ to the specified \a value.
+*/
+void QComboBox::setItemData(int index, const QVariant &value, int role)
+{
+ Q_D(const QComboBox);
+ QModelIndex item = d->model->index(index, d->modelColumn, d->root);
+ if (item.isValid()) {
+ d->model->setData(item, value, role);
+ }
+}
+
+/*!
+ Returns the list view used for the combobox popup.
+*/
+QAbstractItemView *QComboBox::view() const
+{
+ Q_D(const QComboBox);
+ return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView();
+}
+
+/*!
+ Sets the view to be used in the combobox popup to the given \a
+ itemView. The combobox takes ownership of the view.
+
+ Note: If you want to use the convenience views (like QListWidget,
+ QTableWidget or QTreeWidget), make sure to call setModel() on the
+ combobox with the convenience widgets model before calling this
+ function.
+*/
+void QComboBox::setView(QAbstractItemView *itemView)
+{
+ Q_D(QComboBox);
+ if (!itemView) {
+ qWarning("QComboBox::setView: cannot set a 0 view");
+ return;
+ }
+
+ if (itemView->model() != d->model)
+ itemView->setModel(d->model);
+ d->viewContainer()->setItemView(itemView);
+}
+
+/*!
+ \reimp
+*/
+QSize QComboBox::minimumSizeHint() const
+{
+ Q_D(const QComboBox);
+ return d->recomputeSizeHint(d->minimumSizeHint);
+}
+
+/*!
+ \reimp
+
+ This implementation caches the size hint to avoid resizing when
+ the contents change dynamically. To invalidate the cached value
+ change the \l sizeAdjustPolicy.
+*/
+QSize QComboBox::sizeHint() const
+{
+ Q_D(const QComboBox);
+ return d->recomputeSizeHint(d->sizeHint);
+}
+
+/*!
+ Displays the list of items in the combobox. If the list is empty
+ then the no items will be shown.
+
+ If you reimplement this function to show a custom pop-up, make
+ sure you call hidePopup() to reset the internal state.
+
+ \sa hidePopup()
+*/
+void QComboBox::showPopup()
+{
+ Q_D(QComboBox);
+ if (count() <= 0)
+ return;
+
+#ifdef QT_KEYPAD_NAVIGATION
+#ifndef QT_NO_COMPLETER
+ if (QApplication::keypadNavigationEnabled() && d->completer) {
+ // editable combo box is line edit plus completer
+ setEditFocus(true);
+ d->completer->complete(); // show popup
+ return;
+ }
+#endif
+#endif
+
+ QStyle * const style = this->style();
+
+ // set current item and select it
+ view()->selectionModel()->setCurrentIndex(d->currentIndex,
+ QItemSelectionModel::ClearAndSelect);
+ QComboBoxPrivateContainer* container = d->viewContainer();
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
+ QStyle::SC_ComboBoxListBoxPopup, this));
+#ifndef Q_WS_S60
+ QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this));
+#else
+ QRect screen = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+#endif
+
+ QPoint below = mapToGlobal(listRect.bottomLeft());
+ int belowHeight = screen.bottom() - below.y();
+ QPoint above = mapToGlobal(listRect.topLeft());
+ int aboveHeight = above.y() - screen.y();
+ bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
+
+ const bool usePopup = style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this);
+ {
+ int listHeight = 0;
+ int count = 0;
+ QStack<QModelIndex> toCheck;
+ toCheck.push(view()->rootIndex());
+#ifndef QT_NO_TREEVIEW
+ QTreeView *treeView = qobject_cast<QTreeView*>(view());
+ if (treeView && treeView->header() && !treeView->header()->isHidden())
+ listHeight += treeView->header()->height();
+#endif
+ while (!toCheck.isEmpty()) {
+ QModelIndex parent = toCheck.pop();
+ for (int i = 0; i < d->model->rowCount(parent); ++i) {
+ QModelIndex idx = d->model->index(i, d->modelColumn, parent);
+ if (!idx.isValid())
+ continue;
+ listHeight += view()->visualRect(idx).height() + container->spacing();
+#ifndef QT_NO_TREEVIEW
+ if (d->model->hasChildren(idx) && treeView && treeView->isExpanded(idx))
+ toCheck.push(idx);
+#endif
+ ++count;
+ if (!usePopup && count >= d->maxVisibleItems) {
+ toCheck.clear();
+ break;
+ }
+ }
+ }
+ listRect.setHeight(listHeight);
+ }
+
+ {
+ // add the spacing for the grid on the top and the bottom;
+ int heightMargin = 2*container->spacing();
+
+ // add the frame of the container
+ int marginTop, marginBottom;
+ container->getContentsMargins(0, &marginTop, 0, &marginBottom);
+ heightMargin += marginTop + marginBottom;
+
+ //add the frame of the view
+ view()->getContentsMargins(0, &marginTop, 0, &marginBottom);
+ marginTop += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->top;
+ marginBottom += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->bottom;
+ heightMargin += marginTop + marginBottom;
+
+ listRect.setHeight(listRect.height() + heightMargin);
+ }
+
+ // Add space for margin at top and bottom if the style wants it.
+ if (usePopup)
+ listRect.setHeight(listRect.height() + style->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) * 2);
+
+ // Make sure the popup is wide enough to display its contents.
+ if (usePopup) {
+ const int diff = d->computeWidthHint() - width();
+ if (diff > 0)
+ listRect.setWidth(listRect.width() + diff);
+ }
+
+ //we need to activate the layout to make sure the min/maximum size are set when the widget was not yet show
+ container->layout()->activate();
+ //takes account of the minimum/maximum size of the container
+ listRect.setSize( listRect.size().expandedTo(container->minimumSize())
+ .boundedTo(container->maximumSize()));
+
+ // make sure the widget fits on screen
+ if (boundToScreen) {
+ if (listRect.width() > screen.width() )
+ listRect.setWidth(screen.width());
+ if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) {
+ below.setX(screen.x() + screen.width() - listRect.width());
+ above.setX(screen.x() + screen.width() - listRect.width());
+ }
+ if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) {
+ below.setX(screen.x());
+ above.setX(screen.x());
+ }
+ }
+
+ if (usePopup) {
+ // Position horizontally.
+ listRect.moveLeft(above.x());
+
+#ifndef Q_WS_S60
+ // Position vertically so the curently selected item lines up
+ // with the combo box.
+ const QRect currentItemRect = view()->visualRect(view()->currentIndex());
+ const int offset = listRect.top() - currentItemRect.top();
+ listRect.moveTop(above.y() + offset - listRect.top());
+#endif
+
+
+ // Clamp the listRect height and vertical position so we don't expand outside the
+ // available screen geometry.This may override the vertical position, but it is more
+ // important to show as much as possible of the popup.
+ const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height());
+ listRect.setHeight(height);
+
+ if (boundToScreen) {
+ if (listRect.top() < screen.top())
+ listRect.moveTop(screen.top());
+ if (listRect.bottom() > screen.bottom())
+ listRect.moveBottom(screen.bottom());
+ }
+#ifdef Q_WS_S60
+ if (screen.width() < screen.height()) {
+ // in portait, menu should be positioned above softkeys
+ listRect.moveBottom(screen.bottom());
+ } else {
+ TRect staConTopRect = TRect();
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
+ listRect.setWidth(listRect.height());
+ //by default popup is centered on screen in landscape
+ listRect.moveCenter(screen.center());
+ if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) {
+ // landscape without stacon, menu should be at the right
+ (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) :
+ listRect.setLeft(screen.left());
+ }
+ }
+#endif
+ } else if (!boundToScreen || listRect.height() <= belowHeight) {
+ listRect.moveTopLeft(below);
+ } else if (listRect.height() <= aboveHeight) {
+ listRect.moveBottomLeft(above);
+ } else if (belowHeight >= aboveHeight) {
+ listRect.setHeight(belowHeight);
+ listRect.moveTopLeft(below);
+ } else {
+ listRect.setHeight(aboveHeight);
+ listRect.moveBottomLeft(above);
+ }
+
+#ifndef QT_NO_IM
+ if (QInputContext *qic = inputContext())
+ qic->reset();
+#endif
+ QScrollBar *sb = view()->horizontalScrollBar();
+ Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy();
+ bool needHorizontalScrollBar = (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn)
+ && sb->minimum() < sb->maximum();
+ if (needHorizontalScrollBar) {
+ listRect.adjust(0, 0, 0, sb->height());
+ }
+ container->setGeometry(listRect);
+
+#ifndef Q_WS_MAC
+ const bool updatesEnabled = container->updatesEnabled();
+#endif
+
+#if defined(Q_WS_WIN) && !defined(QT_NO_EFFECTS)
+ bool scrollDown = (listRect.topLeft() == below);
+ if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo)
+ && !style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && !window()->testAttribute(Qt::WA_DontShowOnScreen))
+ qScrollEffect(container, scrollDown ? QEffects::DownScroll : QEffects::UpScroll, 150);
+#endif
+
+// Don't disable updates on Mac OS X. Windows are displayed immediately on this platform,
+// which means that the window will be visible before the call to container->show() returns.
+// If updates are disabled at this point we'll miss our chance at painting the popup
+// menu before it's shown, causing flicker since the window then displays the standard gray
+// background.
+#ifndef Q_WS_MAC
+ container->setUpdatesEnabled(false);
+#endif
+
+ container->raise();
+ container->show();
+ container->updateScrollers();
+ view()->setFocus();
+
+ view()->scrollTo(view()->currentIndex(),
+ style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)
+ ? QAbstractItemView::PositionAtCenter
+ : QAbstractItemView::EnsureVisible);
+
+#ifndef Q_WS_MAC
+ container->setUpdatesEnabled(updatesEnabled);
+#endif
+
+ container->update();
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ view()->setEditFocus(true);
+#endif
+}
+
+/*!
+ Hides the list of items in the combobox if it is currently visible
+ and resets the internal state, so that if the custom pop-up was
+ shown inside the reimplemented showPopup(), then you also need to
+ reimplement the hidePopup() function to hide your custom pop-up
+ and call the base class implementation to reset the internal state
+ whenever your custom pop-up widget is hidden.
+
+ \sa showPopup()
+*/
+void QComboBox::hidePopup()
+{
+ Q_D(QComboBox);
+ if (d->container && d->container->isVisible()) {
+#if !defined(QT_NO_EFFECTS)
+ d->model->blockSignals(true);
+ d->container->itemView()->blockSignals(true);
+ d->container->blockSignals(true);
+ // Flash selected/triggered item (if any).
+ if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)) {
+ QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : 0;
+ if (selectionModel && selectionModel->hasSelection()) {
+ QEventLoop eventLoop;
+ const QItemSelection selection = selectionModel->selection();
+
+ // Deselect item and wait 60 ms.
+ selectionModel->select(selection, QItemSelectionModel::Toggle);
+ QTimer::singleShot(60, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+
+ // Select item and wait 20 ms.
+ selectionModel->select(selection, QItemSelectionModel::Toggle);
+ QTimer::singleShot(20, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+ }
+ }
+
+ // Fade out.
+ bool needFade = style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
+ if (needFade) {
+#if defined(Q_WS_MAC)
+ macWindowFade(qt_mac_window_for(d->container));
+#endif // Q_WS_MAC
+ // Other platform implementations welcome :-)
+ }
+ d->model->blockSignals(false);
+ d->container->itemView()->blockSignals(false);
+ d->container->blockSignals(false);
+
+ if (!needFade)
+#endif // QT_NO_EFFECTS
+ // Fade should implicitly hide as well ;-)
+ d->container->hide();
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && isEditable() && hasFocus())
+ setEditFocus(true);
+#endif
+ d->_q_resetButton();
+}
+
+/*!
+ Clears the combobox, removing all items.
+
+ Note: If you have set an external model on the combobox this model
+ will still be cleared when calling this function.
+*/
+void QComboBox::clear()
+{
+ Q_D(QComboBox);
+ d->model->removeRows(0, d->model->rowCount(d->root), d->root);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+/*!
+ \fn void QComboBox::clearValidator()
+
+ Use setValidator(0) instead.
+*/
+
+/*!
+ Clears the contents of the line edit used for editing in the combobox.
+*/
+void QComboBox::clearEditText()
+{
+ Q_D(QComboBox);
+ if (d->lineEdit)
+ d->lineEdit->clear();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+/*!
+ Sets the \a text in the combobox's text edit.
+*/
+void QComboBox::setEditText(const QString &text)
+{
+ Q_D(QComboBox);
+ if (d->lineEdit)
+ d->lineEdit->setText(text);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QComboBox);
+ update();
+ if (d->lineEdit) {
+ d->lineEdit->event(e);
+#ifndef QT_NO_COMPLETER
+ if (d->lineEdit->completer())
+ d->lineEdit->completer()->setWidget(this);
+#endif
+ }
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QComboBox);
+ update();
+ if (d->lineEdit)
+ d->lineEdit->event(e);
+}
+
+/*! \reimp */
+void QComboBox::changeEvent(QEvent *e)
+{
+ Q_D(QComboBox);
+ switch (e->type()) {
+ case QEvent::StyleChange:
+ d->updateDelegate();
+#ifdef Q_WS_MAC
+ case QEvent::MacSizeChange:
+#endif
+ d->sizeHint = QSize(); // invalidate size hint
+ d->minimumSizeHint = QSize();
+ d->updateLayoutDirection();
+ if (d->lineEdit)
+ d->updateLineEditGeometry();
+ d->setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
+
+#ifdef Q_WS_S60
+ if (d->container) {
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+
+ if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
+ QRect screen = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+
+ QRect listRect(style()->subControlRect(QStyle::CC_ComboBox, &opt,
+ QStyle::SC_ComboBoxListBoxPopup, this));
+ listRect.setHeight(qMin(screen.height(), screen.width()));
+
+ if (screen.width() < screen.height()) {
+ // in portait, menu should be positioned above softkeys
+ listRect.moveBottom(screen.bottom());
+ } else {
+ TRect staConTopRect = TRect();
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
+ listRect.setWidth(listRect.height());
+ //by default popup is centered on screen in landscape
+ listRect.moveCenter(screen.center());
+ if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) {
+ // landscape without stacon, menu should be at the right
+ (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) :
+ listRect.setLeft(screen.left());
+ }
+ }
+
+ d->container->setGeometry(listRect);
+ }
+ }
+#endif
+
+ // ### need to update scrollers etc. as well here
+ break;
+ case QEvent::EnabledChange:
+ if (!isEnabled())
+ hidePopup();
+ break;
+ case QEvent::PaletteChange: {
+ d->updateViewContainerPaletteAndOpacity();
+ break;
+ }
+ case QEvent::FontChange:
+ d->sizeHint = QSize(); // invalidate size hint
+ d->viewContainer()->setFont(font());
+ if (d->lineEdit)
+ d->updateLineEditGeometry();
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::resizeEvent(QResizeEvent *)
+{
+ Q_D(QComboBox);
+#ifdef Q_WS_S60
+ if (d->viewContainer() && d->viewContainer()->isVisible())
+ showPopup();
+#endif
+ d->updateLineEditGeometry();
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::paintEvent(QPaintEvent *)
+{
+ QStylePainter painter(this);
+ painter.setPen(palette().color(QPalette::Text));
+
+ // draw the combobox frame, focusrect and selected etc.
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+
+ // draw the icon and text
+ painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::showEvent(QShowEvent *e)
+{
+ Q_D(QComboBox);
+ if (!d->shownOnce && d->sizeAdjustPolicy == QComboBox::AdjustToContentsOnFirstShow) {
+ d->sizeHint = QSize();
+ updateGeometry();
+ }
+ d->shownOnce = true;
+ QWidget::showEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::hideEvent(QHideEvent *)
+{
+ hidePopup();
+}
+
+/*!
+ \reimp
+*/
+bool QComboBox::event(QEvent *event)
+{
+ Q_D(QComboBox);
+ switch(event->type()) {
+ case QEvent::LayoutDirectionChange:
+ case QEvent::ApplicationLayoutDirectionChange:
+ d->updateLayoutDirection();
+ d->updateLineEditGeometry();
+ break;
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d->updateHoverControl(he->pos());
+ break;
+ case QEvent::ShortcutOverride:
+ if (d->lineEdit)
+ return d->lineEdit->event(event);
+ break;
+#ifdef QT_KEYPAD_NAVIGATION
+ case QEvent::EnterEditFocus:
+ if (!d->lineEdit)
+ setEditFocus(false); // We never want edit focus if we are not editable
+ else
+ d->lineEdit->event(event); //so cursor starts
+ break;
+ case QEvent::LeaveEditFocus:
+ if (d->lineEdit)
+ d->lineEdit->event(event); //so cursor stops
+ break;
+#endif
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QComboBox);
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(),
+ this);
+ if (e->button() == Qt::LeftButton && (sc == QStyle::SC_ComboBoxArrow || !isEditable())
+ && !d->viewContainer()->isVisible()) {
+ if (sc == QStyle::SC_ComboBoxArrow)
+ d->updateArrow(QStyle::State_Sunken);
+#ifdef QT_KEYPAD_NAVIGATION
+ //if the container already exists, then d->viewContainer() is safe to call
+ if (d->container) {
+#endif
+ // We've restricted the next couple of lines, because by not calling
+ // viewContainer(), we avoid creating the QComboBoxPrivateContainer.
+ d->viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval());
+ d->viewContainer()->initialClickPosition = mapToGlobal(e->pos());
+#ifdef QT_KEYPAD_NAVIGATION
+ }
+#endif
+ showPopup();
+ } else {
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && d->lineEdit) {
+ d->lineEdit->event(e); //so lineedit can move cursor, etc
+ return;
+ }
+#endif
+ QWidget::mousePressEvent(e);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QComboBox);
+ Q_UNUSED(e);
+ d->updateArrow(QStyle::State_None);
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QComboBox);
+
+#ifndef QT_NO_COMPLETER
+ if (d->lineEdit
+ && d->lineEdit->completer()
+ && d->lineEdit->completer()->popup()
+ && d->lineEdit->completer()->popup()->isVisible()) {
+ // provide same autocompletion support as line edit
+ d->lineEdit->event(e);
+ return;
+ }
+#endif
+
+ enum Move { NoMove=0 , MoveUp , MoveDown , MoveFirst , MoveLast};
+
+ Move move = NoMove;
+ int newIndex = currentIndex();
+ switch (e->key()) {
+ case Qt::Key_Up:
+ if (e->modifiers() & Qt::ControlModifier)
+ break; // pass to line edit for auto completion
+ case Qt::Key_PageUp:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ e->ignore();
+ else
+#endif
+ move = MoveUp;
+ break;
+ case Qt::Key_Down:
+ if (e->modifiers() & Qt::AltModifier) {
+ showPopup();
+ return;
+ } else if (e->modifiers() & Qt::ControlModifier)
+ break; // pass to line edit for auto completion
+ // fall through
+ case Qt::Key_PageDown:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ e->ignore();
+ else
+#endif
+ move = MoveDown;
+ break;
+ case Qt::Key_Home:
+ if (!d->lineEdit)
+ move = MoveFirst;
+ break;
+ case Qt::Key_End:
+ if (!d->lineEdit)
+ move = MoveLast;
+ break;
+ case Qt::Key_F4:
+ if (!e->modifiers()) {
+ showPopup();
+ return;
+ }
+ break;
+ case Qt::Key_Space:
+ if (!d->lineEdit) {
+ showPopup();
+ return;
+ }
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Escape:
+ if (!d->lineEdit)
+ e->ignore();
+ break;
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()
+ && (!hasEditFocus() || !d->lineEdit)) {
+ showPopup();
+ return;
+ }
+ break;
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
+ e->ignore();
+ break;
+ case Qt::Key_Back:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus() || !d->lineEdit)
+ e->ignore();
+ } else {
+ e->ignore(); // let the surounding dialog have it
+ }
+ break;
+#endif
+ default:
+ if (!d->lineEdit) {
+ if (!e->text().isEmpty())
+ d->keyboardSearchString(e->text());
+ else
+ e->ignore();
+ }
+ }
+
+ if (move != NoMove) {
+ e->accept();
+ switch (move) {
+ case MoveFirst:
+ newIndex = -1;
+ case MoveDown:
+ newIndex++;
+ while ((newIndex < count()) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
+ newIndex++;
+ break;
+ case MoveLast:
+ newIndex = count();
+ case MoveUp:
+ newIndex--;
+ while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
+ newIndex--;
+ break;
+ default:
+ e->ignore();
+ break;
+ }
+
+ if (newIndex >= 0 && newIndex < count() && newIndex != currentIndex()) {
+ setCurrentIndex(newIndex);
+ d->emitActivated(d->currentIndex);
+ }
+ } else if (d->lineEdit) {
+ d->lineEdit->event(e);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QComboBox::keyReleaseEvent(QKeyEvent *e)
+{
+ Q_D(QComboBox);
+ if (d->lineEdit)
+ d->lineEdit->event(e);
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QComboBox::wheelEvent(QWheelEvent *e)
+{
+ Q_D(QComboBox);
+ if (!d->viewContainer()->isVisible()) {
+ int newIndex = currentIndex();
+
+ if (e->delta() > 0) {
+ newIndex--;
+ while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
+ newIndex--;
+ } else {
+ newIndex++;
+ while ((newIndex < count()) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
+ newIndex++;
+ }
+
+ if (newIndex >= 0 && newIndex < count() && newIndex != currentIndex()) {
+ setCurrentIndex(newIndex);
+ d->emitActivated(d->currentIndex);
+ }
+ e->accept();
+ }
+}
+#endif
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \reimp
+*/
+void QComboBox::contextMenuEvent(QContextMenuEvent *e)
+{
+ Q_D(QComboBox);
+ if (d->lineEdit) {
+ Qt::ContextMenuPolicy p = d->lineEdit->contextMenuPolicy();
+ d->lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu);
+ d->lineEdit->event(e);
+ d->lineEdit->setContextMenuPolicy(p);
+ }
+}
+#endif // QT_NO_CONTEXTMENU
+
+void QComboBoxPrivate::keyboardSearchString(const QString &text)
+{
+ // use keyboardSearch from the listView so we do not duplicate code
+ QAbstractItemView *view = viewContainer()->itemView();
+ view->setCurrentIndex(currentIndex);
+ int currentRow = view->currentIndex().row();
+ view->keyboardSearch(text);
+ if (currentRow != view->currentIndex().row()) {
+ setCurrentIndex(view->currentIndex());
+ emitActivated(currentIndex);
+ }
+}
+
+void QComboBoxPrivate::modelChanged()
+{
+ Q_Q(QComboBox);
+
+ if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
+ sizeHint = QSize();
+ adjustComboBoxSize();
+ q->updateGeometry();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QComboBox);
+ if (d->lineEdit) {
+ d->lineEdit->event(e);
+ } else {
+ if (!e->commitString().isEmpty())
+ d->keyboardSearchString(e->commitString());
+ else
+ e->ignore();
+ }
+}
+
+/*!
+ \reimp
+*/
+QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QComboBox);
+ if (d->lineEdit)
+ return d->lineEdit->inputMethodQuery(query);
+ return QWidget::inputMethodQuery(query);
+}
+
+/*!
+ \fn bool QComboBox::editable() const
+
+ Use isEditable() instead.
+*/
+
+/*!
+ \fn void QComboBox::insertItem(const QPixmap &pixmap, int index)
+
+ Use an insertItem() function that takes a QIcon instead, for
+ example, insertItem(index, QIcon(pixmap)).
+*/
+
+/*!
+ \fn void QComboBox::insertItem(const QPixmap &pixmap, const QString &text, int index)
+
+ Use an insertItem() function that takes a QIcon instead, for
+ example, insertItem(index, QIcon(pixmap), text).
+
+ \sa insertItems()
+*/
+
+/*!
+ \fn void QComboBox::changeItem(const QString &text, int index)
+
+ Use setItemText() instead.
+*/
+
+/*!
+ \fn void QComboBox::changeItem(const QPixmap &pixmap, int index)
+
+ Use setItemIcon() instead, for example,
+ setItemIcon(index, QIcon(pixmap)).
+*/
+
+/*!
+ \fn void QComboBox::changeItem(const QPixmap &pixmap, const QString &text, int index)
+
+ Use setItem() instead, for example, setItem(index, QIcon(pixmap),text).
+*/
+
+/*!
+ \fn void QComboBox::addItem(const QString &text, const QVariant &userData)
+
+ Adds an item to the combobox with the given \a text, and
+ containing the specified \a userData (stored in the Qt::UserRole).
+ The item is appended to the list of existing items.
+*/
+
+/*!
+ \fn void QComboBox::addItem(const QIcon &icon, const QString &text,
+ const QVariant &userData)
+
+ Adds an item to the combobox with the given \a icon and \a text,
+ and containing the specified \a userData (stored in the
+ Qt::UserRole). The item is appended to the list of existing items.
+*/
+
+/*!
+ \fn void QComboBox::addItems(const QStringList &texts)
+
+ Adds each of the strings in the given \a texts to the combobox. Each item
+ is appended to the list of existing items in turn.
+*/
+
+/*!
+ \fn void QComboBox::editTextChanged(const QString &text)
+
+ This signal is emitted when the text in the combobox's line edit
+ widget is changed. The new text is specified by \a text.
+*/
+
+/*!
+ \property QComboBox::frame
+ \brief whether the combo box draws itself with a frame
+
+
+ If enabled (the default) the combo box draws itself inside a
+ frame, otherwise the combo box draws itself without any frame.
+*/
+bool QComboBox::hasFrame() const
+{
+ Q_D(const QComboBox);
+ return d->frame;
+}
+
+
+void QComboBox::setFrame(bool enable)
+{
+ Q_D(QComboBox);
+ d->frame = enable;
+ update();
+ updateGeometry();
+}
+
+/*!
+ \property QComboBox::modelColumn
+ \brief the column in the model that is visible.
+
+ If set prior to populating the combo box, the pop-up view will
+ not be affected and will show the first column (using this property's
+ default value).
+
+ By default, this property has a value of 0.
+*/
+int QComboBox::modelColumn() const
+{
+ Q_D(const QComboBox);
+ return d->modelColumn;
+}
+
+void QComboBox::setModelColumn(int visibleColumn)
+{
+ Q_D(QComboBox);
+ d->modelColumn = visibleColumn;
+ QListView *lv = qobject_cast<QListView *>(d->viewContainer()->itemView());
+ if (lv)
+ lv->setModelColumn(visibleColumn);
+#ifndef QT_NO_COMPLETER
+ if (d->lineEdit && d->lineEdit->completer()
+ && d->lineEdit->completer() == d->completer)
+ d->lineEdit->completer()->setCompletionColumn(visibleColumn);
+#endif
+ setCurrentIndex(currentIndex()); //update the text to the text of the new column;
+}
+
+/*!
+ \fn int QComboBox::currentItem() const
+
+ Use currentIndex() instead.
+*/
+
+/*!
+ \fn void QComboBox::setCurrentItem(int)
+
+ Use setCurrentIndex(int) instead.
+*/
+
+/*!
+ \fn void QComboBox::popup()
+
+ Use showPopup() instead.
+*/
+
+/*!
+ \fn void QComboBox::textChanged(const QString &text)
+
+ Use the editTextChanged(const QString &text) signal instead.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qcombobox.cpp"
+
+#endif // QT_NO_COMBOBOX
diff --git a/src/widgets/widgets/qcombobox.h b/src/widgets/widgets/qcombobox.h
new file mode 100644
index 0000000000..ed766cc004
--- /dev/null
+++ b/src/widgets/widgets/qcombobox.h
@@ -0,0 +1,339 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMBOBOX_H
+#define QCOMBOBOX_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qabstractitemdelegate.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+#ifndef QT_NO_COMBOBOX
+
+class QAbstractItemView;
+class QLineEdit;
+class QComboBoxPrivate;
+class QCompleter;
+
+class Q_WIDGETS_EXPORT QComboBox : public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(InsertPolicy)
+ Q_ENUMS(SizeAdjustPolicy)
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(QString currentText READ currentText)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged USER true)
+ Q_PROPERTY(int maxVisibleItems READ maxVisibleItems WRITE setMaxVisibleItems)
+ Q_PROPERTY(int maxCount READ maxCount WRITE setMaxCount)
+ Q_PROPERTY(InsertPolicy insertPolicy READ insertPolicy WRITE setInsertPolicy)
+ Q_PROPERTY(SizeAdjustPolicy sizeAdjustPolicy READ sizeAdjustPolicy WRITE setSizeAdjustPolicy)
+ Q_PROPERTY(int minimumContentsLength READ minimumContentsLength WRITE setMinimumContentsLength)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+
+#ifndef QT_NO_COMPLETER
+ Q_PROPERTY(bool autoCompletion READ autoCompletion WRITE setAutoCompletion DESIGNABLE false)
+ Q_PROPERTY(Qt::CaseSensitivity autoCompletionCaseSensitivity READ autoCompletionCaseSensitivity WRITE setAutoCompletionCaseSensitivity DESIGNABLE false)
+#endif // QT_NO_COMPLETER
+
+ Q_PROPERTY(bool duplicatesEnabled READ duplicatesEnabled WRITE setDuplicatesEnabled)
+ Q_PROPERTY(bool frame READ hasFrame WRITE setFrame)
+ Q_PROPERTY(int modelColumn READ modelColumn WRITE setModelColumn)
+
+public:
+ explicit QComboBox(QWidget *parent = 0);
+ ~QComboBox();
+
+ int maxVisibleItems() const;
+ void setMaxVisibleItems(int maxItems);
+
+ int count() const;
+ void setMaxCount(int max);
+ int maxCount() const;
+
+#ifndef QT_NO_COMPLETER
+ bool autoCompletion() const;
+ void setAutoCompletion(bool enable);
+
+ Qt::CaseSensitivity autoCompletionCaseSensitivity() const;
+ void setAutoCompletionCaseSensitivity(Qt::CaseSensitivity sensitivity);
+#endif
+
+ bool duplicatesEnabled() const;
+ void setDuplicatesEnabled(bool enable);
+
+ void setFrame(bool);
+ bool hasFrame() const;
+
+ inline int findText(const QString &text,
+ Qt::MatchFlags flags = static_cast<Qt::MatchFlags>(Qt::MatchExactly|Qt::MatchCaseSensitive)) const
+ { return findData(text, Qt::DisplayRole, flags); }
+ int findData(const QVariant &data, int role = Qt::UserRole,
+ Qt::MatchFlags flags = static_cast<Qt::MatchFlags>(Qt::MatchExactly|Qt::MatchCaseSensitive)) const;
+
+ enum InsertPolicy {
+ NoInsert,
+ InsertAtTop,
+ InsertAtCurrent,
+ InsertAtBottom,
+ InsertAfterCurrent,
+ InsertBeforeCurrent,
+ InsertAlphabetically
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ ,
+ NoInsertion = NoInsert,
+ AtTop = InsertAtTop,
+ AtCurrent = InsertAtCurrent,
+ AtBottom = InsertAtBottom,
+ AfterCurrent = InsertAfterCurrent,
+ BeforeCurrent = InsertBeforeCurrent
+#endif
+ };
+#ifdef QT3_SUPPORT
+ typedef InsertPolicy Policy;
+#endif
+
+ InsertPolicy insertPolicy() const;
+ void setInsertPolicy(InsertPolicy policy);
+
+ enum SizeAdjustPolicy {
+ AdjustToContents,
+ AdjustToContentsOnFirstShow,
+ AdjustToMinimumContentsLength, // ### Qt 5: remove
+ AdjustToMinimumContentsLengthWithIcon
+ };
+
+ SizeAdjustPolicy sizeAdjustPolicy() const;
+ void setSizeAdjustPolicy(SizeAdjustPolicy policy);
+ int minimumContentsLength() const;
+ void setMinimumContentsLength(int characters);
+ QSize iconSize() const;
+ void setIconSize(const QSize &size);
+
+ bool isEditable() const;
+ void setEditable(bool editable);
+ void setLineEdit(QLineEdit *edit);
+ QLineEdit *lineEdit() const;
+#ifndef QT_NO_VALIDATOR
+ void setValidator(const QValidator *v);
+ const QValidator *validator() const;
+#endif
+
+#ifndef QT_NO_COMPLETER
+ void setCompleter(QCompleter *c);
+ QCompleter *completer() const;
+#endif
+
+ QAbstractItemDelegate *itemDelegate() const;
+ void setItemDelegate(QAbstractItemDelegate *delegate);
+
+ QAbstractItemModel *model() const;
+ void setModel(QAbstractItemModel *model);
+
+ QModelIndex rootModelIndex() const;
+ void setRootModelIndex(const QModelIndex &index);
+
+ int modelColumn() const;
+ void setModelColumn(int visibleColumn);
+
+ int currentIndex() const;
+
+ QString currentText() const;
+
+ QString itemText(int index) const;
+ QIcon itemIcon(int index) const;
+ QVariant itemData(int index, int role = Qt::UserRole) const;
+
+ inline void addItem(const QString &text, const QVariant &userData = QVariant());
+ inline void addItem(const QIcon &icon, const QString &text,
+ const QVariant &userData = QVariant());
+ inline void addItems(const QStringList &texts)
+ { insertItems(count(), texts); }
+
+ inline void insertItem(int index, const QString &text, const QVariant &userData = QVariant());
+ void insertItem(int index, const QIcon &icon, const QString &text,
+ const QVariant &userData = QVariant());
+ void insertItems(int index, const QStringList &texts);
+ void insertSeparator(int index);
+
+ void removeItem(int index);
+
+ void setItemText(int index, const QString &text);
+ void setItemIcon(int index, const QIcon &icon);
+ void setItemData(int index, const QVariant &value, int role = Qt::UserRole);
+
+ QAbstractItemView *view() const;
+ void setView(QAbstractItemView *itemView);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ virtual void showPopup();
+ virtual void hidePopup();
+
+ bool event(QEvent *event);
+
+public Q_SLOTS:
+ void clear();
+ void clearEditText();
+ void setEditText(const QString &text);
+ void setCurrentIndex(int index);
+
+Q_SIGNALS:
+ void editTextChanged(const QString &);
+ void activated(int index);
+ void activated(const QString &);
+ void highlighted(int index);
+ void highlighted(const QString &);
+ void currentIndexChanged(int index);
+ void currentIndexChanged(const QString &);
+
+protected:
+ void focusInEvent(QFocusEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+ void changeEvent(QEvent *e);
+ void resizeEvent(QResizeEvent *e);
+ void paintEvent(QPaintEvent *e);
+ void showEvent(QShowEvent *e);
+ void hideEvent(QHideEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void keyReleaseEvent(QKeyEvent *e);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *e);
+#endif
+ void contextMenuEvent(QContextMenuEvent *e);
+ void inputMethodEvent(QInputMethodEvent *);
+ QVariant inputMethodQuery(Qt::InputMethodQuery) const;
+ void initStyleOption(QStyleOptionComboBox *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QComboBox(QWidget *parent, const char *name);
+ QT3_SUPPORT_CONSTRUCTOR QComboBox(bool rw, QWidget *parent, const char *name = 0);
+ inline QT3_SUPPORT int currentItem() const { return currentIndex(); }
+ inline QT3_SUPPORT void setCurrentItem(int index) { setCurrentIndex(index); }
+ inline QT3_SUPPORT InsertPolicy insertionPolicy() const { return insertPolicy(); }
+ inline QT3_SUPPORT void setInsertionPolicy(InsertPolicy policy) { setInsertPolicy(policy); }
+ inline QT3_SUPPORT bool editable() const { return isEditable(); }
+ inline QT3_SUPPORT void popup() { showPopup(); }
+ inline QT3_SUPPORT void setCurrentText(const QString& text) {
+ int i = findText(text);
+ if (i != -1)
+ setCurrentIndex(i);
+ else if (isEditable())
+ setEditText(text);
+ else
+ setItemText(currentIndex(), text);
+ }
+ inline QT3_SUPPORT QString text(int index) const { return itemText(index); }
+
+ inline QT3_SUPPORT QPixmap pixmap(int index) const
+ { return itemIcon(index).pixmap(iconSize(), isEnabled() ? QIcon::Normal : QIcon::Disabled); }
+ inline QT3_SUPPORT void insertStringList(const QStringList &list, int index = -1)
+ { insertItems((index < 0 ? count() : index), list); }
+ inline QT3_SUPPORT void insertItem(const QString &text, int index = -1)
+ { insertItem((index < 0 ? count() : index), text); }
+ inline QT3_SUPPORT void insertItem(const QPixmap &pix, int index = -1)
+ { insertItem((index < 0 ? count() : index), QIcon(pix), QString()); }
+ inline QT3_SUPPORT void insertItem(const QPixmap &pix, const QString &text, int index = -1)
+ { insertItem((index < 0 ? count() : index), QIcon(pix), text); }
+ inline QT3_SUPPORT void changeItem(const QString &text, int index)
+ { setItemText(index, text); }
+ inline QT3_SUPPORT void changeItem(const QPixmap &pix, int index)
+ { setItemIcon(index, QIcon(pix)); }
+ inline QT3_SUPPORT void changeItem(const QPixmap &pix, const QString &text, int index)
+ { setItemIcon(index, QIcon(pix)); setItemText(index, text); }
+ inline QT3_SUPPORT void clearValidator() { setValidator(0); }
+ inline QT3_SUPPORT void clearEdit() { clearEditText(); }
+
+Q_SIGNALS:
+ QT_MOC_COMPAT void textChanged(const QString &);
+#endif
+
+protected:
+ QComboBox(QComboBoxPrivate &, QWidget *);
+
+private:
+ Q_DECLARE_PRIVATE(QComboBox)
+ Q_DISABLE_COPY(QComboBox)
+ Q_PRIVATE_SLOT(d_func(), void _q_itemSelected(const QModelIndex &item))
+ Q_PRIVATE_SLOT(d_func(), void _q_emitHighlighted(const QModelIndex &))
+ Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentIndexChanged(const QModelIndex &index))
+ Q_PRIVATE_SLOT(d_func(), void _q_editingFinished())
+ Q_PRIVATE_SLOT(d_func(), void _q_returnPressed())
+ Q_PRIVATE_SLOT(d_func(), void _q_resetButton())
+ Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &, const QModelIndex &))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateIndexBeforeChange())
+ Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex & parent, int start, int end))
+ Q_PRIVATE_SLOT(d_func(), void _q_rowsRemoved(const QModelIndex & parent, int start, int end))
+ Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
+ Q_PRIVATE_SLOT(d_func(), void _q_modelReset())
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_PRIVATE_SLOT(d_func(), void _q_completerActivated())
+#endif
+};
+
+inline void QComboBox::addItem(const QString &atext, const QVariant &auserData)
+{ insertItem(count(), atext, auserData); }
+inline void QComboBox::addItem(const QIcon &aicon, const QString &atext,
+ const QVariant &auserData)
+{ insertItem(count(), aicon, atext, auserData); }
+
+inline void QComboBox::insertItem(int aindex, const QString &atext,
+ const QVariant &auserData)
+{ insertItem(aindex, QIcon(), atext, auserData); }
+
+#endif // QT_NO_COMBOBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOMBOBOX_H
diff --git a/src/widgets/widgets/qcombobox_p.h b/src/widgets/widgets/qcombobox_p.h
new file mode 100644
index 0000000000..2d3f261d6e
--- /dev/null
+++ b/src/widgets/widgets/qcombobox_p.h
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMBOBOX_P_H
+#define QCOMBOBOX_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 "QtWidgets/qcombobox.h"
+
+#ifndef QT_NO_COMBOBOX
+#include "QtWidgets/qabstractslider.h"
+#include "QtWidgets/qapplication.h"
+#include "QtWidgets/qitemdelegate.h"
+#include "QtWidgets/qstandarditemmodel.h"
+#include "QtWidgets/qlineedit.h"
+#include "QtWidgets/qlistview.h"
+#include "QtGui/qpainter.h"
+#include "QtWidgets/qstyle.h"
+#include "QtWidgets/qstyleoption.h"
+#include "QtCore/qhash.h"
+#include "QtCore/qpair.h"
+#include "QtCore/qtimer.h"
+#include "private/qwidget_p.h"
+#include "QtCore/qpointer.h"
+#include "QtWidgets/qcompleter.h"
+#include "QtGui/qevent.h"
+#include "QtCore/qdebug.h"
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAction;
+
+class QComboBoxListView : public QListView
+{
+ Q_OBJECT
+public:
+ QComboBoxListView(QComboBox *cmb = 0) : combo(cmb) {}
+
+protected:
+ void resizeEvent(QResizeEvent *event)
+ {
+ resizeContents(viewport()->width(), contentsSize().height());
+ QListView::resizeEvent(event);
+ }
+
+ QStyleOptionViewItem viewOptions() const
+ {
+ QStyleOptionViewItem option = QListView::viewOptions();
+ option.showDecorationSelected = true;
+ if (combo)
+ option.font = combo->font();
+ return option;
+ }
+
+ void paintEvent(QPaintEvent *e)
+ {
+ if (combo) {
+ QStyleOptionComboBox opt;
+ opt.initFrom(combo);
+ opt.editable = combo->isEditable();
+ if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
+ //we paint the empty menu area to avoid having blank space that can happen when scrolling
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.initFrom(this);
+ menuOpt.palette = palette();
+ menuOpt.state = QStyle::State_None;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.menuRect = e->rect();
+ menuOpt.maxIconWidth = 0;
+ menuOpt.tabWidth = 0;
+ QPainter p(viewport());
+ combo->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
+ }
+ }
+ QListView::paintEvent(e);
+ }
+
+private:
+ QComboBox *combo;
+};
+
+
+class QStandardItemModel;
+
+class Q_AUTOTEST_EXPORT QComboBoxPrivateScroller : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QComboBoxPrivateScroller(QAbstractSlider::SliderAction action, QWidget *parent)
+ : QWidget(parent), sliderAction(action)
+ {
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ setAttribute(Qt::WA_NoMousePropagation);
+ }
+ QSize sizeHint() const {
+ return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight));
+ }
+
+protected:
+ inline void stopTimer() {
+ timer.stop();
+ }
+
+ inline void startTimer() {
+ timer.start(100, this);
+ fast = false;
+ }
+
+ void enterEvent(QEvent *) {
+ startTimer();
+ }
+
+ void leaveEvent(QEvent *) {
+ stopTimer();
+ }
+ void timerEvent(QTimerEvent *e) {
+ if (e->timerId() == timer.timerId()) {
+ emit doScroll(sliderAction);
+ if (fast) {
+ emit doScroll(sliderAction);
+ emit doScroll(sliderAction);
+ }
+ }
+ }
+ void hideEvent(QHideEvent *) {
+ stopTimer();
+ }
+
+ void mouseMoveEvent(QMouseEvent *e)
+ {
+ // Enable fast scrolling if the cursor is directly above or below the popup.
+ const int mouseX = e->pos().x();
+ const int mouseY = e->pos().y();
+ const bool horizontallyInside = pos().x() < mouseX && mouseX < rect().right() + 1;
+ const bool verticallyOutside = (sliderAction == QAbstractSlider::SliderSingleStepAdd) ?
+ rect().bottom() + 1 < mouseY : mouseY < pos().y();
+
+ fast = horizontallyInside && verticallyOutside;
+ }
+
+ void paintEvent(QPaintEvent *) {
+ QPainter p(this);
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.init(this);
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.menuRect = rect();
+ menuOpt.maxIconWidth = 0;
+ menuOpt.tabWidth = 0;
+ menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
+ if (sliderAction == QAbstractSlider::SliderSingleStepAdd)
+ menuOpt.state |= QStyle::State_DownArrow;
+#ifndef Q_WS_S60
+ p.eraseRect(rect());
+#endif
+ style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p);
+ }
+
+Q_SIGNALS:
+ void doScroll(int action);
+
+private:
+ QAbstractSlider::SliderAction sliderAction;
+ QBasicTimer timer;
+ bool fast;
+};
+
+class Q_AUTOTEST_EXPORT QComboBoxPrivateContainer : public QFrame
+{
+ Q_OBJECT
+
+public:
+ QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent);
+ QAbstractItemView *itemView() const;
+ void setItemView(QAbstractItemView *itemView);
+ int spacing() const;
+ void updateTopBottomMargin();
+
+ QTimer blockMouseReleaseTimer;
+ QBasicTimer adjustSizeTimer;
+ QPoint initialClickPosition;
+
+public Q_SLOTS:
+ void scrollItemView(int action);
+ void updateScrollers();
+ void viewDestroyed();
+
+protected:
+ void changeEvent(QEvent *e);
+ bool eventFilter(QObject *o, QEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void showEvent(QShowEvent *e);
+ void hideEvent(QHideEvent *e);
+ void timerEvent(QTimerEvent *timerEvent);
+ void leaveEvent(QEvent *e);
+ void resizeEvent(QResizeEvent *e);
+ QStyleOptionComboBox comboStyleOption() const;
+
+Q_SIGNALS:
+ void itemSelected(const QModelIndex &);
+ void resetButton();
+
+private:
+ QComboBox *combo;
+ QAbstractItemView *view;
+ QComboBoxPrivateScroller *top;
+ QComboBoxPrivateScroller *bottom;
+#ifdef QT_SOFTKEYS_ENABLED
+ QAction *selectAction;
+ QAction *cancelAction;
+#endif
+};
+
+class QComboMenuDelegate : public QAbstractItemDelegate
+{ Q_OBJECT
+public:
+ QComboMenuDelegate(QObject *parent, QComboBox *cmb) : QAbstractItemDelegate(parent), mCombo(cmb) {}
+
+protected:
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ QStyleOptionMenuItem opt = getStyleOption(option, index);
+#ifndef Q_WS_S60
+ painter->fillRect(option.rect, opt.palette.background());
+#endif
+ mCombo->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, mCombo);
+ }
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ QStyleOptionMenuItem opt = getStyleOption(option, index);
+ return mCombo->style()->sizeFromContents(
+ QStyle::CT_MenuItem, &opt, option.rect.size(), mCombo);
+ }
+
+private:
+ QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ QComboBox *mCombo;
+};
+
+// Note that this class is intentionally not using QStyledItemDelegate
+// Vista does not use the new theme for combo boxes and there might
+// be other side effects from using the new class
+class QComboBoxDelegate : public QItemDelegate
+{ Q_OBJECT
+public:
+ QComboBoxDelegate(QObject *parent, QComboBox *cmb) : QItemDelegate(parent), mCombo(cmb) {}
+
+ static bool isSeparator(const QModelIndex &index) {
+ return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
+ }
+ static void setSeparator(QAbstractItemModel *model, const QModelIndex &index) {
+ model->setData(index, QString::fromLatin1("separator"), Qt::AccessibleDescriptionRole);
+ if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model))
+ if (QStandardItem *item = m->itemFromIndex(index))
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ }
+
+protected:
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ if (isSeparator(index)) {
+ QRect rect = option.rect;
+ if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&option))
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(v3->widget))
+ rect.setWidth(view->viewport()->width());
+ QStyleOption opt;
+ opt.rect = rect;
+ mCombo->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, mCombo);
+ } else {
+ QItemDelegate::paint(painter, option, index);
+ }
+ }
+
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ if (isSeparator(index)) {
+ int pm = mCombo->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, mCombo);
+ return QSize(pm, pm);
+ }
+ return QItemDelegate::sizeHint(option, index);
+ }
+private:
+ QComboBox *mCombo;
+};
+
+class Q_AUTOTEST_EXPORT QComboBoxPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QComboBox)
+public:
+ QComboBoxPrivate();
+ ~QComboBoxPrivate() {}
+ void init();
+ QComboBoxPrivateContainer* viewContainer();
+ void updateLineEditGeometry();
+ Qt::MatchFlags matchFlags() const;
+ void _q_editingFinished();
+ void _q_returnPressed();
+ void _q_complete();
+ void _q_itemSelected(const QModelIndex &item);
+ bool contains(const QString &text, int role);
+ void emitActivated(const QModelIndex&);
+ void _q_emitHighlighted(const QModelIndex&);
+ void _q_emitCurrentIndexChanged(const QModelIndex &index);
+ void _q_modelDestroyed();
+ void _q_modelReset();
+#ifdef QT_KEYPAD_NAVIGATION
+ void _q_completerActivated();
+#endif
+ void _q_resetButton();
+ void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void _q_updateIndexBeforeChange();
+ void _q_rowsInserted(const QModelIndex & parent, int start, int end);
+ void _q_rowsRemoved(const QModelIndex & parent, int start, int end);
+ void updateArrow(QStyle::StateFlag state);
+ bool updateHoverControl(const QPoint &pos);
+ QRect popupGeometry(int screen = -1) const;
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+ int computeWidthHint() const;
+ QSize recomputeSizeHint(QSize &sh) const;
+ void adjustComboBoxSize();
+ QString itemText(const QModelIndex &index) const;
+ QIcon itemIcon(const QModelIndex &index) const;
+ int itemRole() const;
+ void updateLayoutDirection();
+ void setCurrentIndex(const QModelIndex &index);
+ void updateDelegate(bool force = false);
+ void keyboardSearchString(const QString &text);
+ void modelChanged();
+ void updateViewContainerPaletteAndOpacity();
+
+ QAbstractItemModel *model;
+ QLineEdit *lineEdit;
+ QComboBoxPrivateContainer *container;
+ QComboBox::InsertPolicy insertPolicy;
+ QComboBox::SizeAdjustPolicy sizeAdjustPolicy;
+ int minimumContentsLength;
+ QSize iconSize;
+ uint shownOnce : 1;
+ uint autoCompletion : 1;
+ uint duplicatesEnabled : 1;
+ uint frame : 1;
+ uint padding : 26;
+ int maxVisibleItems;
+ int maxCount;
+ int modelColumn;
+ bool inserting;
+ mutable QSize minimumSizeHint;
+ mutable QSize sizeHint;
+ QStyle::StateFlag arrowState;
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+ QPersistentModelIndex currentIndex;
+ QPersistentModelIndex root;
+ Qt::CaseSensitivity autoCompletionCaseSensitivity;
+ int indexBeforeChange;
+#ifndef QT_NO_COMPLETER
+ QPointer<QCompleter> completer;
+#endif
+ static QPalette viewContainerPalette(QComboBox *cmb)
+ { return cmb->d_func()->viewContainer()->palette(); }
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_COMBOBOX
+
+#endif // QCOMBOBOX_P_H
diff --git a/src/widgets/widgets/qcommandlinkbutton.cpp b/src/widgets/widgets/qcommandlinkbutton.cpp
new file mode 100644
index 0000000000..257459a96f
--- /dev/null
+++ b/src/widgets/widgets/qcommandlinkbutton.cpp
@@ -0,0 +1,410 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcommandlinkbutton.h"
+#include "qstylepainter.h"
+#include "qstyleoption.h"
+#include "qtextdocument.h"
+#include "qtextlayout.h"
+#include "qcolor.h"
+#include "qfont.h"
+#include <qmath.h>
+
+#include "private/qpushbutton_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QCommandLinkButton
+ \since 4.4
+ \brief The QCommandLinkButton widget provides a Vista style command link button.
+
+ \ingroup basicwidgets
+
+
+ The command link is a new control that was introduced by Windows Vista. It's
+ intended use is similar to that of a radio button in that it is used to choose
+ between a set of mutually exclusive options. Command link buttons should not
+ be used by themselves but rather as an alternative to radio buttons in
+ Wizards and dialogs and makes pressing the "next" button redundant.
+ The appearance is generally similar to that of a flat pushbutton, but
+ it allows for a descriptive text in addition to the normal button text.
+ By default it will also carry an arrow icon, indicating that pressing the
+ control will open another window or page.
+
+ \sa QPushButton QRadioButton
+*/
+
+/*!
+ \property QCommandLinkButton::description
+ \brief A descriptive label to complement the button text
+
+ Setting this property will set a descriptive text on the
+ button, complementing the text label. This will usually
+ be displayed in a smaller font than the primary text.
+*/
+
+/*!
+ \property QCommandLinkButton::flat
+ \brief This property determines whether the button is displayed as a flat
+ panel or with a border.
+
+ By default, this property is set to false.
+
+ \sa QPushButton::flat
+*/
+
+class QCommandLinkButtonPrivate : public QPushButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QCommandLinkButton)
+
+public:
+ QCommandLinkButtonPrivate()
+ : QPushButtonPrivate(){}
+
+ void init();
+ qreal titleSize() const;
+ bool usingVistaStyle() const;
+
+ QFont titleFont() const;
+ QFont descriptionFont() const;
+
+ QRect titleRect() const;
+ QRect descriptionRect() const;
+
+ int textOffset() const;
+ int descriptionOffset() const;
+ int descriptionHeight(int width) const;
+ QColor mergedColors(const QColor &a, const QColor &b, int value) const;
+
+ int topMargin() const { return 10; }
+ int leftMargin() const { return 7; }
+ int rightMargin() const { return 4; }
+ int bottomMargin() const { return 10; }
+
+ QString description;
+ QColor currentColor;
+};
+
+// Mix colors a and b with a ratio in the range [0-255]
+QColor QCommandLinkButtonPrivate::mergedColors(const QColor &a, const QColor &b, int value = 50) const
+{
+ Q_ASSERT(value >= 0);
+ Q_ASSERT(value <= 255);
+ QColor tmp = a;
+ tmp.setRed((tmp.red() * value) / 255 + (b.red() * (255 - value)) / 255);
+ tmp.setGreen((tmp.green() * value) / 255 + (b.green() * (255 - value)) / 255);
+ tmp.setBlue((tmp.blue() * value) / 255 + (b.blue() * (255 - value)) / 255);
+ return tmp;
+}
+
+QFont QCommandLinkButtonPrivate::titleFont() const
+{
+ Q_Q(const QCommandLinkButton);
+ QFont font = q->font();
+ if (usingVistaStyle()) {
+ font.setPointSizeF(12.0);
+ } else {
+ font.setBold(true);
+ font.setPointSizeF(9.0);
+ }
+
+ // Note the font will be resolved against
+ // QPainters font, so we need to restore the mask
+ int resolve_mask = font.resolve_mask;
+ QFont modifiedFont = q->font().resolve(font);
+ modifiedFont.detach();
+ modifiedFont.resolve_mask = resolve_mask;
+ return modifiedFont;
+}
+
+QFont QCommandLinkButtonPrivate::descriptionFont() const
+{
+ Q_Q(const QCommandLinkButton);
+ QFont font = q->font();
+ font.setPointSizeF(9.0);
+
+ // Note the font will be resolved against
+ // QPainters font, so we need to restore the mask
+ int resolve_mask = font.resolve_mask;
+ QFont modifiedFont = q->font().resolve(font);
+ modifiedFont.detach();
+ modifiedFont.resolve_mask = resolve_mask;
+ return modifiedFont;
+}
+
+QRect QCommandLinkButtonPrivate::titleRect() const
+{
+ Q_Q(const QCommandLinkButton);
+ QRect r = q->rect().adjusted(textOffset(), topMargin(), -rightMargin(), 0);
+ if (description.isEmpty())
+ {
+ QFontMetrics fm(titleFont());
+ r.setTop(r.top() + qMax(0, (q->icon().actualSize(q->iconSize()).height()
+ - fm.height()) / 2));
+ }
+
+ return r;
+}
+
+QRect QCommandLinkButtonPrivate::descriptionRect() const
+{
+ Q_Q(const QCommandLinkButton);
+ return q->rect().adjusted(textOffset(), descriptionOffset(),
+ -rightMargin(), -bottomMargin());
+}
+
+int QCommandLinkButtonPrivate::textOffset() const
+{
+ Q_Q(const QCommandLinkButton);
+ return q->icon().actualSize(q->iconSize()).width() + leftMargin() + 6;
+}
+
+int QCommandLinkButtonPrivate::descriptionOffset() const
+{
+ QFontMetrics fm(titleFont());
+ return topMargin() + fm.height();
+}
+
+bool QCommandLinkButtonPrivate::usingVistaStyle() const
+{
+ Q_Q(const QCommandLinkButton);
+ //### This is a hack to detect if we are indeed running Vista style themed and not in classic
+ // When we add api to query for this, we should change this implementation to use it.
+ return q->style()->inherits("QWindowsVistaStyle")
+ && !q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal);
+}
+
+void QCommandLinkButtonPrivate::init()
+{
+ Q_Q(QCommandLinkButton);
+ QPushButtonPrivate::init();
+ q->setAttribute(Qt::WA_Hover);
+
+ QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::PushButton);
+ policy.setHeightForWidth(true);
+ q->setSizePolicy(policy);
+
+ q->setIconSize(QSize(20, 20));
+ QStyleOptionButton opt;
+ q->initStyleOption(&opt);
+ q->setIcon(q->style()->standardIcon(QStyle::SP_CommandLink, &opt));
+}
+
+// Calculates the height of the description text based on widget width
+int QCommandLinkButtonPrivate::descriptionHeight(int widgetWidth) const
+{
+ // Calc width of actual paragraph
+ int lineWidth = widgetWidth - textOffset() - rightMargin();
+
+ qreal descriptionheight = 0;
+ if (!description.isEmpty()) {
+ QTextLayout layout(description);
+ layout.setFont(descriptionFont());
+ layout.beginLayout();
+ while (true) {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(lineWidth);
+ line.setPosition(QPointF(0, descriptionheight));
+ descriptionheight += line.height();
+ }
+ layout.endLayout();
+ }
+ return qCeil(descriptionheight);
+}
+
+/*!
+ \reimp
+ */
+QSize QCommandLinkButton::minimumSizeHint() const
+{
+ Q_D(const QCommandLinkButton);
+ QSize size = sizeHint();
+ int minimumHeight = qMax(d->descriptionOffset() + d->bottomMargin(),
+ icon().actualSize(iconSize()).height() + d->topMargin());
+ size.setHeight(minimumHeight);
+ return size;
+}
+
+/*!
+ Constructs a command link with no text and a \a parent.
+*/
+
+QCommandLinkButton::QCommandLinkButton(QWidget *parent)
+: QPushButton(*new QCommandLinkButtonPrivate, parent)
+{
+ Q_D(QCommandLinkButton);
+ d->init();
+}
+
+/*!
+ Constructs a command link with the parent \a parent and the text \a
+ text.
+*/
+
+QCommandLinkButton::QCommandLinkButton(const QString &text, QWidget *parent)
+ : QPushButton(*new QCommandLinkButtonPrivate, parent)
+{
+ Q_D(QCommandLinkButton);
+ setText(text);
+ d->init();
+}
+
+/*!
+ Constructs a command link with a \a text, a \a description, and a \a parent.
+*/
+QCommandLinkButton::QCommandLinkButton(const QString &text, const QString &description, QWidget *parent)
+ : QPushButton(*new QCommandLinkButtonPrivate, parent)
+{
+ Q_D(QCommandLinkButton);
+ setText(text);
+ setDescription(description);
+ d->init();
+}
+
+/*! \reimp */
+bool QCommandLinkButton::event(QEvent *e)
+{
+ return QPushButton::event(e);
+}
+
+/*! \reimp */
+QSize QCommandLinkButton::sizeHint() const
+{
+// Standard size hints from UI specs
+// Without note: 135, 41
+// With note: 135, 60
+ Q_D(const QCommandLinkButton);
+
+ QSize size = QPushButton::sizeHint();
+ QFontMetrics fm(d->titleFont());
+ int textWidth = qMax(fm.width(text()), 135);
+ int buttonWidth = textWidth + d->textOffset() + d->rightMargin();
+ int heightWithoutDescription = d->descriptionOffset() + d->bottomMargin();
+
+ size.setWidth(qMax(size.width(), buttonWidth));
+ size.setHeight(qMax(d->description.isEmpty() ? 41 : 60,
+ heightWithoutDescription + d->descriptionHeight(buttonWidth)));
+ return size;
+}
+
+/*! \reimp */
+int QCommandLinkButton::heightForWidth(int width) const
+{
+ Q_D(const QCommandLinkButton);
+ int heightWithoutDescription = d->descriptionOffset() + d->bottomMargin();
+ // find the width available for the description area
+ return qMax(heightWithoutDescription + d->descriptionHeight(width),
+ icon().actualSize(iconSize()).height() + d->topMargin() +
+ d->bottomMargin());
+}
+
+/*! \reimp */
+void QCommandLinkButton::paintEvent(QPaintEvent *)
+{
+ Q_D(QCommandLinkButton);
+ QStylePainter p(this);
+ p.save();
+
+ QStyleOptionButton option;
+ initStyleOption(&option);
+
+ //Enable command link appearance on Vista
+ option.features |= QStyleOptionButton::CommandLinkButton;
+ option.text = QString();
+ option.icon = QIcon(); //we draw this ourselves
+ QSize pixmapSize = icon().actualSize(iconSize());
+
+ int vOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical) : 0;
+ int hOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal) : 0;
+
+ //Draw icon
+ p.drawControl(QStyle::CE_PushButton, option);
+ if (!icon().isNull())
+ p.drawPixmap(d->leftMargin() + hOffset, d->topMargin() + vOffset,
+ icon().pixmap(pixmapSize, isEnabled() ? QIcon::Normal : QIcon::Disabled,
+ isChecked() ? QIcon::On : QIcon::Off));
+
+ //Draw title
+ QColor textColor = palette().buttonText().color();
+ if (isEnabled() && d->usingVistaStyle()) {
+ textColor = QColor(21, 28, 85);
+ if (underMouse() && !isDown())
+ textColor = QColor(7, 64, 229);
+ //A simple text color transition
+ d->currentColor = d->mergedColors(textColor, d->currentColor, 60);
+ option.palette.setColor(QPalette::ButtonText, d->currentColor);
+ }
+
+ int textflags = Qt::TextShowMnemonic;
+ if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &option, this))
+ textflags |= Qt::TextHideMnemonic;
+
+ p.setFont(d->titleFont());
+ p.drawItemText(d->titleRect().translated(hOffset, vOffset),
+ textflags, option.palette, isEnabled(), text(), QPalette::ButtonText);
+
+ //Draw description
+ textflags |= Qt::TextWordWrap | Qt::ElideRight;
+ p.setFont(d->descriptionFont());
+ p.drawItemText(d->descriptionRect().translated(hOffset, vOffset), textflags,
+ option.palette, isEnabled(), description(), QPalette::ButtonText);
+ p.restore();
+}
+
+void QCommandLinkButton::setDescription(const QString &description)
+{
+ Q_D(QCommandLinkButton);
+ d->description = description;
+ updateGeometry();
+ update();
+}
+
+QString QCommandLinkButton::description() const
+{
+ Q_D(const QCommandLinkButton);
+ return d->description;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/widgets/widgets/qcommandlinkbutton.h b/src/widgets/widgets/qcommandlinkbutton.h
new file mode 100644
index 0000000000..9d01e37b1b
--- /dev/null
+++ b/src/widgets/widgets/qcommandlinkbutton.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMMANDLINKBUTTON_H
+#define QCOMMANDLINKBUTTON_H
+
+#include <QtWidgets/qpushbutton.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QCommandLinkButtonPrivate;
+
+class Q_WIDGETS_EXPORT QCommandLinkButton: public QPushButton
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString description READ description WRITE setDescription)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat DESIGNABLE false)
+
+public:
+ explicit QCommandLinkButton(QWidget *parent=0);
+ explicit QCommandLinkButton(const QString &text, QWidget *parent=0);
+ QCommandLinkButton(const QString &text, const QString &description, QWidget *parent=0);
+ QString description() const;
+ void setDescription(const QString &description);
+
+protected:
+ QSize sizeHint() const;
+ int heightForWidth(int) const;
+ QSize minimumSizeHint() const;
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *);
+
+private:
+ Q_DISABLE_COPY(QCommandLinkButton)
+ Q_DECLARE_PRIVATE(QCommandLinkButton)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOMMANDLINKBUTTON
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp
new file mode 100644
index 0000000000..d9ff8a6bad
--- /dev/null
+++ b/src/widgets/widgets/qdatetimeedit.cpp
@@ -0,0 +1,2655 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <math.h>
+#include <private/qdatetimeedit_p.h>
+#include <qabstractspinbox.h>
+#include <qapplication.h>
+#include <qdatetimeedit.h>
+#include <qdesktopwidget.h>
+#include <qdebug.h>
+#include <qevent.h>
+#include <qlineedit.h>
+#include <private/qlineedit_p.h>
+#include <qlocale.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qset.h>
+#include <qstyle.h>
+
+#ifndef QT_NO_DATETIMEEDIT
+
+//#define QDATETIMEEDIT_QDTEDEBUG
+#ifdef QDATETIMEEDIT_QDTEDEBUG
+# define QDTEDEBUG qDebug() << QString::fromLatin1("%1:%2").arg(__FILE__).arg(__LINE__)
+# define QDTEDEBUGN qDebug
+#else
+# define QDTEDEBUG if (false) qDebug()
+# define QDTEDEBUGN if (false) qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// --- QDateTimeEdit ---
+
+/*!
+ \class QDateTimeEdit
+ \brief The QDateTimeEdit class provides a widget for editing dates and times.
+
+ \ingroup basicwidgets
+
+
+ QDateTimeEdit allows the user to edit dates by using the keyboard or
+ the arrow keys to increase and decrease date and time values. The
+ arrow keys can be used to move from section to section within the
+ QDateTimeEdit box. Dates and times appear in accordance with the
+ format set; see setDisplayFormat().
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 0
+
+ Here we've created a new QDateTimeEdit object initialized with
+ today's date, and restricted the valid date range to today plus or
+ minus 365 days. We've set the order to month, day, year.
+
+ The minimum value for QDateTimeEdit is 14 September 1752,
+ and 2 January 4713BC for QDate. You can change this by calling
+ setMinimumDate(), setMaximumDate(), setMinimumTime(),
+ and setMaximumTime().
+
+ \section1 Using a Pop-up Calendar Widget
+
+ QDateTimeEdit can be configured to allow a QCalendarWidget to be used
+ to select dates. This is enabled by setting the calendarPopup property.
+ Additionally, you can supply a custom calendar widget for use as the
+ calendar pop-up by calling the setCalendarWidget() function. The existing
+ calendar widget can be retrieved with calendarWidget().
+
+ \table 100%
+ \row \o \inlineimage windowsxp-datetimeedit.png Screenshot of a Windows XP style date time editing widget
+ \o A date time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage macintosh-datetimeedit.png Screenshot of a Macintosh style date time editing widget
+ \o A date time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage plastique-datetimeedit.png Screenshot of a Plastique style date time editing widget
+ \o A date time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QDateEdit, QTimeEdit, QDate, QTime
+*/
+
+/*!
+ \enum QDateTimeEdit::Section
+
+ \value NoSection
+ \value AmPmSection
+ \value MSecSection
+ \value SecondSection
+ \value MinuteSection
+ \value HourSection
+ \value DaySection
+ \value MonthSection
+ \value YearSection
+ \omitvalue DateSections_Mask
+ \omitvalue TimeSections_Mask
+*/
+
+/*!
+ \fn void QDateTimeEdit::dateTimeChanged(const QDateTime &datetime)
+
+ This signal is emitted whenever the date or time is changed. The
+ new date and time is passed in \a datetime.
+*/
+
+/*!
+ \fn void QDateTimeEdit::timeChanged(const QTime &time)
+
+ This signal is emitted whenever the time is changed. The new time
+ is passed in \a time.
+*/
+
+/*!
+ \fn void QDateTimeEdit::dateChanged(const QDate &date)
+
+ This signal is emitted whenever the date is changed. The new date
+ is passed in \a date.
+*/
+
+
+/*!
+ Constructs an empty date time editor with a \a parent.
+*/
+
+QDateTimeEdit::QDateTimeEdit(QWidget *parent)
+ : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
+{
+ Q_D(QDateTimeEdit);
+ d->init(QDateTime(QDATETIMEEDIT_DATE_INITIAL, QDATETIMEEDIT_TIME_MIN));
+}
+
+/*!
+ Constructs an empty date time editor with a \a parent. The value
+ is set to \a datetime.
+*/
+
+QDateTimeEdit::QDateTimeEdit(const QDateTime &datetime, QWidget *parent)
+ : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
+{
+ Q_D(QDateTimeEdit);
+ d->init(datetime.isValid() ? datetime : QDateTime(QDATETIMEEDIT_DATE_INITIAL,
+ QDATETIMEEDIT_TIME_MIN));
+}
+
+/*!
+ \fn QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent)
+
+ Constructs an empty date time editor with a \a parent.
+ The value is set to \a date.
+*/
+
+QDateTimeEdit::QDateTimeEdit(const QDate &date, QWidget *parent)
+ : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
+{
+ Q_D(QDateTimeEdit);
+ d->init(date.isValid() ? date : QDATETIMEEDIT_DATE_INITIAL);
+}
+
+/*!
+ \fn QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent)
+
+ Constructs an empty date time editor with a \a parent.
+ The value is set to \a time.
+*/
+
+QDateTimeEdit::QDateTimeEdit(const QTime &time, QWidget *parent)
+ : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
+{
+ Q_D(QDateTimeEdit);
+ d->init(time.isValid() ? time : QDATETIMEEDIT_TIME_MIN);
+}
+
+/*!
+ \internal
+*/
+
+QDateTimeEdit::QDateTimeEdit(const QVariant &var, QVariant::Type parserType, QWidget *parent)
+ : QAbstractSpinBox(*new QDateTimeEditPrivate, parent)
+{
+ Q_D(QDateTimeEdit);
+ d->parserType = parserType;
+ d->init(var);
+}
+
+/*!
+ \property QDateTimeEdit::dateTime
+ \brief the QDateTime that is set in the QDateTimeEdit
+
+ When setting this property the timespec of the QDateTimeEdit remains the same
+ and the timespec of the new QDateTime is ignored.
+
+ By default, this property contains a date that refers to January 1,
+ 2000 and a time of 00:00:00 and 0 milliseconds.
+
+ \sa date, time
+*/
+
+QDateTime QDateTimeEdit::dateTime() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->value.toDateTime();
+}
+
+void QDateTimeEdit::setDateTime(const QDateTime &datetime)
+{
+ Q_D(QDateTimeEdit);
+ if (datetime.isValid()) {
+ d->clearCache();
+ if (!(d->sections & DateSections_Mask))
+ setDateRange(datetime.date(), datetime.date());
+ d->setValue(QDateTime(datetime.date(), datetime.time(), d->spec), EmitIfChanged);
+ }
+}
+
+/*!
+ \property QDateTimeEdit::date
+ \brief the QDate that is set in the widget
+
+ By default, this property contains a date that refers to January 1, 2000.
+
+ \sa time, dateTime
+*/
+
+/*!
+ Returns the date of the date time edit.
+*/
+QDate QDateTimeEdit::date() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->value.toDate();
+}
+
+void QDateTimeEdit::setDate(const QDate &date)
+{
+ Q_D(QDateTimeEdit);
+ if (date.isValid()) {
+ if (!(d->sections & DateSections_Mask))
+ setDateRange(date, date);
+
+ d->clearCache();
+ d->setValue(QDateTime(date, d->value.toTime(), d->spec), EmitIfChanged);
+ d->updateTimeSpec();
+ }
+}
+
+/*!
+ \property QDateTimeEdit::time
+ \brief the QTime that is set in the widget
+
+ By default, this property contains a time of 00:00:00 and 0 milliseconds.
+
+ \sa date, dateTime
+*/
+
+/*!
+ Returns the time of the date time edit.
+*/
+QTime QDateTimeEdit::time() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->value.toTime();
+}
+
+void QDateTimeEdit::setTime(const QTime &time)
+{
+ Q_D(QDateTimeEdit);
+ if (time.isValid()) {
+ d->clearCache();
+ d->setValue(QDateTime(d->value.toDate(), time, d->spec), EmitIfChanged);
+ }
+}
+
+
+/*!
+ \property QDateTimeEdit::minimumDateTime
+ \since 4.4
+
+ \brief the minimum datetime of the date time edit
+
+ When setting this property the \l maximumDateTime() is adjusted if
+ necessary to ensure that the range remains valid. If the datetime is
+ not a valid QDateTime object, this function does nothing.
+
+ The default minimumDateTime can be restored with
+ clearMinimumDateTime()
+
+ By default, this property contains a date that refers to September 14,
+ 1752 and a time of 00:00:00 and 0 milliseconds.
+
+ \sa maximumDateTime(), minimumTime(), maximumTime(), minimumDate(),
+ maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
+ clearMaximumDateTime(), clearMinimumDate(),
+ clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
+*/
+
+QDateTime QDateTimeEdit::minimumDateTime() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->minimum.toDateTime();
+}
+
+void QDateTimeEdit::clearMinimumDateTime()
+{
+ setMinimumDateTime(QDateTime(QDATETIMEEDIT_COMPAT_DATE_MIN, QDATETIMEEDIT_TIME_MIN));
+}
+
+void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt)
+{
+ Q_D(QDateTimeEdit);
+ if (dt.isValid() && dt.date() >= QDATETIMEEDIT_DATE_MIN) {
+ const QDateTime m = dt.toTimeSpec(d->spec);
+ const QDateTime max = d->maximum.toDateTime();
+ d->setRange(m, (max > m ? max : m));
+ }
+}
+
+/*!
+ \property QDateTimeEdit::maximumDateTime
+ \since 4.4
+
+ \brief the maximum datetime of the date time edit
+
+ When setting this property the \l minimumDateTime() is adjusted if
+ necessary to ensure that the range remains valid. If the datetime is
+ not a valid QDateTime object, this function does nothing.
+
+ The default maximumDateTime can be restored with
+ clearMaximumDateTime().
+
+ By default, this property contains a date that refers to 31 December,
+ 7999 and a time of 23:59:59 and 999 milliseconds.
+
+ \sa minimumDateTime(), minimumTime(), maximumTime(), minimumDate(),
+ maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
+ clearMinimumDateTime(), clearMinimumDate(),
+ clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
+*/
+
+QDateTime QDateTimeEdit::maximumDateTime() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->maximum.toDateTime();
+}
+
+void QDateTimeEdit::clearMaximumDateTime()
+{
+ setMaximumDateTime(QDATETIMEEDIT_DATETIME_MAX);
+}
+
+void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt)
+{
+ Q_D(QDateTimeEdit);
+ if (dt.isValid() && dt.date() <= QDATETIMEEDIT_DATE_MAX) {
+ const QDateTime m = dt.toTimeSpec(d->spec);
+ const QDateTime min = d->minimum.toDateTime();
+ d->setRange((min < m ? min : m), m);
+ }
+}
+
+
+/*!
+ Convenience function to set minimum and maximum date time with one
+ function call.
+ \since 4.4
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 1
+
+ is analogous to:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 2
+
+ If either \a min or \a max are not valid, this function does
+ nothing.
+
+ \sa setMinimumDate(), maximumDate(), setMaximumDate(),
+ clearMinimumDate(), setMinimumTime(), maximumTime(),
+ setMaximumTime(), clearMinimumTime(), QDateTime::isValid()
+*/
+
+void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max)
+{
+ Q_D(QDateTimeEdit);
+ const QDateTime minimum = min.toTimeSpec(d->spec);
+ QDateTime maximum = max.toTimeSpec(d->spec);
+ if (min > max)
+ maximum = minimum;
+ d->setRange(minimum, maximum);
+}
+
+/*!
+ \property QDateTimeEdit::minimumDate
+
+ \brief the minimum date of the date time edit
+
+ When setting this property the \l maximumDate is adjusted if
+ necessary, to ensure that the range remains valid. If the date is
+ not a valid QDate object, this function does nothing.
+
+ By default, this property contains a date that refers to September 14, 1752.
+ The minimum date must be at least the first day in year 100, otherwise
+ setMinimumDate() has no effect.
+
+ \sa minimumTime(), maximumTime(), setDateRange()
+*/
+
+QDate QDateTimeEdit::minimumDate() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->minimum.toDate();
+}
+
+void QDateTimeEdit::setMinimumDate(const QDate &min)
+{
+ Q_D(QDateTimeEdit);
+ if (min.isValid() && min >= QDATETIMEEDIT_DATE_MIN) {
+ setMinimumDateTime(QDateTime(min, d->minimum.toTime(), d->spec));
+ }
+}
+
+void QDateTimeEdit::clearMinimumDate()
+{
+ setMinimumDate(QDATETIMEEDIT_COMPAT_DATE_MIN);
+}
+
+/*!
+ \property QDateTimeEdit::maximumDate
+
+ \brief the maximum date of the date time edit
+
+ When setting this property the \l minimumDate is adjusted if
+ necessary to ensure that the range remains valid. If the date is
+ not a valid QDate object, this function does nothing.
+
+ By default, this property contains a date that refers to December 31, 7999.
+
+ \sa minimumDate, minimumTime, maximumTime, setDateRange()
+*/
+
+QDate QDateTimeEdit::maximumDate() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->maximum.toDate();
+}
+
+void QDateTimeEdit::setMaximumDate(const QDate &max)
+{
+ Q_D(QDateTimeEdit);
+ if (max.isValid()) {
+ setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec));
+ }
+}
+
+void QDateTimeEdit::clearMaximumDate()
+{
+ setMaximumDate(QDATETIMEEDIT_DATE_MAX);
+}
+
+/*!
+ \property QDateTimeEdit::minimumTime
+
+ \brief the minimum time of the date time edit
+
+ When setting this property the \l maximumTime is adjusted if
+ necessary, to ensure that the range remains valid. If the time is
+ not a valid QTime object, this function does nothing.
+
+ By default, this property contains a time of 00:00:00 and 0 milliseconds.
+
+ \sa maximumTime, minimumDate, maximumDate, setTimeRange()
+*/
+
+QTime QDateTimeEdit::minimumTime() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->minimum.toTime();
+}
+
+void QDateTimeEdit::setMinimumTime(const QTime &min)
+{
+ Q_D(QDateTimeEdit);
+ if (min.isValid()) {
+ const QDateTime m(d->minimum.toDate(), min, d->spec);
+ setMinimumDateTime(m);
+ }
+}
+
+void QDateTimeEdit::clearMinimumTime()
+{
+ setMinimumTime(QDATETIMEEDIT_TIME_MIN);
+}
+
+/*!
+ \property QDateTimeEdit::maximumTime
+
+ \brief the maximum time of the date time edit
+
+ When setting this property, the \l minimumTime is adjusted if
+ necessary to ensure that the range remains valid. If the time is
+ not a valid QTime object, this function does nothing.
+
+ By default, this property contains a time of 23:59:59 and 999 milliseconds.
+
+ \sa minimumTime, minimumDate, maximumDate, setTimeRange()
+*/
+QTime QDateTimeEdit::maximumTime() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->maximum.toTime();
+}
+
+void QDateTimeEdit::setMaximumTime(const QTime &max)
+{
+ Q_D(QDateTimeEdit);
+ if (max.isValid()) {
+ const QDateTime m(d->maximum.toDate(), max);
+ setMaximumDateTime(m);
+ }
+}
+
+void QDateTimeEdit::clearMaximumTime()
+{
+ setMaximumTime(QDATETIMEEDIT_TIME_MAX);
+}
+
+/*!
+ Convenience function to set minimum and maximum date with one
+ function call.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 3
+
+ is analogous to:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 4
+
+ If either \a min or \a max are not valid, this function does
+ nothing.
+
+ \sa setMinimumDate(), maximumDate(), setMaximumDate(),
+ clearMinimumDate(), setMinimumTime(), maximumTime(),
+ setMaximumTime(), clearMinimumTime(), QDate::isValid()
+*/
+
+void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max)
+{
+ Q_D(QDateTimeEdit);
+ if (min.isValid() && max.isValid()) {
+ setDateTimeRange(QDateTime(min, d->minimum.toTime(), d->spec),
+ QDateTime(max, d->maximum.toTime(), d->spec));
+ }
+}
+
+/*!
+ Convenience function to set minimum and maximum time with one
+ function call.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 5
+
+ is analogous to:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qdatetimeedit.cpp 6
+
+ If either \a min or \a max are not valid, this function does
+ nothing.
+
+ \sa setMinimumDate(), maximumDate(), setMaximumDate(),
+ clearMinimumDate(), setMinimumTime(), maximumTime(),
+ setMaximumTime(), clearMinimumTime(), QTime::isValid()
+*/
+
+void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max)
+{
+ Q_D(QDateTimeEdit);
+ if (min.isValid() && max.isValid()) {
+ setDateTimeRange(QDateTime(d->minimum.toDate(), min, d->spec),
+ QDateTime(d->maximum.toDate(), max, d->spec));
+ }
+}
+
+/*!
+ \property QDateTimeEdit::displayedSections
+
+ \brief the currently displayed fields of the date time edit
+
+ Returns a bit set of the displayed sections for this format.
+ \a setDisplayFormat(), displayFormat()
+*/
+
+QDateTimeEdit::Sections QDateTimeEdit::displayedSections() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->sections;
+}
+
+/*!
+ \property QDateTimeEdit::currentSection
+
+ \brief the current section of the spinbox
+ \a setCurrentSection()
+*/
+
+QDateTimeEdit::Section QDateTimeEdit::currentSection() const
+{
+ Q_D(const QDateTimeEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && d->focusOnButton)
+ return NoSection;
+#endif
+ return d->convertToPublic(d->sectionType(d->currentSectionIndex));
+}
+
+void QDateTimeEdit::setCurrentSection(Section section)
+{
+ Q_D(QDateTimeEdit);
+ if (section == NoSection || !(section & d->sections))
+ return;
+
+ d->updateCache(d->value, d->displayText());
+ const int size = d->sectionNodes.size();
+ int index = d->currentSectionIndex + 1;
+ for (int i=0; i<2; ++i) {
+ while (index < size) {
+ if (d->convertToPublic(d->sectionType(index)) == section) {
+ d->edit->setCursorPosition(d->sectionPos(index));
+ QDTEDEBUG << d->sectionPos(index);
+ return;
+ }
+ ++index;
+ }
+ index = 0;
+ }
+}
+
+/*!
+ \since 4.3
+
+ Returns the Section at \a index.
+
+ If the format is 'yyyy/MM/dd', sectionAt(0) returns YearSection,
+ sectionAt(1) returns MonthSection, and sectionAt(2) returns
+ YearSection,
+*/
+
+QDateTimeEdit::Section QDateTimeEdit::sectionAt(int index) const
+{
+ Q_D(const QDateTimeEdit);
+ if (index < 0 || index >= d->sectionNodes.size())
+ return NoSection;
+ return d->convertToPublic(d->sectionType(index));
+}
+
+/*!
+ \since 4.3
+
+ \property QDateTimeEdit::sectionCount
+
+ \brief the number of sections displayed.
+ If the format is 'yyyy/yy/yyyy', sectionCount returns 3
+*/
+
+int QDateTimeEdit::sectionCount() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->sectionNodes.size();
+}
+
+
+/*!
+ \since 4.3
+
+ \property QDateTimeEdit::currentSectionIndex
+
+ \brief the current section index of the spinbox
+
+ If the format is 'yyyy/MM/dd', the displayText is '2001/05/21' and
+ the cursorPosition is 5 currentSectionIndex returns 1. If the
+ cursorPosition is 3 currentSectionIndex is 0 etc.
+
+ \a setCurrentSection()
+ \sa currentSection()
+*/
+
+int QDateTimeEdit::currentSectionIndex() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->currentSectionIndex;
+}
+
+void QDateTimeEdit::setCurrentSectionIndex(int index)
+{
+ Q_D(QDateTimeEdit);
+ if (index < 0 || index >= d->sectionNodes.size())
+ return;
+ d->edit->setCursorPosition(d->sectionPos(index));
+}
+
+/*!
+ \since 4.4
+
+ \brief Returns the calendar widget for the editor if calendarPopup is
+ set to true and (sections() & DateSections_Mask) != 0.
+
+ This function creates and returns a calendar widget if none has been set.
+*/
+
+
+QCalendarWidget *QDateTimeEdit::calendarWidget() const
+{
+ Q_D(const QDateTimeEdit);
+ if (!d->calendarPopup || !(d->sections & QDateTimeParser::DateSectionMask))
+ return 0;
+ if (!d->monthCalendar) {
+ const_cast<QDateTimeEditPrivate*>(d)->initCalendarPopup();
+ }
+ return d->monthCalendar->calendarWidget();
+}
+
+/*!
+ \since 4.4
+
+ Sets the given \a calendarWidget as the widget to be used for the calendar
+ pop-up. The editor does not automatically take ownership of the calendar widget.
+
+ \note calendarPopup must be set to true before setting the calendar widget.
+ \sa calendarPopup
+*/
+void QDateTimeEdit::setCalendarWidget(QCalendarWidget *calendarWidget)
+{
+ Q_D(QDateTimeEdit);
+ if (!calendarWidget) {
+ qWarning("QDateTimeEdit::setCalendarWidget: Cannot set a null calendar widget");
+ return;
+ }
+
+ if (!d->calendarPopup) {
+ qWarning("QDateTimeEdit::setCalendarWidget: calendarPopup is set to false");
+ return;
+ }
+
+ if (!(d->display & QDateTimeParser::DateSectionMask)) {
+ qWarning("QDateTimeEdit::setCalendarWidget: no date sections specified");
+ return;
+ }
+ d->initCalendarPopup(calendarWidget);
+}
+
+
+/*!
+ \since 4.2
+
+ Selects \a section. If \a section doesn't exist in the currently
+ displayed sections this function does nothing. If \a section is
+ NoSection this function will unselect all text in the editor.
+ Otherwise this function will move the cursor and the current section
+ to the selected section.
+
+ \sa currentSection()
+*/
+
+void QDateTimeEdit::setSelectedSection(Section section)
+{
+ Q_D(QDateTimeEdit);
+ if (section == NoSection) {
+ d->edit->setSelection(d->edit->cursorPosition(), 0);
+ } else if (section & d->sections) {
+ if (currentSection() != section)
+ setCurrentSection(section);
+ d->setSelected(d->currentSectionIndex);
+ }
+}
+
+
+
+/*!
+ \fn QString QDateTimeEdit::sectionText(Section section) const
+
+ Returns the text from the given \a section.
+
+ \sa currentSection()
+*/
+
+QString QDateTimeEdit::sectionText(Section section) const
+{
+ Q_D(const QDateTimeEdit);
+ if (section == QDateTimeEdit::NoSection || !(section & d->sections)) {
+ return QString();
+ }
+
+ d->updateCache(d->value, d->displayText());
+ const int sectionIndex = d->absoluteIndex(section, 0);
+ return d->sectionText(sectionIndex);
+}
+
+/*!
+ \property QDateTimeEdit::displayFormat
+
+ \brief the format used to display the time/date of the date time edit
+
+ This format is the same as the one used described in QDateTime::toString()
+ and QDateTime::fromString()
+
+ Example format strings (assuming that the date is 2nd of July 1969):
+
+ \table
+ \header \i Format \i Result
+ \row \i dd.MM.yyyy \i 02.07.1969
+ \row \i MMM d yy \i Jul 2 69
+ \row \i MMMM d yy \i July 2 69
+ \endtable
+
+ Note that if you specify a two digit year, it will be interpreted
+ to be in the century in which the date time edit was initialized.
+ The default century is the 21 (2000-2099).
+
+ If you specify an invalid format the format will not be set.
+
+ \sa QDateTime::toString(), displayedSections()
+*/
+
+QString QDateTimeEdit::displayFormat() const
+{
+ Q_D(const QDateTimeEdit);
+ return isRightToLeft() ? d->unreversedFormat : d->displayFormat;
+}
+
+template<typename C> static inline C reverse(const C &l)
+{
+ C ret;
+ for (int i=l.size() - 1; i>=0; --i)
+ ret.append(l.at(i));
+ return ret;
+}
+
+void QDateTimeEdit::setDisplayFormat(const QString &format)
+{
+ Q_D(QDateTimeEdit);
+ if (d->parseFormat(format)) {
+ d->unreversedFormat.clear();
+ if (isRightToLeft()) {
+ d->unreversedFormat = format;
+ d->displayFormat.clear();
+ for (int i=d->sectionNodes.size() - 1; i>=0; --i) {
+ d->displayFormat += d->separators.at(i + 1);
+ d->displayFormat += d->sectionFormat(i);
+ }
+ d->displayFormat += d->separators.at(0);
+ d->separators = reverse(d->separators);
+ d->sectionNodes = reverse(d->sectionNodes);
+ }
+
+ d->formatExplicitlySet = true;
+ d->sections = d->convertSections(d->display);
+ d->clearCache();
+
+ d->currentSectionIndex = qMin(d->currentSectionIndex, d->sectionNodes.size() - 1);
+ const bool timeShown = (d->sections & TimeSections_Mask);
+ const bool dateShown = (d->sections & DateSections_Mask);
+ Q_ASSERT(dateShown || timeShown);
+ if (timeShown && !dateShown) {
+ QTime time = d->value.toTime();
+ setDateRange(d->value.toDate(), d->value.toDate());
+ if (d->minimum.toTime() >= d->maximum.toTime()) {
+ setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
+ // if the time range became invalid during the adjustment, the time would have been reset
+ setTime(time);
+ }
+ } else if (dateShown && !timeShown) {
+ setTimeRange(QDATETIMEEDIT_TIME_MIN, QDATETIMEEDIT_TIME_MAX);
+ d->value = QDateTime(d->value.toDate(), QTime(), d->spec);
+ }
+ d->updateEdit();
+ d->_q_editorCursorPositionChanged(-1, 0);
+ }
+}
+
+/*!
+ \property QDateTimeEdit::calendarPopup
+ \brief the current calendar pop-up showing mode.
+ \since 4.2
+
+ The calendar pop-up will be shown upon clicking the arrow button.
+ This property is valid only if there is a valid date display format.
+
+ \sa setDisplayFormat()
+*/
+
+bool QDateTimeEdit::calendarPopup() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->calendarPopup;
+}
+
+void QDateTimeEdit::setCalendarPopup(bool enable)
+{
+ Q_D(QDateTimeEdit);
+ if (enable == d->calendarPopup)
+ return;
+ setAttribute(Qt::WA_MacShowFocusRect, !enable);
+ d->calendarPopup = enable;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!enable)
+ d->focusOnButton = false;
+#endif
+ d->updateEditFieldGeometry();
+ update();
+}
+
+/*!
+ \property QDateTimeEdit::timeSpec
+ \brief the current timespec used by the date time edit.
+ \since 4.4
+*/
+
+Qt::TimeSpec QDateTimeEdit::timeSpec() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->spec;
+}
+
+void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec)
+{
+ Q_D(QDateTimeEdit);
+ if (spec != d->spec) {
+ d->spec = spec;
+ d->updateTimeSpec();
+ }
+}
+
+/*!
+ \reimp
+*/
+
+QSize QDateTimeEdit::sizeHint() const
+{
+ Q_D(const QDateTimeEdit);
+ if (d->cachedSizeHint.isEmpty()) {
+ ensurePolished();
+
+ const QFontMetrics fm(fontMetrics());
+ int h = d->edit->sizeHint().height();
+ int w = 0;
+ QString s;
+ s = d->textFromValue(d->minimum) + QLatin1String(" ");
+ w = qMax<int>(w, fm.width(s));
+ s = d->textFromValue(d->maximum) + QLatin1String(" ");
+ w = qMax<int>(w, fm.width(s));
+ if (d->specialValueText.size()) {
+ s = d->specialValueText;
+ w = qMax<int>(w, fm.width(s));
+ }
+ w += 2; // cursor blinking space
+
+ QSize hint(w, h);
+
+#ifdef Q_WS_MAC
+ if (d->calendarPopupEnabled()) {
+ QStyleOptionComboBox opt;
+ d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, hint, this);
+ } else {
+#else
+ {
+#endif
+ QSize extra(35, 6);
+ QStyleOptionSpinBox opt;
+ initStyleOption(&opt);
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ // get closer to final result by repeating the calculation
+ opt.rect.setSize(hint + extra);
+ extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
+ QStyle::SC_SpinBoxEditField, this).size();
+ hint += extra;
+
+ opt.rect = rect();
+ d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
+ .expandedTo(QApplication::globalStrut());
+ }
+
+ d->cachedMinimumSizeHint = d->cachedSizeHint;
+ // essentially make minimumSizeHint return the same as sizeHint for datetimeedits
+ }
+ return d->cachedSizeHint;
+}
+
+/*!
+ \reimp
+*/
+
+bool QDateTimeEdit::event(QEvent *event)
+{
+ Q_D(QDateTimeEdit);
+ switch (event->type()) {
+ case QEvent::ApplicationLayoutDirectionChange: {
+ const bool was = d->formatExplicitlySet;
+ const QString oldFormat = d->displayFormat;
+ d->displayFormat.clear();
+ setDisplayFormat(oldFormat);
+ d->formatExplicitlySet = was;
+ break; }
+ case QEvent::LocaleChange:
+ d->updateEdit();
+ break;
+ case QEvent::StyleChange:
+#ifdef Q_WS_MAC
+ case QEvent::MacSizeChange:
+#endif
+ d->setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
+ break;
+ default:
+ break;
+ }
+ return QAbstractSpinBox::event(event);
+}
+
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::clear()
+{
+ Q_D(QDateTimeEdit);
+ d->clearSection(d->currentSectionIndex);
+}
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QDateTimeEdit);
+ int oldCurrent = d->currentSectionIndex;
+ bool select = true;
+ bool inserted = false;
+
+ switch (event->key()) {
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_NumberSign: //shortcut to popup calendar
+ if (QApplication::keypadNavigationEnabled() && d->calendarPopupEnabled()) {
+ d->initCalendarPopup();
+ d->positionCalendarPopup();
+ d->monthCalendar->show();
+ return;
+ }
+ break;
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (hasEditFocus()) {
+ if (d->focusOnButton) {
+ d->initCalendarPopup();
+ d->positionCalendarPopup();
+ d->monthCalendar->show();
+ d->focusOnButton = false;
+ return;
+ }
+ setEditFocus(false);
+ selectAll();
+ } else {
+ setEditFocus(true);
+
+ //hide cursor
+ d->edit->d_func()->setCursorVisible(false);
+ d->edit->d_func()->control->setCursorBlinkPeriod(0);
+ d->setSelected(0);
+ }
+ }
+ return;
+#endif
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ d->interpret(AlwaysEmit);
+ d->setSelected(d->currentSectionIndex, true);
+ event->ignore();
+ emit editingFinished();
+ return;
+ default:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()
+ && !event->text().isEmpty() && event->text().at(0).isLetterOrNumber()) {
+ setEditFocus(true);
+
+ //hide cursor
+ d->edit->d_func()->setCursorVisible(false);
+ d->edit->d_func()->control->setCursorBlinkPeriod(0);
+ d->setSelected(0);
+ oldCurrent = 0;
+ }
+#endif
+ if (!d->isSeparatorKey(event)) {
+ inserted = select = !event->text().isEmpty() && event->text().at(0).isPrint()
+ && !(event->modifiers() & ~(Qt::ShiftModifier|Qt::KeypadModifier));
+ break;
+ }
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {
+ if (
+#ifdef QT_KEYPAD_NAVIGATION
+ QApplication::keypadNavigationEnabled() && !hasEditFocus()
+ || !QApplication::keypadNavigationEnabled() &&
+#endif
+ !(event->modifiers() & Qt::ControlModifier)) {
+ select = false;
+ break;
+ }
+#ifdef Q_WS_MAC
+ else
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled())
+#endif
+ {
+ select = (event->modifiers() & Qt::ShiftModifier);
+ break;
+ }
+#endif
+ }
+ // else fall through
+ case Qt::Key_Backtab:
+ case Qt::Key_Tab: {
+ event->accept();
+ if (d->specialValue()) {
+ d->edit->setSelection(d->edit->cursorPosition(), 0);
+ return;
+ }
+ const bool forward = event->key() != Qt::Key_Left && event->key() != Qt::Key_Backtab
+ && (event->key() != Qt::Key_Tab || !(event->modifiers() & Qt::ShiftModifier));
+#ifdef QT_KEYPAD_NAVIGATION
+ int newSection = d->nextPrevSection(d->currentSectionIndex, forward);
+ if (QApplication::keypadNavigationEnabled()) {
+ if (d->focusOnButton) {
+ newSection = forward ? 0 : d->sectionNodes.size() - 1;
+ d->focusOnButton = false;
+ update();
+ } else if (newSection < 0 && select && d->calendarPopupEnabled()) {
+ setSelectedSection(NoSection);
+ d->focusOnButton = true;
+ update();
+ return;
+ }
+ }
+ // only allow date/time sections to be selected.
+ if (newSection & ~(QDateTimeParser::TimeSectionMask | QDateTimeParser::DateSectionMask))
+ return;
+#endif
+ //key tab and backtab will be managed thrgout QWidget::event
+ if (event->key() != Qt::Key_Backtab && event->key() != Qt::Key_Tab)
+ focusNextPrevChild(forward);
+
+ return; }
+ }
+ QAbstractSpinBox::keyPressEvent(event);
+ if (select && !d->edit->hasSelectedText()) {
+ if (inserted && d->sectionAt(d->edit->cursorPosition()) == QDateTimeParser::NoSectionIndex) {
+ QString str = d->displayText();
+ int pos = d->edit->cursorPosition();
+ if (validate(str, pos) == QValidator::Acceptable
+ && (d->sectionNodes.at(oldCurrent).count != 1
+ || d->sectionMaxSize(oldCurrent) == d->sectionSize(oldCurrent)
+ || d->skipToNextSection(oldCurrent, d->value.toDateTime(), d->sectionText(oldCurrent)))) {
+ QDTEDEBUG << "Setting currentsection to"
+ << d->closestSection(d->edit->cursorPosition(), true) << event->key()
+ << oldCurrent << str;
+ const int tmp = d->closestSection(d->edit->cursorPosition(), true);
+ if (tmp >= 0)
+ d->currentSectionIndex = tmp;
+ }
+ }
+ if (d->currentSectionIndex != oldCurrent) {
+ d->setSelected(d->currentSectionIndex);
+ }
+ }
+ if (d->specialValue()) {
+ d->edit->setSelection(d->edit->cursorPosition(), 0);
+ }
+}
+
+/*!
+ \reimp
+*/
+
+#ifndef QT_NO_WHEELEVENT
+void QDateTimeEdit::wheelEvent(QWheelEvent *event)
+{
+ QAbstractSpinBox::wheelEvent(event);
+}
+#endif
+
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QDateTimeEdit);
+ QAbstractSpinBox::focusInEvent(event);
+ QString *frm = 0;
+ const int oldPos = d->edit->cursorPosition();
+ if (!d->formatExplicitlySet) {
+ if (d->displayFormat == d->defaultTimeFormat) {
+ frm = &d->defaultTimeFormat;
+ } else if (d->displayFormat == d->defaultDateFormat) {
+ frm = &d->defaultDateFormat;
+ } else if (d->displayFormat == d->defaultDateTimeFormat) {
+ frm = &d->defaultDateTimeFormat;
+ }
+
+ if (frm) {
+ d->readLocaleSettings();
+ if (d->displayFormat != *frm) {
+ setDisplayFormat(*frm);
+ d->formatExplicitlySet = false;
+ d->edit->setCursorPosition(oldPos);
+ }
+ }
+ }
+ const bool oldHasHadFocus = d->hasHadFocus;
+ d->hasHadFocus = true;
+ bool first = true;
+ switch (event->reason()) {
+ case Qt::BacktabFocusReason:
+ first = false;
+ break;
+ case Qt::MouseFocusReason:
+ case Qt::PopupFocusReason:
+ return;
+ case Qt::ActiveWindowFocusReason:
+ if (oldHasHadFocus)
+ return;
+ case Qt::ShortcutFocusReason:
+ case Qt::TabFocusReason:
+ default:
+ break;
+ }
+ if (isRightToLeft())
+ first = !first;
+ d->updateEdit(); // needed to make it update specialValueText
+
+ d->setSelected(first ? 0 : d->sectionNodes.size() - 1);
+}
+
+/*!
+ \reimp
+*/
+
+bool QDateTimeEdit::focusNextPrevChild(bool next)
+{
+ Q_D(QDateTimeEdit);
+ const int newSection = d->nextPrevSection(d->currentSectionIndex, next);
+ switch (d->sectionType(newSection)) {
+ case QDateTimeParser::NoSection:
+ case QDateTimeParser::FirstSection:
+ case QDateTimeParser::LastSection:
+ return QAbstractSpinBox::focusNextPrevChild(next);
+ default:
+ d->edit->deselect();
+ d->edit->setCursorPosition(d->sectionPos(newSection));
+ QDTEDEBUG << d->sectionPos(newSection);
+ d->setSelected(newSection, true);
+ return false;
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::stepBy(int steps)
+{
+ Q_D(QDateTimeEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ // with keypad navigation and not editFocus, left right change the date/time by a fixed amount.
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ // if date based, shift by day. else shift by 15min
+ if (d->sections & DateSections_Mask) {
+ setDateTime(dateTime().addDays(steps));
+ } else {
+ int minutes = time().hour()*60 + time().minute();
+ int blocks = minutes/15;
+ blocks += steps;
+ /* rounding involved */
+ if (minutes % 15) {
+ if (steps < 0) {
+ blocks += 1; // do one less step;
+ }
+ }
+
+ minutes = blocks * 15;
+
+ /* need to take wrapping into account */
+ if (!d->wrapping) {
+ int max_minutes = d->maximum.toTime().hour()*60 + d->maximum.toTime().minute();
+ int min_minutes = d->minimum.toTime().hour()*60 + d->minimum.toTime().minute();
+
+ if (minutes >= max_minutes) {
+ setTime(maximumTime());
+ return;
+ } else if (minutes <= min_minutes) {
+ setTime(minimumTime());
+ return;
+ }
+ }
+ setTime(QTime(minutes/60, minutes%60));
+ }
+ return;
+ }
+#endif
+ // don't optimize away steps == 0. This is the only way to select
+ // the currentSection in Qt 4.1.x
+ if (d->specialValue() && displayedSections() != AmPmSection) {
+ for (int i=0; i<d->sectionNodes.size(); ++i) {
+ if (d->sectionType(i) != QDateTimeParser::AmPmSection) {
+ d->currentSectionIndex = i;
+ break;
+ }
+ }
+ }
+ d->setValue(d->stepBy(d->currentSectionIndex, steps, false), EmitIfChanged);
+ d->updateCache(d->value, d->displayText());
+
+ d->setSelected(d->currentSectionIndex);
+ d->updateTimeSpec();
+}
+
+/*!
+ This virtual function is used by the date time edit whenever it
+ needs to display \a dateTime.
+
+ If you reimplement this, you may also need to reimplement validate().
+
+ \sa dateTimeFromText(), validate()
+*/
+QString QDateTimeEdit::textFromDateTime(const QDateTime &dateTime) const
+{
+ Q_D(const QDateTimeEdit);
+ return locale().toString(dateTime, d->displayFormat);
+}
+
+
+/*!
+ Returns an appropriate datetime for the given \a text.
+
+ This virtual function is used by the datetime edit whenever it
+ needs to interpret text entered by the user as a value.
+
+ \sa textFromDateTime(), validate()
+*/
+QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const
+{
+ Q_D(const QDateTimeEdit);
+ QString copy = text;
+ int pos = d->edit->cursorPosition();
+ QValidator::State state = QValidator::Acceptable;
+ return d->validateAndInterpret(copy, pos, state);
+}
+
+/*!
+ \reimp
+*/
+
+QValidator::State QDateTimeEdit::validate(QString &text, int &pos) const
+{
+ Q_D(const QDateTimeEdit);
+ QValidator::State state;
+ d->validateAndInterpret(text, pos, state);
+ return state;
+}
+
+/*!
+ \reimp
+*/
+
+
+void QDateTimeEdit::fixup(QString &input) const
+{
+ Q_D(const QDateTimeEdit);
+ QValidator::State state;
+ int copy = d->edit->cursorPosition();
+
+ d->validateAndInterpret(input, copy, state, true);
+}
+
+
+/*!
+ \reimp
+*/
+
+QDateTimeEdit::StepEnabled QDateTimeEdit::stepEnabled() const
+{
+ Q_D(const QDateTimeEdit);
+ if (d->readOnly)
+ return StepEnabled(0);
+ if (d->specialValue()) {
+ return (d->minimum == d->maximum ? StepEnabled(0) : StepEnabled(StepUpEnabled));
+ }
+
+ QAbstractSpinBox::StepEnabled ret = 0;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ if (d->wrapping)
+ return StepEnabled(StepUpEnabled | StepDownEnabled);
+ // 3 cases. date, time, datetime. each case look
+ // at just the relavant component.
+ QVariant max, min, val;
+ if (!(d->sections & DateSections_Mask)) {
+ // time only, no date
+ max = d->maximum.toTime();
+ min = d->minimum.toTime();
+ val = d->value.toTime();
+ } else if (!(d->sections & TimeSections_Mask)) {
+ // date only, no time
+ max = d->maximum.toDate();
+ min = d->minimum.toDate();
+ val = d->value.toDate();
+ } else {
+ // both
+ max = d->maximum;
+ min = d->minimum;
+ val = d->value;
+ }
+ if (val != min)
+ ret |= QAbstractSpinBox::StepDownEnabled;
+ if (val != max)
+ ret |= QAbstractSpinBox::StepUpEnabled;
+ return ret;
+ }
+#endif
+ switch (d->sectionType(d->currentSectionIndex)) {
+ case QDateTimeParser::NoSection:
+ case QDateTimeParser::FirstSection:
+ case QDateTimeParser::LastSection: return 0;
+ default: break;
+ }
+ if (d->wrapping)
+ return StepEnabled(StepDownEnabled|StepUpEnabled);
+
+ QVariant v = d->stepBy(d->currentSectionIndex, 1, true);
+ if (v != d->value) {
+ ret |= QAbstractSpinBox::StepUpEnabled;
+ }
+ v = d->stepBy(d->currentSectionIndex, -1, true);
+ if (v != d->value) {
+ ret |= QAbstractSpinBox::StepDownEnabled;
+ }
+
+ return ret;
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QDateTimeEdit);
+ if (!d->calendarPopupEnabled()) {
+ QAbstractSpinBox::mousePressEvent(event);
+ return;
+ }
+ d->updateHoverControl(event->pos());
+ if (d->hoverControl == QStyle::SC_ComboBoxArrow) {
+ event->accept();
+ if (d->readOnly) {
+ return;
+ }
+ d->updateArrow(QStyle::State_Sunken);
+ d->initCalendarPopup();
+ d->positionCalendarPopup();
+ //Show the calendar
+ d->monthCalendar->show();
+ } else {
+ QAbstractSpinBox::mousePressEvent(event);
+ }
+}
+
+/*!
+ \class QTimeEdit
+ \brief The QTimeEdit class provides a widget for editing times based on
+ the QDateTimeEdit widget.
+
+ \ingroup basicwidgets
+
+
+ Many of the properties and functions provided by QTimeEdit are implemented in
+ QDateTimeEdit. The following properties are most relevant to users of this
+ class:
+
+ \list
+ \o \l{QDateTimeEdit::time}{time} holds the date displayed by the widget.
+ \o \l{QDateTimeEdit::minimumTime}{minimumTime} defines the minimum (earliest) time
+ that can be set by the user.
+ \o \l{QDateTimeEdit::maximumTime}{maximumTime} defines the maximum (latest) time
+ that can be set by the user.
+ \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
+ to format the time displayed in the widget.
+ \endlist
+
+ \table 100%
+ \row \o \inlineimage windowsxp-timeedit.png Screenshot of a Windows XP style time editing widget
+ \o A time editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage macintosh-timeedit.png Screenshot of a Macintosh style time editing widget
+ \o A time editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage plastique-timeedit.png Screenshot of a Plastique style time editing widget
+ \o A time editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QDateEdit, QDateTimeEdit
+*/
+
+/*!
+ Constructs an empty time editor with a \a parent.
+*/
+
+
+QTimeEdit::QTimeEdit(QWidget *parent)
+ : QDateTimeEdit(QDATETIMEEDIT_TIME_MIN, QVariant::Time, parent)
+{
+}
+
+/*!
+ Constructs an empty time editor with a \a parent. The time is set
+ to \a time.
+*/
+
+QTimeEdit::QTimeEdit(const QTime &time, QWidget *parent)
+ : QDateTimeEdit(time, QVariant::Time, parent)
+{
+}
+
+
+/*!
+ \class QDateEdit
+ \brief The QDateEdit class provides a widget for editing dates based on
+ the QDateTimeEdit widget.
+
+ \ingroup basicwidgets
+
+
+ Many of the properties and functions provided by QDateEdit are implemented in
+ QDateTimeEdit. The following properties are most relevant to users of this
+ class:
+
+ \list
+ \o \l{QDateTimeEdit::date}{date} holds the date displayed by the widget.
+ \o \l{QDateTimeEdit::minimumDate}{minimumDate} defines the minimum (earliest)
+ date that can be set by the user.
+ \o \l{QDateTimeEdit::maximumDate}{maximumDate} defines the maximum (latest) date
+ that can be set by the user.
+ \o \l{QDateTimeEdit::displayFormat}{displayFormat} contains a string that is used
+ to format the date displayed in the widget.
+ \endlist
+
+ \table 100%
+ \row \o \inlineimage windowsxp-dateedit.png Screenshot of a Windows XP style date editing widget
+ \o A date editing widget shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage macintosh-dateedit.png Screenshot of a Macintosh style date editing widget
+ \o A date editing widget shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage plastique-dateedit.png Screenshot of a Plastique style date editing widget
+ \o A date editing widget shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QTimeEdit, QDateTimeEdit
+*/
+
+/*!
+ Constructs an empty date editor with a \a parent.
+*/
+
+QDateEdit::QDateEdit(QWidget *parent)
+ : QDateTimeEdit(QDATETIMEEDIT_DATE_INITIAL, QVariant::Date, parent)
+{
+}
+
+/*!
+ Constructs an empty date editor with a \a parent. The date is set
+ to \a date.
+*/
+
+QDateEdit::QDateEdit(const QDate &date, QWidget *parent)
+ : QDateTimeEdit(date, QVariant::Date, parent)
+{
+}
+
+
+// --- QDateTimeEditPrivate ---
+
+/*!
+ \internal
+ Constructs a QDateTimeEditPrivate object
+*/
+
+
+QDateTimeEditPrivate::QDateTimeEditPrivate()
+ : QDateTimeParser(QVariant::DateTime, QDateTimeParser::DateTimeEdit)
+{
+ hasHadFocus = false;
+ formatExplicitlySet = false;
+ cacheGuard = false;
+ fixday = true;
+ type = QVariant::DateTime;
+ sections = 0;
+ cachedDay = -1;
+ currentSectionIndex = FirstSectionIndex;
+
+ first.type = FirstSection;
+ last.type = LastSection;
+ none.type = NoSection;
+ first.pos = 0;
+ last.pos = -1;
+ none.pos = -1;
+ sections = 0;
+ calendarPopup = false;
+ minimum = QDATETIMEEDIT_COMPAT_DATETIME_MIN;
+ maximum = QDATETIMEEDIT_DATETIME_MAX;
+ arrowState = QStyle::State_None;
+ monthCalendar = 0;
+ readLocaleSettings();
+
+#ifdef QT_KEYPAD_NAVIGATION
+ focusOnButton = false;
+#endif
+}
+
+void QDateTimeEditPrivate::updateTimeSpec()
+{
+ minimum = minimum.toDateTime().toTimeSpec(spec);
+ maximum = maximum.toDateTime().toTimeSpec(spec);
+ value = value.toDateTime().toTimeSpec(spec);
+
+ // time zone changes can lead to 00:00:00 becomes 01:00:00 and 23:59:59 becomes 00:59:59 (invalid range)
+ const bool dateShown = (sections & QDateTimeEdit::DateSections_Mask);
+ if (!dateShown) {
+ if (minimum.toTime() >= maximum.toTime()){
+ minimum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MIN, spec);
+ maximum = QDateTime(value.toDate(), QDATETIMEEDIT_TIME_MAX, spec);
+ }
+ }
+}
+
+void QDateTimeEditPrivate::updateEdit()
+{
+ const QString newText = (specialValue() ? specialValueText : textFromValue(value));
+ if (newText == displayText())
+ return;
+ int selsize = edit->selectedText().size();
+ const bool sb = edit->blockSignals(true);
+
+ edit->setText(newText);
+
+ if (!specialValue()
+#ifdef QT_KEYPAD_NAVIGATION
+ && !(QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
+#endif
+ ) {
+ int cursor = sectionPos(currentSectionIndex);
+ QDTEDEBUG << "cursor is " << cursor << currentSectionIndex;
+ cursor = qBound(0, cursor, displayText().size());
+ QDTEDEBUG << cursor;
+ if (selsize > 0) {
+ edit->setSelection(cursor, selsize);
+ QDTEDEBUG << cursor << selsize;
+ } else {
+ edit->setCursorPosition(cursor);
+ QDTEDEBUG << cursor;
+
+ }
+ }
+ edit->blockSignals(sb);
+}
+
+
+/*!
+ \internal
+
+ Selects the section \a s. If \a forward is false selects backwards.
+*/
+
+void QDateTimeEditPrivate::setSelected(int sectionIndex, bool forward)
+{
+ if (specialValue()
+#ifdef QT_KEYPAD_NAVIGATION
+ || (QApplication::keypadNavigationEnabled() && !edit->hasEditFocus())
+#endif
+ ) {
+ edit->selectAll();
+ } else {
+ const SectionNode &node = sectionNode(sectionIndex);
+ if (node.type == NoSection || node.type == LastSection || node.type == FirstSection)
+ return;
+
+ updateCache(value, displayText());
+ const int size = sectionSize(sectionIndex);
+ if (forward) {
+ edit->setSelection(sectionPos(node), size);
+ } else {
+ edit->setSelection(sectionPos(node) + size, -size);
+ }
+ }
+}
+
+/*!
+ \internal
+
+ Returns the section at index \a index or NoSection if there are no sections there.
+*/
+
+int QDateTimeEditPrivate::sectionAt(int pos) const
+{
+ if (pos < separators.first().size()) {
+ return (pos == 0 ? FirstSectionIndex : NoSectionIndex);
+ } else if (displayText().size() - pos < separators.last().size() + 1) {
+ if (separators.last().size() == 0) {
+ return sectionNodes.count() - 1;
+ }
+ return (pos == displayText().size() ? LastSectionIndex : NoSectionIndex);
+ }
+ updateCache(value, displayText());
+
+ for (int i=0; i<sectionNodes.size(); ++i) {
+ const int tmp = sectionPos(i);
+ if (pos < tmp + sectionSize(i)) {
+ return (pos < tmp ? -1 : i);
+ }
+ }
+ return -1;
+}
+
+/*!
+ \internal
+
+ Returns the closest section of index \a index. Searches forward
+ for a section if \a forward is true. Otherwise searches backwards.
+*/
+
+int QDateTimeEditPrivate::closestSection(int pos, bool forward) const
+{
+ Q_ASSERT(pos >= 0);
+ if (pos < separators.first().size()) {
+ return forward ? 0 : FirstSectionIndex;
+ } else if (displayText().size() - pos < separators.last().size() + 1) {
+ return forward ? LastSectionIndex : sectionNodes.size() - 1;
+ }
+ updateCache(value, displayText());
+ for (int i=0; i<sectionNodes.size(); ++i) {
+ const int tmp = sectionPos(sectionNodes.at(i));
+ if (pos < tmp + sectionSize(i)) {
+ if (pos < tmp && !forward) {
+ return i-1;
+ }
+ return i;
+ } else if (i == sectionNodes.size() - 1 && pos > tmp) {
+ return i;
+ }
+ }
+ qWarning("QDateTimeEdit: Internal Error: closestSection returned NoSection");
+ return NoSectionIndex;
+}
+
+/*!
+ \internal
+
+ Returns a copy of the section that is before or after \a current, depending on \a forward.
+*/
+
+int QDateTimeEditPrivate::nextPrevSection(int current, bool forward) const
+{
+ Q_Q(const QDateTimeEdit);
+ if (q->isRightToLeft())
+ forward = !forward;
+
+ switch (current) {
+ case FirstSectionIndex: return forward ? 0 : FirstSectionIndex;
+ case LastSectionIndex: return (forward ? LastSectionIndex : sectionNodes.size() - 1);
+ case NoSectionIndex: return FirstSectionIndex;
+ default: break;
+ }
+ Q_ASSERT(current >= 0 && current < sectionNodes.size());
+
+ current += (forward ? 1 : -1);
+ if (current >= sectionNodes.size()) {
+ return LastSectionIndex;
+ } else if (current < 0) {
+ return FirstSectionIndex;
+ }
+
+ return current;
+}
+
+/*!
+ \internal
+
+ Clears the text of section \a s.
+*/
+
+void QDateTimeEditPrivate::clearSection(int index)
+{
+ const QLatin1Char space(' ');
+ int cursorPos = edit->cursorPosition();
+ bool blocked = edit->blockSignals(true);
+ QString t = edit->text();
+ const int pos = sectionPos(index);
+ if (pos == -1) {
+ qWarning("QDateTimeEdit: Internal error (%s:%d)", __FILE__, __LINE__);
+ return;
+ }
+ const int size = sectionSize(index);
+ t.replace(pos, size, QString().fill(space, size));
+ edit->setText(t);
+ edit->setCursorPosition(cursorPos);
+ QDTEDEBUG << cursorPos;
+
+ edit->blockSignals(blocked);
+}
+
+
+/*!
+ \internal
+
+ updates the cached values
+*/
+
+void QDateTimeEditPrivate::updateCache(const QVariant &val, const QString &str) const
+{
+ if (val != cachedValue || str != cachedText || cacheGuard) {
+ cacheGuard = true;
+ QString copy = str;
+ int unused = edit->cursorPosition();
+ QValidator::State unusedState;
+ validateAndInterpret(copy, unused, unusedState);
+ cacheGuard = false;
+ }
+}
+
+/*!
+ \internal
+
+ parses and validates \a input
+*/
+
+QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &position,
+ QValidator::State &state, bool fixup) const
+{
+ if (input.isEmpty()) {
+ if (sectionNodes.size() == 1 || !specialValueText.isEmpty()) {
+ state = QValidator::Intermediate;
+ } else {
+ state = QValidator::Invalid;
+ }
+ return getZeroVariant().toDateTime();
+ } else if (cachedText == input && !fixup) {
+ state = cachedState;
+ return cachedValue.toDateTime();
+ } else if (!specialValueText.isEmpty()) {
+ bool changeCase = false;
+ const int max = qMin(specialValueText.size(), input.size());
+ int i;
+ for (i=0; i<max; ++i) {
+ const QChar ic = input.at(i);
+ const QChar sc = specialValueText.at(i);
+ if (ic != sc) {
+ if (sc.toLower() == ic.toLower()) {
+ changeCase = true;
+ } else {
+ break;
+ }
+ }
+ }
+ if (i == max) {
+ state = specialValueText.size() == input.size() ? QValidator::Acceptable : QValidator::Intermediate;
+ if (changeCase) {
+ input = specialValueText.left(max);
+ }
+ return minimum.toDateTime();
+ }
+ }
+ StateNode tmp = parse(input, position, value.toDateTime(), fixup);
+ input = tmp.input;
+ state = QValidator::State(int(tmp.state));
+ if (state == QValidator::Acceptable) {
+ if (tmp.conflicts && conflictGuard != tmp.value) {
+ conflictGuard = tmp.value;
+ clearCache();
+ input = textFromValue(tmp.value);
+ updateCache(tmp.value, input);
+ conflictGuard.clear();
+ } else {
+ cachedText = input;
+ cachedState = state;
+ cachedValue = tmp.value;
+ }
+ } else {
+ clearCache();
+ }
+ return (tmp.value.isNull() ? getZeroVariant().toDateTime() : tmp.value);
+}
+
+
+/*!
+ \internal
+*/
+
+QString QDateTimeEditPrivate::textFromValue(const QVariant &f) const
+{
+ Q_Q(const QDateTimeEdit);
+ return q->textFromDateTime(f.toDateTime());
+}
+
+/*!
+ \internal
+
+ This function's name is slightly confusing; it is not to be confused
+ with QAbstractSpinBox::valueFromText().
+*/
+
+QVariant QDateTimeEditPrivate::valueFromText(const QString &f) const
+{
+ Q_Q(const QDateTimeEdit);
+ return q->dateTimeFromText(f).toTimeSpec(spec);
+}
+
+
+/*!
+ \internal
+
+ Internal function called by QDateTimeEdit::stepBy(). Also takes a
+ Section for which section to step on and a bool \a test for
+ whether or not to modify the internal cachedDay variable. This is
+ necessary because the function is called from the const function
+ QDateTimeEdit::stepEnabled() as well as QDateTimeEdit::stepBy().
+*/
+
+QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) const
+{
+ Q_Q(const QDateTimeEdit);
+ QDateTime v = value.toDateTime();
+ QString str = displayText();
+ int pos = edit->cursorPosition();
+ const SectionNode sn = sectionNode(sectionIndex);
+
+ int val;
+ // to make sure it behaves reasonably when typing something and then stepping in non-tracking mode
+ if (!test && pendingEmit) {
+ if (q->validate(str, pos) != QValidator::Acceptable) {
+ v = value.toDateTime();
+ } else {
+ v = q->dateTimeFromText(str);
+ }
+ val = getDigit(v, sectionIndex);
+ } else {
+ val = getDigit(v, sectionIndex);
+ }
+
+ val += steps;
+
+ const int min = absoluteMin(sectionIndex);
+ const int max = absoluteMax(sectionIndex, value.toDateTime());
+
+ if (val < min) {
+ val = (wrapping ? max - (min - val) + 1 : min);
+ } else if (val > max) {
+ val = (wrapping ? min + val - max - 1 : max);
+ }
+
+
+ const int oldDay = v.date().day();
+
+ setDigit(v, sectionIndex, val);
+ // if this sets year or month it will make
+ // sure that days are lowered if needed.
+
+ const QDateTime minimumDateTime = minimum.toDateTime();
+ const QDateTime maximumDateTime = maximum.toDateTime();
+ // changing one section should only modify that section, if possible
+ if (sn.type != AmPmSection && (v < minimumDateTime || v > maximumDateTime)) {
+ const int localmin = getDigit(minimumDateTime, sectionIndex);
+ const int localmax = getDigit(maximumDateTime, sectionIndex);
+
+ if (wrapping) {
+ // just because we hit the roof in one direction, it
+ // doesn't mean that we hit the floor in the other
+ if (steps > 0) {
+ setDigit(v, sectionIndex, min);
+ if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
+ const int daysInMonth = v.date().daysInMonth();
+ if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
+ const int adds = qMin(oldDay, daysInMonth);
+ v = v.addDays(adds - v.date().day());
+ }
+ }
+
+ if (v < minimumDateTime) {
+ setDigit(v, sectionIndex, localmin);
+ if (v < minimumDateTime)
+ setDigit(v, sectionIndex, localmin + 1);
+ }
+ } else {
+ setDigit(v, sectionIndex, max);
+ if (!(sn.type & (DaySection|DayOfWeekSection)) && sections & DateSectionMask) {
+ const int daysInMonth = v.date().daysInMonth();
+ if (v.date().day() < oldDay && v.date().day() < daysInMonth) {
+ const int adds = qMin(oldDay, daysInMonth);
+ v = v.addDays(adds - v.date().day());
+ }
+ }
+
+ if (v > maximumDateTime) {
+ setDigit(v, sectionIndex, localmax);
+ if (v > maximumDateTime)
+ setDigit(v, sectionIndex, localmax - 1);
+ }
+ }
+ } else {
+ setDigit(v, sectionIndex, (steps > 0 ? localmax : localmin));
+ }
+ }
+ if (!test && oldDay != v.date().day() && !(sn.type & (DaySection|DayOfWeekSection))) {
+ // this should not happen when called from stepEnabled
+ cachedDay = qMax<int>(oldDay, cachedDay);
+ }
+
+ if (v < minimumDateTime) {
+ if (wrapping) {
+ QDateTime t = v;
+ setDigit(t, sectionIndex, steps < 0 ? max : min);
+ bool mincmp = (t >= minimumDateTime);
+ bool maxcmp = (t <= maximumDateTime);
+ if (!mincmp || !maxcmp) {
+ setDigit(t, sectionIndex, getDigit(steps < 0
+ ? maximumDateTime
+ : minimumDateTime, sectionIndex));
+ mincmp = (t >= minimumDateTime);
+ maxcmp = (t <= maximumDateTime);
+ }
+ if (mincmp && maxcmp) {
+ v = t;
+ }
+ } else {
+ v = value.toDateTime();
+ }
+ } else if (v > maximumDateTime) {
+ if (wrapping) {
+ QDateTime t = v;
+ setDigit(t, sectionIndex, steps > 0 ? min : max);
+ bool mincmp = (t >= minimumDateTime);
+ bool maxcmp = (t <= maximumDateTime);
+ if (!mincmp || !maxcmp) {
+ setDigit(t, sectionIndex, getDigit(steps > 0 ?
+ minimumDateTime :
+ maximumDateTime, sectionIndex));
+ mincmp = (t >= minimumDateTime);
+ maxcmp = (t <= maximumDateTime);
+ }
+ if (mincmp && maxcmp) {
+ v = t;
+ }
+ } else {
+ v = value.toDateTime();
+ }
+ }
+
+ const QDateTime ret = bound(v, value, steps).toDateTime().toTimeSpec(spec);
+ return ret;
+}
+
+/*!
+ \internal
+*/
+
+void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
+{
+ Q_Q(QDateTimeEdit);
+ if (ep == NeverEmit) {
+ return;
+ }
+ pendingEmit = false;
+
+ const bool dodate = value.toDate().isValid() && (sections & DateSectionMask);
+ const bool datechanged = (ep == AlwaysEmit || old.toDate() != value.toDate());
+ const bool dotime = value.toTime().isValid() && (sections & TimeSectionMask);
+ const bool timechanged = (ep == AlwaysEmit || old.toTime() != value.toTime());
+
+ updateCache(value, displayText());
+
+ syncCalendarWidget();
+ if (datechanged || timechanged)
+ emit q->dateTimeChanged(value.toDateTime());
+ if (dodate && datechanged)
+ emit q->dateChanged(value.toDate());
+ if (dotime && timechanged)
+ emit q->timeChanged(value.toTime());
+
+}
+
+/*!
+ \internal
+*/
+
+void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
+{
+ if (ignoreCursorPositionChanged || specialValue())
+ return;
+ const QString oldText = displayText();
+ updateCache(value, oldText);
+
+ const bool allowChange = !edit->hasSelectedText();
+ const bool forward = oldpos <= newpos;
+ ignoreCursorPositionChanged = true;
+ int s = sectionAt(newpos);
+ if (s == NoSectionIndex && forward && newpos > 0) {
+ s = sectionAt(newpos - 1);
+ }
+
+ int c = newpos;
+
+ const int selstart = edit->selectionStart();
+ const int selSection = sectionAt(selstart);
+ const int l = selSection != -1 ? sectionSize(selSection) : 0;
+
+ if (s == NoSectionIndex) {
+ if (l > 0 && selstart == sectionPos(selSection) && edit->selectedText().size() == l) {
+ s = selSection;
+ if (allowChange)
+ setSelected(selSection, true);
+ c = -1;
+ } else {
+ int closest = closestSection(newpos, forward);
+ c = sectionPos(closest) + (forward ? 0 : qMax<int>(0, sectionSize(closest)));
+
+ if (allowChange) {
+ edit->setCursorPosition(c);
+ QDTEDEBUG << c;
+ }
+ s = closest;
+ }
+ }
+
+ if (allowChange && currentSectionIndex != s) {
+ interpret(EmitIfChanged);
+ }
+ if (c == -1) {
+ setSelected(s, true);
+ } else if (!edit->hasSelectedText()) {
+ if (oldpos < newpos) {
+ edit->setCursorPosition(displayText().size() - (oldText.size() - c));
+ } else {
+ edit->setCursorPosition(c);
+ }
+ }
+
+ QDTEDEBUG << "currentSectionIndex is set to" << sectionName(sectionType(s))
+ << oldpos << newpos
+ << "was" << sectionName(sectionType(currentSectionIndex));
+
+ currentSectionIndex = s;
+ Q_ASSERT_X(currentSectionIndex < sectionNodes.size(),
+ "QDateTimeEditPrivate::_q_editorCursorPositionChanged()",
+ qPrintable(QString::fromAscii("Internal error (%1 %2)").
+ arg(currentSectionIndex).
+ arg(sectionNodes.size())));
+
+ ignoreCursorPositionChanged = false;
+}
+
+/*!
+ \internal
+
+ Try to get the format from the local settings
+*/
+void QDateTimeEditPrivate::readLocaleSettings()
+{
+ const QLocale loc;
+ defaultTimeFormat = loc.timeFormat(QLocale::ShortFormat);
+ defaultDateFormat = loc.dateFormat(QLocale::ShortFormat);
+ defaultDateTimeFormat = loc.dateTimeFormat(QLocale::ShortFormat);
+}
+
+QDateTimeEdit::Section QDateTimeEditPrivate::convertToPublic(QDateTimeParser::Section s)
+{
+ switch (s & ~Internal) {
+ case AmPmSection: return QDateTimeEdit::AmPmSection;
+ case MSecSection: return QDateTimeEdit::MSecSection;
+ case SecondSection: return QDateTimeEdit::SecondSection;
+ case MinuteSection: return QDateTimeEdit::MinuteSection;
+ case DayOfWeekSection:
+ case DaySection: return QDateTimeEdit::DaySection;
+ case MonthSection: return QDateTimeEdit::MonthSection;
+ case YearSection2Digits:
+ case YearSection: return QDateTimeEdit::YearSection;
+ case Hour12Section:
+ case Hour24Section: return QDateTimeEdit::HourSection;
+ case FirstSection:
+ case NoSection:
+ case LastSection: break;
+ }
+ return QDateTimeEdit::NoSection;
+}
+
+QDateTimeEdit::Sections QDateTimeEditPrivate::convertSections(QDateTimeParser::Sections s)
+{
+ QDateTimeEdit::Sections ret = 0;
+ if (s & QDateTimeParser::MSecSection)
+ ret |= QDateTimeEdit::MSecSection;
+ if (s & QDateTimeParser::SecondSection)
+ ret |= QDateTimeEdit::SecondSection;
+ if (s & QDateTimeParser::MinuteSection)
+ ret |= QDateTimeEdit::MinuteSection;
+ if (s & (QDateTimeParser::Hour24Section|QDateTimeParser::Hour12Section))
+ ret |= QDateTimeEdit::HourSection;
+ if (s & QDateTimeParser::AmPmSection)
+ ret |= QDateTimeEdit::AmPmSection;
+ if (s & (QDateTimeParser::DaySection|QDateTimeParser::DayOfWeekSection))
+ ret |= QDateTimeEdit::DaySection;
+ if (s & QDateTimeParser::MonthSection)
+ ret |= QDateTimeEdit::MonthSection;
+ if (s & (QDateTimeParser::YearSection|QDateTimeParser::YearSection2Digits))
+ ret |= QDateTimeEdit::YearSection;
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+
+void QDateTimeEdit::paintEvent(QPaintEvent *event)
+{
+ Q_D(QDateTimeEdit);
+ if (!d->calendarPopupEnabled()) {
+ QAbstractSpinBox::paintEvent(event);
+ return;
+ }
+
+ QStyleOptionSpinBox opt;
+ initStyleOption(&opt);
+
+ QStyleOptionComboBox optCombo;
+
+ optCombo.init(this);
+ optCombo.editable = true;
+ optCombo.frame = opt.frame;
+ optCombo.subControls = opt.subControls;
+ optCombo.activeSubControls = opt.activeSubControls;
+ optCombo.state = opt.state;
+ if (d->readOnly) {
+ optCombo.state &= ~QStyle::State_Enabled;
+ }
+
+ QPainter p(this);
+ style()->drawComplexControl(QStyle::CC_ComboBox, &optCombo, &p, this);
+}
+
+QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const
+{
+ if (ap == AmText) {
+ return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am"));
+ } else {
+ return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm"));
+ }
+}
+
+int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) const
+{
+ for (int i=0; i<sectionNodes.size(); ++i) {
+ if (convertToPublic(sectionNodes.at(i).type) == s && index-- == 0) {
+ return i;
+ }
+ }
+ return NoSectionIndex;
+}
+
+int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
+{
+ return sectionNodes.indexOf(s);
+}
+
+void QDateTimeEditPrivate::interpret(EmitPolicy ep)
+{
+ Q_Q(QDateTimeEdit);
+ QString tmp = displayText();
+ int pos = edit->cursorPosition();
+ const QValidator::State state = q->validate(tmp, pos);
+ if (state != QValidator::Acceptable
+ && correctionMode == QAbstractSpinBox::CorrectToPreviousValue
+ && (state == QValidator::Invalid || !(fieldInfo(currentSectionIndex) & AllowPartial))) {
+ setValue(value, ep);
+ updateTimeSpec();
+ } else {
+ QAbstractSpinBoxPrivate::interpret(ep);
+ }
+}
+
+void QDateTimeEditPrivate::clearCache() const
+{
+ QAbstractSpinBoxPrivate::clearCache();
+ cachedDay = -1;
+}
+
+/*!
+ Initialize \a option with the values from this QDataTimeEdit. This method
+ is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QDateTimeEdit::initStyleOption(QStyleOptionSpinBox *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QDateTimeEdit);
+ QAbstractSpinBox::initStyleOption(option);
+ if (d->calendarPopupEnabled()) {
+ option->subControls = QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField
+ | QStyle::SC_ComboBoxArrow;
+ if (d->arrowState == QStyle::State_Sunken)
+ option->state |= QStyle::State_Sunken;
+ else
+ option->state &= ~QStyle::State_Sunken;
+ }
+}
+
+void QDateTimeEditPrivate::init(const QVariant &var)
+{
+ Q_Q(QDateTimeEdit);
+ switch (var.type()) {
+ case QVariant::Date:
+ value = QDateTime(var.toDate(), QDATETIMEEDIT_TIME_MIN);
+ q->setDisplayFormat(defaultDateFormat);
+ if (sectionNodes.isEmpty()) // ### safeguard for broken locale
+ q->setDisplayFormat(QLatin1String("dd/MM/yyyy"));
+ break;
+ case QVariant::DateTime:
+ value = var;
+ q->setDisplayFormat(defaultDateTimeFormat);
+ if (sectionNodes.isEmpty()) // ### safeguard for broken locale
+ q->setDisplayFormat(QLatin1String("dd/MM/yyyy hh:mm:ss"));
+ break;
+ case QVariant::Time:
+ value = QDateTime(QDATETIMEEDIT_DATE_INITIAL, var.toTime());
+ q->setDisplayFormat(defaultTimeFormat);
+ if (sectionNodes.isEmpty()) // ### safeguard for broken locale
+ q->setDisplayFormat(QLatin1String("hh:mm:ss"));
+ break;
+ default:
+ Q_ASSERT_X(0, "QDateTimeEditPrivate::init", "Internal error");
+ break;
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ q->setCalendarPopup(true);
+#endif
+ updateTimeSpec();
+ q->setInputMethodHints(Qt::ImhPreferNumbers);
+ setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem);
+}
+
+void QDateTimeEditPrivate::_q_resetButton()
+{
+ updateArrow(QStyle::State_None);
+}
+
+void QDateTimeEditPrivate::updateArrow(QStyle::StateFlag state)
+{
+ Q_Q(QDateTimeEdit);
+
+ if (arrowState == state)
+ return;
+ arrowState = state;
+ if (arrowState != QStyle::State_None)
+ buttonState |= Mouse;
+ else {
+ buttonState = 0;
+ hoverControl = QStyle::SC_ComboBoxFrame;
+ }
+ q->update();
+}
+
+/*!
+ \internal
+ Returns the hover control at \a pos.
+ This will update the hoverRect and hoverControl.
+*/
+QStyle::SubControl QDateTimeEditPrivate::newHoverControl(const QPoint &pos)
+{
+ if (!calendarPopupEnabled())
+ return QAbstractSpinBoxPrivate::newHoverControl(pos);
+
+ Q_Q(QDateTimeEdit);
+
+ QStyleOptionComboBox optCombo;
+ optCombo.init(q);
+ optCombo.editable = true;
+ optCombo.subControls = QStyle::SC_All;
+ hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &optCombo, pos, q);
+ return hoverControl;
+}
+
+void QDateTimeEditPrivate::updateEditFieldGeometry()
+{
+ if (!calendarPopupEnabled()) {
+ QAbstractSpinBoxPrivate::updateEditFieldGeometry();
+ return;
+ }
+
+ Q_Q(QDateTimeEdit);
+
+ QStyleOptionComboBox optCombo;
+ optCombo.init(q);
+ optCombo.editable = true;
+ optCombo.subControls = QStyle::SC_ComboBoxEditField;
+ edit->setGeometry(q->style()->subControlRect(QStyle::CC_ComboBox, &optCombo,
+ QStyle::SC_ComboBoxEditField, q));
+}
+
+QVariant QDateTimeEditPrivate::getZeroVariant() const
+{
+ Q_ASSERT(type == QVariant::DateTime);
+ return QDateTime(QDATETIMEEDIT_DATE_INITIAL, QTime(), spec);
+}
+
+void QDateTimeEditPrivate::setRange(const QVariant &min, const QVariant &max)
+{
+ QAbstractSpinBoxPrivate::setRange(min, max);
+ syncCalendarWidget();
+}
+
+
+bool QDateTimeEditPrivate::isSeparatorKey(const QKeyEvent *ke) const
+{
+ if (!ke->text().isEmpty() && currentSectionIndex + 1 < sectionNodes.size() && currentSectionIndex >= 0) {
+ if (fieldInfo(currentSectionIndex) & Numeric) {
+ if (ke->text().at(0).isNumber())
+ return false;
+ } else if (ke->text().at(0).isLetterOrNumber()) {
+ return false;
+ }
+ return separators.at(currentSectionIndex + 1).contains(ke->text());
+ }
+ return false;
+}
+
+void QDateTimeEditPrivate::initCalendarPopup(QCalendarWidget *cw)
+{
+ Q_Q(QDateTimeEdit);
+ if (!monthCalendar) {
+ monthCalendar = new QCalendarPopup(q, cw);
+ monthCalendar->setObjectName(QLatin1String("qt_datetimedit_calendar"));
+ QObject::connect(monthCalendar, SIGNAL(newDateSelected(QDate)), q, SLOT(setDate(QDate)));
+ QObject::connect(monthCalendar, SIGNAL(hidingCalendar(QDate)), q, SLOT(setDate(QDate)));
+ QObject::connect(monthCalendar, SIGNAL(activated(QDate)), q, SLOT(setDate(QDate)));
+ QObject::connect(monthCalendar, SIGNAL(activated(QDate)), monthCalendar, SLOT(close()));
+ QObject::connect(monthCalendar, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
+ } else if (cw) {
+ monthCalendar->setCalendarWidget(cw);
+ }
+ syncCalendarWidget();
+}
+
+void QDateTimeEditPrivate::positionCalendarPopup()
+{
+ Q_Q(QDateTimeEdit);
+ QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft();
+ QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft();
+ pos = q->mapToGlobal(pos);
+ pos2 = q->mapToGlobal(pos2);
+ QSize size = monthCalendar->sizeHint();
+ QRect screen = QApplication::desktop()->availableGeometry(pos);
+ //handle popup falling "off screen"
+ if (q->layoutDirection() == Qt::RightToLeft) {
+ pos.setX(pos.x()-size.width());
+ pos2.setX(pos2.x()-size.width());
+ if (pos.x() < screen.left())
+ pos.setX(qMax(pos.x(), screen.left()));
+ else if (pos.x()+size.width() > screen.right())
+ pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width()));
+ } else {
+ if (pos.x()+size.width() > screen.right())
+ pos.setX(screen.right()-size.width());
+ pos.setX(qMax(pos.x(), screen.left()));
+ }
+ if (pos.y() + size.height() > screen.bottom())
+ pos.setY(pos2.y() - size.height());
+ else if (pos.y() < screen.top())
+ pos.setY(screen.top());
+ if (pos.y() < screen.top())
+ pos.setY(screen.top());
+ if (pos.y()+size.height() > screen.bottom())
+ pos.setY(screen.bottom()-size.height());
+ monthCalendar->move(pos);
+}
+
+bool QDateTimeEditPrivate::calendarPopupEnabled() const
+{
+ return (calendarPopup && (sections & (DateSectionMask)));
+}
+
+void QDateTimeEditPrivate::syncCalendarWidget()
+{
+ Q_Q(QDateTimeEdit);
+ if (monthCalendar) {
+ monthCalendar->setDateRange(q->minimumDate(), q->maximumDate());
+ monthCalendar->setDate(q->date());
+ }
+}
+
+QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw)
+ : QWidget(parent, Qt::Popup)
+{
+ setAttribute(Qt::WA_WindowPropagation);
+
+ dateChanged = false;
+ if (!cw) {
+ verifyCalendarInstance();
+ } else {
+ setCalendarWidget(cw);
+ }
+}
+
+QCalendarWidget *QCalendarPopup::verifyCalendarInstance()
+{
+ if (calendar.isNull()) {
+ QCalendarWidget *cw = new QCalendarWidget(this);
+ cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames);
+#endif
+ setCalendarWidget(cw);
+ return cw;
+ } else {
+ return calendar.data();
+ }
+}
+
+void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw)
+{
+ Q_ASSERT(cw);
+ QVBoxLayout *widgetLayout = qobject_cast<QVBoxLayout*>(layout());
+ if (!widgetLayout) {
+ widgetLayout = new QVBoxLayout(this);
+ widgetLayout->setMargin(0);
+ widgetLayout->setSpacing(0);
+ }
+ delete calendar.data();
+ calendar = QWeakPointer<QCalendarWidget>(cw);
+ widgetLayout->addWidget(cw);
+
+ connect(cw, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate)));
+ connect(cw, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate)));
+ connect(cw, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged()));
+
+ cw->setFocus();
+}
+
+
+void QCalendarPopup::setDate(const QDate &date)
+{
+ oldDate = date;
+ verifyCalendarInstance()->setSelectedDate(date);
+}
+
+void QCalendarPopup::setDateRange(const QDate &min, const QDate &max)
+{
+ QCalendarWidget *cw = verifyCalendarInstance();
+ cw->setMinimumDate(min);
+ cw->setMaximumDate(max);
+}
+
+void QCalendarPopup::mousePressEvent(QMouseEvent *event)
+{
+ QDateTimeEdit *dateTime = qobject_cast<QDateTimeEdit *>(parentWidget());
+ if (dateTime) {
+ QStyleOptionComboBox opt;
+ opt.init(dateTime);
+ QRect arrowRect = dateTime->style()->subControlRect(QStyle::CC_ComboBox, &opt,
+ QStyle::SC_ComboBoxArrow, dateTime);
+ arrowRect.moveTo(dateTime->mapToGlobal(arrowRect .topLeft()));
+ if (arrowRect.contains(event->globalPos()) || rect().contains(event->pos()))
+ setAttribute(Qt::WA_NoMouseReplay);
+ }
+ QWidget::mousePressEvent(event);
+}
+
+void QCalendarPopup::mouseReleaseEvent(QMouseEvent*)
+{
+ emit resetButton();
+}
+
+bool QCalendarPopup::event(QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ if (keyEvent->key()== Qt::Key_Escape)
+ dateChanged = false;
+ }
+ return QWidget::event(event);
+}
+
+void QCalendarPopup::dateSelectionChanged()
+{
+ dateChanged = true;
+ emit newDateSelected(verifyCalendarInstance()->selectedDate());
+}
+void QCalendarPopup::dateSelected(const QDate &date)
+{
+ dateChanged = true;
+ emit activated(date);
+ close();
+}
+
+void QCalendarPopup::hideEvent(QHideEvent *)
+{
+ emit resetButton();
+ if (!dateChanged)
+ emit hidingCalendar(oldDate);
+}
+
+QT_END_NAMESPACE
+#include "moc_qdatetimeedit.cpp"
+
+#endif // QT_NO_DATETIMEEDIT
diff --git a/src/widgets/widgets/qdatetimeedit.h b/src/widgets/widgets/qdatetimeedit.h
new file mode 100644
index 0000000000..a57a5f29e9
--- /dev/null
+++ b/src/widgets/widgets/qdatetimeedit.h
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATETIMEEDIT_H
+#define QDATETIMEEDIT_H
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qvariant.h>
+#include <QtWidgets/qabstractspinbox.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_DATETIMEEDIT
+
+class QDateTimeEditPrivate;
+class QStyleOptionSpinBox;
+class QCalendarWidget;
+
+class Q_WIDGETS_EXPORT QDateTimeEdit : public QAbstractSpinBox
+{
+ Q_OBJECT
+
+ Q_ENUMS(Section)
+ Q_FLAGS(Sections)
+ Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged USER true)
+ Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged)
+ Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
+ Q_PROPERTY(QDateTime maximumDateTime READ maximumDateTime WRITE setMaximumDateTime RESET clearMaximumDateTime)
+ Q_PROPERTY(QDateTime minimumDateTime READ minimumDateTime WRITE setMinimumDateTime RESET clearMinimumDateTime)
+ Q_PROPERTY(QDate maximumDate READ maximumDate WRITE setMaximumDate RESET clearMaximumDate)
+ Q_PROPERTY(QDate minimumDate READ minimumDate WRITE setMinimumDate RESET clearMinimumDate)
+ Q_PROPERTY(QTime maximumTime READ maximumTime WRITE setMaximumTime RESET clearMaximumTime)
+ Q_PROPERTY(QTime minimumTime READ minimumTime WRITE setMinimumTime RESET clearMinimumTime)
+ Q_PROPERTY(Section currentSection READ currentSection WRITE setCurrentSection)
+ Q_PROPERTY(Sections displayedSections READ displayedSections)
+ Q_PROPERTY(QString displayFormat READ displayFormat WRITE setDisplayFormat)
+ Q_PROPERTY(bool calendarPopup READ calendarPopup WRITE setCalendarPopup)
+ Q_PROPERTY(int currentSectionIndex READ currentSectionIndex WRITE setCurrentSectionIndex)
+ Q_PROPERTY(int sectionCount READ sectionCount)
+ Q_PROPERTY(Qt::TimeSpec timeSpec READ timeSpec WRITE setTimeSpec)
+public:
+ enum Section {
+ NoSection = 0x0000,
+ AmPmSection = 0x0001,
+ MSecSection = 0x0002,
+ SecondSection = 0x0004,
+ MinuteSection = 0x0008,
+ HourSection = 0x0010,
+ DaySection = 0x0100,
+ MonthSection = 0x0200,
+ YearSection = 0x0400,
+ TimeSections_Mask = AmPmSection|MSecSection|SecondSection|MinuteSection|HourSection,
+ DateSections_Mask = DaySection|MonthSection|YearSection
+ };
+
+ Q_DECLARE_FLAGS(Sections, Section)
+
+ explicit QDateTimeEdit(QWidget *parent = 0);
+ explicit QDateTimeEdit(const QDateTime &dt, QWidget *parent = 0);
+ explicit QDateTimeEdit(const QDate &d, QWidget *parent = 0);
+ explicit QDateTimeEdit(const QTime &t, QWidget *parent = 0);
+
+ QDateTime dateTime() const;
+ QDate date() const;
+ QTime time() const;
+
+ QDateTime minimumDateTime() const;
+ void clearMinimumDateTime();
+ void setMinimumDateTime(const QDateTime &dt);
+
+ QDateTime maximumDateTime() const;
+ void clearMaximumDateTime();
+ void setMaximumDateTime(const QDateTime &dt);
+
+ void setDateTimeRange(const QDateTime &min, const QDateTime &max);
+
+ QDate minimumDate() const;
+ void setMinimumDate(const QDate &min);
+ void clearMinimumDate();
+
+ QDate maximumDate() const;
+ void setMaximumDate(const QDate &max);
+ void clearMaximumDate();
+
+ void setDateRange(const QDate &min, const QDate &max);
+
+ QTime minimumTime() const;
+ void setMinimumTime(const QTime &min);
+ void clearMinimumTime();
+
+ QTime maximumTime() const;
+ void setMaximumTime(const QTime &max);
+ void clearMaximumTime();
+
+ void setTimeRange(const QTime &min, const QTime &max);
+
+ Sections displayedSections() const;
+ Section currentSection() const;
+ Section sectionAt(int index) const;
+ void setCurrentSection(Section section);
+
+ int currentSectionIndex() const;
+ void setCurrentSectionIndex(int index);
+
+ QCalendarWidget *calendarWidget() const;
+ void setCalendarWidget(QCalendarWidget *calendarWidget);
+
+ int sectionCount() const;
+
+ void setSelectedSection(Section section);
+
+ QString sectionText(Section section) const;
+
+ QString displayFormat() const;
+ void setDisplayFormat(const QString &format);
+
+ bool calendarPopup() const;
+ void setCalendarPopup(bool enable);
+
+ Qt::TimeSpec timeSpec() const;
+ void setTimeSpec(Qt::TimeSpec spec);
+
+ QSize sizeHint() const;
+
+ virtual void clear();
+ virtual void stepBy(int steps);
+
+ bool event(QEvent *event);
+Q_SIGNALS:
+ void dateTimeChanged(const QDateTime &date);
+ void timeChanged(const QTime &date);
+ void dateChanged(const QDate &date);
+
+public Q_SLOTS:
+ void setDateTime(const QDateTime &dateTime);
+ void setDate(const QDate &date);
+ void setTime(const QTime &time);
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *event);
+#ifndef QT_NO_WHEELEVENT
+ virtual void wheelEvent(QWheelEvent *event);
+#endif
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual bool focusNextPrevChild(bool next);
+ virtual QValidator::State validate(QString &input, int &pos) const;
+ virtual void fixup(QString &input) const;
+
+ virtual QDateTime dateTimeFromText(const QString &text) const;
+ virtual QString textFromDateTime(const QDateTime &dt) const;
+ virtual StepEnabled stepEnabled() const;
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void paintEvent(QPaintEvent *event);
+ void initStyleOption(QStyleOptionSpinBox *option) const;
+
+ QDateTimeEdit(const QVariant &val, QVariant::Type parserType, QWidget *parent = 0);
+private:
+ Q_DECLARE_PRIVATE(QDateTimeEdit)
+ Q_DISABLE_COPY(QDateTimeEdit)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_resetButton())
+};
+
+class Q_WIDGETS_EXPORT QTimeEdit : public QDateTimeEdit
+{
+ Q_OBJECT
+public:
+ QTimeEdit(QWidget *parent = 0);
+ QTimeEdit(const QTime &time, QWidget *parent = 0);
+};
+
+class Q_WIDGETS_EXPORT QDateEdit : public QDateTimeEdit
+{
+ Q_OBJECT
+public:
+ QDateEdit(QWidget *parent = 0);
+ QDateEdit(const QDate &date, QWidget *parent = 0);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeEdit::Sections)
+
+#endif // QT_NO_DATETIMEEDIT
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDATETIMEEDIT_H
diff --git a/src/widgets/widgets/qdatetimeedit_p.h b/src/widgets/widgets/qdatetimeedit_p.h
new file mode 100644
index 0000000000..57799d5bc0
--- /dev/null
+++ b/src/widgets/widgets/qdatetimeedit_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATETIMEEDIT_P_H
+#define QDATETIMEEDIT_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 "QtWidgets/qcombobox.h"
+#include "QtWidgets/qcalendarwidget.h"
+#include "QtWidgets/qspinbox.h"
+#include "QtWidgets/qtoolbutton.h"
+#include "QtWidgets/qmenu.h"
+#include "QtWidgets/qlabel.h"
+#include "QtWidgets/qdatetimeedit.h"
+#include "private/qabstractspinbox_p.h"
+#include "private/qdatetime_p.h"
+
+#include "qdebug.h"
+
+#ifndef QT_NO_DATETIMEEDIT
+
+QT_BEGIN_NAMESPACE
+
+class QCalendarPopup;
+class QDateTimeEditPrivate : public QAbstractSpinBoxPrivate, public QDateTimeParser
+{
+ Q_DECLARE_PUBLIC(QDateTimeEdit)
+public:
+ QDateTimeEditPrivate();
+
+ void init(const QVariant &var);
+ void readLocaleSettings();
+
+ void emitSignals(EmitPolicy ep, const QVariant &old);
+ QString textFromValue(const QVariant &f) const;
+ QVariant valueFromText(const QString &f) const;
+ virtual void _q_editorCursorPositionChanged(int oldpos, int newpos);
+ virtual void interpret(EmitPolicy ep);
+ virtual void clearCache() const;
+
+ QDateTime validateAndInterpret(QString &input, int &, QValidator::State &state,
+ bool fixup = false) const;
+ void clearSection(int index);
+ virtual QString displayText() const { return edit->text(); } // this is from QDateTimeParser
+
+ int absoluteIndex(QDateTimeEdit::Section s, int index) const;
+ int absoluteIndex(const SectionNode &s) const;
+ void updateEdit();
+ QDateTime stepBy(int index, int steps, bool test = false) const;
+ int sectionAt(int pos) const;
+ int closestSection(int index, bool forward) const;
+ int nextPrevSection(int index, bool forward) const;
+ void setSelected(int index, bool forward = false);
+
+ void updateCache(const QVariant &val, const QString &str) const;
+
+ void updateTimeSpec();
+ virtual QDateTime getMinimum() const { return minimum.toDateTime(); }
+ virtual QDateTime getMaximum() const { return maximum.toDateTime(); }
+ virtual QLocale locale() const { return q_func()->locale(); }
+ QString valueToText(const QVariant &var) const { return textFromValue(var); }
+ QString getAmPmText(AmPm ap, Case cs) const;
+ int cursorPosition() const { return edit ? edit->cursorPosition() : -1; }
+
+ virtual QStyle::SubControl newHoverControl(const QPoint &pos);
+ virtual void updateEditFieldGeometry();
+ virtual QVariant getZeroVariant() const;
+ virtual void setRange(const QVariant &min, const QVariant &max);
+
+ void _q_resetButton();
+ void updateArrow(QStyle::StateFlag state);
+ bool calendarPopupEnabled() const;
+ void syncCalendarWidget();
+
+ bool isSeparatorKey(const QKeyEvent *k) const;
+
+ static QDateTimeEdit::Sections convertSections(QDateTimeParser::Sections s);
+ static QDateTimeEdit::Section convertToPublic(QDateTimeParser::Section s);
+
+ void initCalendarPopup(QCalendarWidget *cw = 0);
+ void positionCalendarPopup();
+
+ QDateTimeEdit::Sections sections;
+ mutable bool cacheGuard;
+
+ QString defaultDateFormat, defaultTimeFormat, defaultDateTimeFormat, unreversedFormat;
+ mutable QVariant conflictGuard;
+ bool hasHadFocus, formatExplicitlySet, calendarPopup;
+ QStyle::StateFlag arrowState;
+ QCalendarPopup *monthCalendar;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ bool focusOnButton;
+#endif
+};
+
+
+class QCalendarPopup : public QWidget
+{
+ Q_OBJECT
+public:
+ QCalendarPopup(QWidget *parent = 0, QCalendarWidget *cw = 0);
+ QDate selectedDate() { return verifyCalendarInstance()->selectedDate(); }
+ void setDate(const QDate &date);
+ void setDateRange(const QDate &min, const QDate &max);
+ void setFirstDayOfWeek(Qt::DayOfWeek dow) { verifyCalendarInstance()->setFirstDayOfWeek(dow); }
+ QCalendarWidget *calendarWidget() const { return const_cast<QCalendarPopup*>(this)->verifyCalendarInstance(); }
+ void setCalendarWidget(QCalendarWidget *cw);
+Q_SIGNALS:
+ void activated(const QDate &date);
+ void newDateSelected(const QDate &newDate);
+ void hidingCalendar(const QDate &oldDate);
+ void resetButton();
+
+private Q_SLOTS:
+ void dateSelected(const QDate &date);
+ void dateSelectionChanged();
+
+protected:
+ void hideEvent(QHideEvent *);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *);
+ bool event(QEvent *e);
+
+private:
+ QCalendarWidget *verifyCalendarInstance();
+
+ QWeakPointer<QCalendarWidget> calendar;
+ QDate oldDate;
+ bool dateChanged;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DATETIMEEDIT
+
+#endif // QDATETIMEEDIT_P_H
diff --git a/src/widgets/widgets/qdial.cpp b/src/widgets/widgets/qdial.cpp
new file mode 100644
index 0000000000..e2b1983f66
--- /dev/null
+++ b/src/widgets/widgets/qdial.cpp
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdial.h"
+
+#ifndef QT_NO_DIAL
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcolor.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qpolygon.h>
+#include <qregion.h>
+#include <qstyle.h>
+#include <qstylepainter.h>
+#include <qstyleoption.h>
+#include <qslider.h>
+#include <private/qabstractslider_p.h>
+#include <private/qmath_p.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDialPrivate : public QAbstractSliderPrivate
+{
+ Q_DECLARE_PUBLIC(QDial)
+public:
+ QDialPrivate()
+ {
+ wrapping = false;
+ tracking = true;
+ doNotEmit = false;
+ target = qreal(3.7);
+ }
+
+ qreal target;
+ uint showNotches : 1;
+ uint wrapping : 1;
+ uint doNotEmit : 1;
+
+ int valueFromPoint(const QPoint &) const;
+ double angle(const QPoint &, const QPoint &) const;
+ void init();
+ virtual int bound(int val) const;
+};
+
+void QDialPrivate::init()
+{
+ Q_Q(QDial);
+ showNotches = false;
+ q->setFocusPolicy(Qt::WheelFocus);
+#ifdef QT3_SUPPORT
+ QObject::connect(q, SIGNAL(sliderPressed()), q, SIGNAL(dialPressed()));
+ QObject::connect(q, SIGNAL(sliderMoved(int)), q, SIGNAL(dialMoved(int)));
+ QObject::connect(q, SIGNAL(sliderReleased()), q, SIGNAL(dialReleased()));
+#endif
+}
+
+int QDialPrivate::bound(int val) const
+{
+ if (wrapping) {
+ if ((val >= minimum) && (val <= maximum))
+ return val;
+ val = minimum + ((val - minimum) % (maximum - minimum));
+ if (val < minimum)
+ val += maximum - minimum;
+ return val;
+ } else {
+ return QAbstractSliderPrivate::bound(val);
+ }
+}
+
+/*!
+ Initialize \a option with the values from this QDial. This method
+ is useful for subclasses when they need a QStyleOptionSlider, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QDial::initStyleOption(QStyleOptionSlider *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QDial);
+ option->initFrom(this);
+ option->minimum = d->minimum;
+ option->maximum = d->maximum;
+ option->sliderPosition = d->position;
+ option->sliderValue = d->value;
+ option->singleStep = d->singleStep;
+ option->pageStep = d->pageStep;
+ option->upsideDown = !d->invertedAppearance;
+ option->notchTarget = d->target;
+ option->dialWrapping = d->wrapping;
+ option->subControls = QStyle::SC_All;
+ option->activeSubControls = QStyle::SC_None;
+ if (!d->showNotches) {
+ option->subControls &= ~QStyle::SC_DialTickmarks;
+ option->tickPosition = QSlider::TicksAbove;
+ } else {
+ option->tickPosition = QSlider::NoTicks;
+ }
+ option->tickInterval = notchSize();
+}
+
+int QDialPrivate::valueFromPoint(const QPoint &p) const
+{
+ Q_Q(const QDial);
+ double yy = (double)q->height()/2.0 - p.y();
+ double xx = (double)p.x() - q->width()/2.0;
+ double a = (xx || yy) ? qAtan2(yy, xx) : 0;
+
+ if (a < Q_PI / -2)
+ a = a + Q_PI * 2;
+
+ int dist = 0;
+ int minv = minimum, maxv = maximum;
+
+ if (minimum < 0) {
+ dist = -minimum;
+ minv = 0;
+ maxv = maximum + dist;
+ }
+
+ int r = maxv - minv;
+ int v;
+ if (wrapping)
+ v = (int)(0.5 + minv + r * (Q_PI * 3 / 2 - a) / (2 * Q_PI));
+ else
+ v = (int)(0.5 + minv + r* (Q_PI * 4 / 3 - a) / (Q_PI * 10 / 6));
+
+ if (dist > 0)
+ v -= dist;
+
+ return !invertedAppearance ? bound(v) : maximum - bound(v);
+}
+
+/*!
+ \class QDial
+
+ \brief The QDial class provides a rounded range control (like a speedometer or potentiometer).
+
+ \ingroup basicwidgets
+
+
+ QDial is used when the user needs to control a value within a
+ program-definable range, and the range either wraps around
+ (for example, with angles measured from 0 to 359 degrees) or the
+ dialog layout needs a square widget.
+
+ Since QDial inherits from QAbstractSlider, the dial behaves in
+ a similar way to a \l{QSlider}{slider}. When wrapping() is false
+ (the default setting) there is no real difference between a slider
+ and a dial. They both share the same signals, slots and member
+ functions. Which one you use depends on the expectations of
+ your users and on the type of application.
+
+ The dial initially emits valueChanged() signals continuously while
+ the slider is being moved; you can make it emit the signal less
+ often by disabling the \l{QAbstractSlider::tracking} {tracking}
+ property. The sliderMoved() signal is emitted continuously even
+ when tracking is disabled.
+
+ The dial also emits sliderPressed() and sliderReleased() signals
+ when the mouse button is pressed and released. Note that the
+ dial's value can change without these signals being emitted since
+ the keyboard and wheel can also be used to change the value.
+
+ Unlike the slider, QDial attempts to draw a "nice" number of
+ notches rather than one per line step. If possible, the number of
+ notches drawn is one per line step, but if there aren't enough pixels
+ to draw every one, QDial will skip notches to try and draw a uniform
+ set (e.g. by drawing every second or third notch).
+
+ Like the slider, the dial makes the QAbstractSlider functions
+ setValue(), addLine(), subtractLine(), addPage() and
+ subtractPage() available as slots.
+
+ The dial's keyboard interface is fairly simple: The
+ \key{left}/\key{up} and \key{right}/\key{down} arrow keys adjust
+ the dial's \l {QAbstractSlider::value} {value} by the defined
+ \l {QAbstractSlider::singleStep} {singleStep}, \key{Page Up} and
+ \key{Page Down} by the defined \l {QAbstractSlider::pageStep}
+ {pageStep}, and the \key Home and \key End keys set the value to
+ the defined \l {QAbstractSlider::minimum} {minimum} and
+ \l {QAbstractSlider::maximum} {maximum} values.
+
+ If you are using the mouse wheel to adjust the dial, the increment
+ value is determined by the lesser value of
+ \l{QApplication::wheelScrollLines()} {wheelScrollLines} multipled
+ by \l {QAbstractSlider::singleStep} {singleStep}, and
+ \l {QAbstractSlider::pageStep} {pageStep}.
+
+ \table
+ \row \o \inlineimage plastique-dial.png Screenshot of a dial in the Plastique widget style
+ \o \inlineimage windowsxp-dial.png Screenshot of a dial in the Windows XP widget style
+ \o \inlineimage macintosh-dial.png Screenshot of a dial in the Macintosh widget style
+ \row \o {3,1} Dials shown in various widget styles (from left to right):
+ \l{Plastique Style Widget Gallery}{Plastique},
+ \l{Windows XP Style Widget Gallery}{Windows XP},
+ \l{Macintosh Style Widget Gallery}{Macintosh}.
+ \endtable
+
+ \sa QScrollBar, QSpinBox, QSlider, {fowler}{GUI Design Handbook: Slider}, {Sliders Example}
+*/
+
+/*!
+ Constructs a dial.
+
+ The \a parent argument is sent to the QAbstractSlider constructor.
+*/
+QDial::QDial(QWidget *parent)
+ : QAbstractSlider(*new QDialPrivate, parent)
+{
+ Q_D(QDial);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QDial::QDial(QWidget *parent, const char *name)
+ : QAbstractSlider(*new QDialPrivate, parent)
+{
+ Q_D(QDial);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QDial::QDial(int minValue, int maxValue, int pageStep, int value,
+ QWidget *parent, const char *name)
+ : QAbstractSlider(*new QDialPrivate, parent)
+{
+ Q_D(QDial);
+ setObjectName(QString::fromAscii(name));
+ d->minimum = minValue;
+ d->maximum = maxValue;
+ d->pageStep = pageStep;
+ d->position = d->value = value;
+ d->init();
+}
+#endif
+/*!
+ Destroys the dial.
+*/
+QDial::~QDial()
+{
+}
+
+/*! \reimp */
+void QDial::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+
+void QDial::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionSlider option;
+ initStyleOption(&option);
+ p.drawComplexControl(QStyle::CC_Dial, option);
+}
+
+/*!
+ \reimp
+*/
+
+void QDial::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QDial);
+ if (d->maximum == d->minimum ||
+ (e->button() != Qt::LeftButton) ||
+ (e->buttons() ^ e->button())) {
+ e->ignore();
+ return;
+ }
+ e->accept();
+ setSliderPosition(d->valueFromPoint(e->pos()));
+ // ### This isn't quite right,
+ // we should be doing a hit test and only setting this if it's
+ // the actual dial thingie (similar to what QSlider does), but we have no
+ // subControls for QDial.
+ setSliderDown(true);
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::mouseReleaseEvent(QMouseEvent * e)
+{
+ Q_D(QDial);
+ if (e->buttons() & (~e->button()) ||
+ (e->button() != Qt::LeftButton)) {
+ e->ignore();
+ return;
+ }
+ e->accept();
+ setValue(d->valueFromPoint(e->pos()));
+ setSliderDown(false);
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::mouseMoveEvent(QMouseEvent * e)
+{
+ Q_D(QDial);
+ if (!(e->buttons() & Qt::LeftButton)) {
+ e->ignore();
+ return;
+ }
+ e->accept();
+ d->doNotEmit = true;
+ setSliderPosition(d->valueFromPoint(e->pos()));
+ d->doNotEmit = false;
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::sliderChange(SliderChange change)
+{
+ QAbstractSlider::sliderChange(change);
+}
+
+void QDial::setWrapping(bool enable)
+{
+ Q_D(QDial);
+ if (d->wrapping == enable)
+ return;
+ d->wrapping = enable;
+ update();
+}
+
+
+/*!
+ \property QDial::wrapping
+ \brief whether wrapping is enabled
+
+ If true, wrapping is enabled; otherwise some space is inserted at the bottom
+ of the dial to separate the ends of the range of valid values.
+
+ If enabled, the arrow can be oriented at any angle on the dial. If disabled,
+ the arrow will be restricted to the upper part of the dial; if it is rotated
+ into the space at the bottom of the dial, it will be clamped to the closest
+ end of the valid range of values.
+
+ By default this property is false.
+*/
+
+bool QDial::wrapping() const
+{
+ Q_D(const QDial);
+ return d->wrapping;
+}
+
+
+/*!
+ \property QDial::notchSize
+ \brief the current notch size
+
+ The notch size is in range control units, not pixels, and if
+ possible it is a multiple of singleStep() that results in an
+ on-screen notch size near notchTarget().
+
+ By default, this property has a value of 1.
+
+ \sa notchTarget(), singleStep()
+*/
+
+int QDial::notchSize() const
+{
+ Q_D(const QDial);
+ // radius of the arc
+ int r = qMin(width(), height())/2;
+ // length of the whole arc
+ int l = (int)(r * (d->wrapping ? 6 : 5) * Q_PI / 6);
+ // length of the arc from minValue() to minValue()+pageStep()
+ if (d->maximum > d->minimum + d->pageStep)
+ l = (int)(0.5 + l * d->pageStep / (d->maximum - d->minimum));
+ // length of a singleStep arc
+ l = l * d->singleStep / (d->pageStep ? d->pageStep : 1);
+ if (l < 1)
+ l = 1;
+ // how many times singleStep can be draw in d->target pixels
+ l = (int)(0.5 + d->target / l);
+ // we want notchSize() to be a non-zero multiple of lineStep()
+ if (!l)
+ l = 1;
+ return d->singleStep * l;
+}
+
+void QDial::setNotchTarget(double target)
+{
+ Q_D(QDial);
+ d->target = target;
+ update();
+}
+
+/*!
+ \property QDial::notchTarget
+ \brief the target number of pixels between notches
+
+ The notch target is the number of pixels QDial attempts to put
+ between each notch.
+
+ The actual size may differ from the target size.
+
+ The default notch target is 3.7 pixels.
+*/
+qreal QDial::notchTarget() const
+{
+ Q_D(const QDial);
+ return d->target;
+}
+
+
+void QDial::setNotchesVisible(bool visible)
+{
+ Q_D(QDial);
+ d->showNotches = visible;
+ update();
+}
+
+/*!
+ \property QDial::notchesVisible
+ \brief whether the notches are shown
+
+ If the property is true, a series of notches are drawn around the dial
+ to indicate the range of values available; otherwise no notches are
+ shown.
+
+ By default, this property is disabled.
+*/
+bool QDial::notchesVisible() const
+{
+ Q_D(const QDial);
+ return d->showNotches;
+}
+
+/*!
+ \reimp
+*/
+
+QSize QDial::minimumSizeHint() const
+{
+ return QSize(50, 50);
+}
+
+/*!
+ \reimp
+*/
+
+QSize QDial::sizeHint() const
+{
+ return QSize(100, 100).expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+bool QDial::event(QEvent *e)
+{
+ return QAbstractSlider::event(e);
+}
+
+/*!
+ \fn void QDial::dialPressed();
+
+ Use QAbstractSlider::sliderPressed() instead.
+*/
+
+/*!
+ \fn void QDial::dialMoved(int value);
+
+ Use QAbstractSlider::sliderMoved() instead.
+*/
+
+/*!
+ \fn void QDial::dialReleased();
+
+ Use QAbstractSlider::sliderReleased() instead.
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DIAL
diff --git a/src/widgets/widgets/qdial.h b/src/widgets/widgets/qdial.h
new file mode 100644
index 0000000000..7687b7e7a1
--- /dev/null
+++ b/src/widgets/widgets/qdial.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QDIAL_H
+#define QDIAL_H
+
+#include <QtWidgets/qabstractslider.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_DIAL
+
+class QDialPrivate;
+class QStyleOptionSlider;
+
+class Q_WIDGETS_EXPORT QDial: public QAbstractSlider
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool wrapping READ wrapping WRITE setWrapping)
+ Q_PROPERTY(int notchSize READ notchSize)
+ Q_PROPERTY(qreal notchTarget READ notchTarget WRITE setNotchTarget)
+ Q_PROPERTY(bool notchesVisible READ notchesVisible WRITE setNotchesVisible)
+public:
+ explicit QDial(QWidget *parent = 0);
+
+ ~QDial();
+
+ bool wrapping() const;
+
+ int notchSize() const;
+
+ void setNotchTarget(double target);
+ qreal notchTarget() const;
+ bool notchesVisible() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+public Q_SLOTS:
+ void setNotchesVisible(bool visible);
+ void setWrapping(bool on);
+
+protected:
+ bool event(QEvent *e);
+ void resizeEvent(QResizeEvent *re);
+ void paintEvent(QPaintEvent *pe);
+
+ void mousePressEvent(QMouseEvent *me);
+ void mouseReleaseEvent(QMouseEvent *me);
+ void mouseMoveEvent(QMouseEvent *me);
+
+ void sliderChange(SliderChange change);
+ void initStyleOption(QStyleOptionSlider *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QDial(int minValue, int maxValue, int pageStep, int value,
+ QWidget* parent = 0, const char* name = 0);
+ QT3_SUPPORT_CONSTRUCTOR QDial(QWidget *parent, const char *name);
+
+Q_SIGNALS:
+ QT_MOC_COMPAT void dialPressed();
+ QT_MOC_COMPAT void dialMoved(int value);
+ QT_MOC_COMPAT void dialReleased();
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QDial)
+ Q_DISABLE_COPY(QDial)
+};
+
+#endif // QT_NO_DIAL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDIAL_H
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
new file mode 100644
index 0000000000..64fd3caa1e
--- /dev/null
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -0,0 +1,1285 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qhash.h>
+#include <QtWidgets/qpushbutton.h>
+#include <QtWidgets/qstyle.h>
+#include <QtWidgets/qlayout.h>
+#include <QtWidgets/qdialog.h>
+#include <QtWidgets/qapplication.h>
+#include <private/qwidget_p.h>
+#include <QtWidgets/qaction.h>
+
+#include "qdialogbuttonbox.h"
+
+#ifdef QT_SOFTKEYS_ENABLED
+#include <QtWidgets/qaction.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDialogButtonBox
+ \since 4.2
+ \brief The QDialogButtonBox class is a widget that presents buttons in a
+ layout that is appropriate to the current widget style.
+
+ \ingroup dialog-classes
+
+
+ Dialogs and message boxes typically present buttons in a layout that
+ conforms to the interface guidelines for that platform. Invariably,
+ different platforms have different layouts for their dialogs.
+ QDialogButtonBox allows a developer to add buttons to it and will
+ automatically use the appropriate layout for the user's desktop
+ environment.
+
+ Most buttons for a dialog follow certain roles. Such roles include:
+
+ \list
+ \o Accepting or rejecting the dialog.
+ \o Asking for help.
+ \o Performing actions on the dialog itself (such as resetting fields or
+ applying changes).
+ \endlist
+
+ There can also be alternate ways of dismissing the dialog which may cause
+ destructive results.
+
+ Most dialogs have buttons that can almost be considered standard (e.g.
+ \gui OK and \gui Cancel buttons). It is sometimes convenient to create these
+ buttons in a standard way.
+
+ There are a couple ways of using QDialogButtonBox. One ways is to create
+ the buttons (or button texts) yourself and add them to the button box,
+ specifying their role.
+
+ \snippet examples/dialogs/extension/finddialog.cpp 1
+
+ Alternatively, QDialogButtonBox provides several standard buttons (e.g. OK, Cancel, Save)
+ that you can use. They exist as flags so you can OR them together in the constructor.
+
+ \snippet examples/dialogs/tabdialog/tabdialog.cpp 2
+
+ You can mix and match normal buttons and standard buttons.
+
+ Currently the buttons are laid out in the following way if the button box is horizontal:
+ \table
+ \row \o \inlineimage buttonbox-gnomelayout-horizontal.png GnomeLayout Horizontal
+ \o Button box laid out in horizontal GnomeLayout
+ \row \o \inlineimage buttonbox-kdelayout-horizontal.png KdeLayout Horizontal
+ \o Button box laid out in horizontal KdeLayout
+ \row \o \inlineimage buttonbox-maclayout-horizontal.png MacLayout Horizontal
+ \o Button box laid out in horizontal MacLayout
+ \row \o \inlineimage buttonbox-winlayout-horizontal.png WinLayout Horizontal
+ \o Button box laid out in horizontal WinLayout
+ \endtable
+
+ The buttons are laid out the following way if the button box is vertical:
+
+ \table
+ \row \o GnomeLayout
+ \o KdeLayout
+ \o MacLayout
+ \o WinLayout
+ \row \o \inlineimage buttonbox-gnomelayout-vertical.png GnomeLayout Vertical
+ \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical
+ \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical
+ \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical
+ \endtable
+
+ Additionally, button boxes that contain only buttons with ActionRole or
+ HelpRole can be considered modeless and have an alternate look on Mac OS X:
+
+ \table
+ \row \o modeless horizontal MacLayout
+ \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout
+ \endtable
+
+ When a button is clicked in the button box, the clicked() signal is emitted
+ for the actual button is that is pressed. For convenience, if the button
+ has an AcceptRole, RejectRole, or HelpRole, the accepted(), rejected(), or
+ helpRequested() signals are emitted respectively.
+
+ If you want a specific button to be default you need to call
+ QPushButton::setDefault() on it yourself. However, if there is no default
+ button set and to preserve which button is the default button across
+ platforms when using the QPushButton::autoDefault property, the first push
+ button with the accept role is made the default button when the
+ QDialogButtonBox is shown,
+
+ \sa QMessageBox, QPushButton, QDialog
+*/
+
+enum {
+ AcceptRole = QDialogButtonBox::AcceptRole,
+ RejectRole = QDialogButtonBox::RejectRole,
+ DestructiveRole = QDialogButtonBox::DestructiveRole,
+ ActionRole = QDialogButtonBox::ActionRole,
+ HelpRole = QDialogButtonBox::HelpRole,
+ YesRole = QDialogButtonBox::YesRole,
+ NoRole = QDialogButtonBox::NoRole,
+ ApplyRole = QDialogButtonBox::ApplyRole,
+ ResetRole = QDialogButtonBox::ResetRole,
+
+ AlternateRole = 0x10000000,
+ Stretch = 0x20000000,
+ EOL = 0x40000000,
+ Reverse = 0x80000000
+};
+
+static QDialogButtonBox::ButtonRole roleFor(QDialogButtonBox::StandardButton button)
+{
+ switch (button) {
+ case QDialogButtonBox::Ok:
+ case QDialogButtonBox::Save:
+ case QDialogButtonBox::Open:
+ case QDialogButtonBox::SaveAll:
+ case QDialogButtonBox::Retry:
+ case QDialogButtonBox::Ignore:
+ return QDialogButtonBox::AcceptRole;
+
+ case QDialogButtonBox::Cancel:
+ case QDialogButtonBox::Close:
+ case QDialogButtonBox::Abort:
+ return QDialogButtonBox::RejectRole;
+
+ case QDialogButtonBox::Discard:
+ return QDialogButtonBox::DestructiveRole;
+
+ case QDialogButtonBox::Help:
+ return QDialogButtonBox::HelpRole;
+
+ case QDialogButtonBox::Apply:
+ return QDialogButtonBox::ApplyRole;
+
+ case QDialogButtonBox::Yes:
+ case QDialogButtonBox::YesToAll:
+ return QDialogButtonBox::YesRole;
+
+ case QDialogButtonBox::No:
+ case QDialogButtonBox::NoToAll:
+ return QDialogButtonBox::NoRole;
+
+ case QDialogButtonBox::RestoreDefaults:
+ case QDialogButtonBox::Reset:
+ return QDialogButtonBox::ResetRole;
+
+ case QDialogButtonBox::NoButton: // NoButton means zero buttons, not "No" button
+ ;
+ }
+
+ return QDialogButtonBox::InvalidRole;
+}
+
+static const int layouts[2][5][14] =
+{
+ // Qt::Horizontal
+ {
+ // WinLayout
+ { ResetRole, Stretch, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, ActionRole, RejectRole, ApplyRole,
+ HelpRole, EOL, EOL, EOL },
+
+ // MacLayout
+ { HelpRole, ResetRole, ApplyRole, ActionRole, Stretch, DestructiveRole | Reverse,
+ AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL, EOL },
+
+ // KdeLayout
+ { HelpRole, ResetRole, Stretch, YesRole, NoRole, ActionRole, AcceptRole, AlternateRole,
+ ApplyRole, DestructiveRole, RejectRole, EOL },
+
+ // GnomeLayout
+ { HelpRole, ResetRole, Stretch, ActionRole, ApplyRole | Reverse, DestructiveRole | Reverse,
+ AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL },
+
+ // Mac modeless
+ { ResetRole, ApplyRole, ActionRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL }
+ },
+
+ // Qt::Vertical
+ {
+ // WinLayout
+ { ActionRole, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, RejectRole, ApplyRole, ResetRole,
+ HelpRole, Stretch, EOL, EOL, EOL },
+
+ // MacLayout
+ { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, Stretch, ActionRole, ApplyRole,
+ ResetRole, HelpRole, EOL, EOL },
+
+ // KdeLayout
+ { AcceptRole, AlternateRole, ApplyRole, ActionRole, YesRole, NoRole, Stretch, ResetRole,
+ DestructiveRole, RejectRole, HelpRole, EOL },
+
+ // GnomeLayout
+ { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, ApplyRole, ActionRole, Stretch,
+ ResetRole, HelpRole, EOL, EOL, EOL },
+
+ // Mac modeless
+ { ActionRole, ApplyRole, ResetRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL }
+ }
+};
+
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+class QDialogButtonEnabledProxy : public QObject
+{
+public:
+ QDialogButtonEnabledProxy(QObject *parent, QWidget *src, QAction *trg) : QObject(parent), source(src), target(trg)
+ {
+ source->installEventFilter(this);
+ target->setEnabled(source->isEnabled());
+ }
+ ~QDialogButtonEnabledProxy()
+ {
+ source->removeEventFilter(this);
+ }
+ bool eventFilter(QObject *object, QEvent *event)
+ {
+ if (object == source && event->type() == QEvent::EnabledChange) {
+ target->setEnabled(source->isEnabled());
+ }
+ return false;
+ };
+private:
+ QWidget *source;
+ QAction *target;
+};
+#endif
+
+class QDialogButtonBoxPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QDialogButtonBox)
+
+public:
+ QDialogButtonBoxPrivate(Qt::Orientation orient);
+
+ QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
+ QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
+#ifdef QT_SOFTKEYS_ENABLED
+ QHash<QAbstractButton *, QAction *> softKeyActions;
+#endif
+
+ Qt::Orientation orientation;
+ QDialogButtonBox::ButtonLayout layoutPolicy;
+ QBoxLayout *buttonLayout;
+ bool internalRemove;
+ bool center;
+
+ void createStandardButtons(QDialogButtonBox::StandardButtons buttons);
+
+ void layoutButtons();
+ void initLayout();
+ void resetLayout();
+ QPushButton *createButton(QDialogButtonBox::StandardButton button, bool doLayout = true);
+ void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, bool doLayout = true);
+ void _q_handleButtonDestroyed();
+ void _q_handleButtonClicked();
+ void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse);
+ void retranslateStrings();
+ const char *standardButtonText(QDialogButtonBox::StandardButton sbutton) const;
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+ QAction *createSoftKey(QAbstractButton *button, QDialogButtonBox::ButtonRole role);
+#endif
+};
+
+QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
+ : orientation(orient), buttonLayout(0), internalRemove(false), center(false)
+{
+}
+
+void QDialogButtonBoxPrivate::initLayout()
+{
+ Q_Q(QDialogButtonBox);
+ layoutPolicy = QDialogButtonBox::ButtonLayout(q->style()->styleHint(QStyle::SH_DialogButtonLayout, 0, q));
+ bool createNewLayout = buttonLayout == 0
+ || (orientation == Qt::Horizontal && qobject_cast<QVBoxLayout *>(buttonLayout) != 0)
+ || (orientation == Qt::Vertical && qobject_cast<QHBoxLayout *>(buttonLayout) != 0);
+ if (createNewLayout) {
+ delete buttonLayout;
+ if (orientation == Qt::Horizontal)
+ buttonLayout = new QHBoxLayout(q);
+ else
+ buttonLayout = new QVBoxLayout(q);
+ }
+
+ int left, top, right, bottom;
+ setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem);
+ getLayoutItemMargins(&left, &top, &right, &bottom);
+ buttonLayout->setContentsMargins(-left, -top, -right, -bottom);
+
+ if (!q->testAttribute(Qt::WA_WState_OwnSizePolicy)) {
+ QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::ButtonBox);
+ if (orientation == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ }
+
+ // ### move to a real init() function
+ q->setFocusPolicy(Qt::TabFocus);
+}
+
+void QDialogButtonBoxPrivate::resetLayout()
+{
+ //delete buttonLayout;
+ initLayout();
+ layoutButtons();
+}
+
+void QDialogButtonBoxPrivate::addButtonsToLayout(const QList<QAbstractButton *> &buttonList,
+ bool reverse)
+{
+ int start = reverse ? buttonList.count() - 1 : 0;
+ int end = reverse ? -1 : buttonList.count();
+ int step = reverse ? -1 : 1;
+
+ for (int i = start; i != end; i += step) {
+ QAbstractButton *button = buttonList.at(i);
+ buttonLayout->addWidget(button);
+ button->show();
+ }
+}
+
+void QDialogButtonBoxPrivate::layoutButtons()
+{
+ Q_Q(QDialogButtonBox);
+ const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item
+
+ for (int i = buttonLayout->count() - 1; i >= 0; --i) {
+ QLayoutItem *item = buttonLayout->takeAt(i);
+ if (QWidget *widget = item->widget())
+ widget->hide();
+ delete item;
+ }
+
+ int tmpPolicy = layoutPolicy;
+
+ static const int M = 5;
+ static const int ModalRoles[M] = { AcceptRole, RejectRole, DestructiveRole, YesRole, NoRole };
+ if (tmpPolicy == QDialogButtonBox::MacLayout) {
+ bool hasModalButton = false;
+ for (int i = 0; i < M; ++i) {
+ if (!buttonLists[ModalRoles[i]].isEmpty()) {
+ hasModalButton = true;
+ break;
+ }
+ }
+ if (!hasModalButton)
+ tmpPolicy = 4; // Mac modeless
+ }
+
+ const int *currentLayout = layouts[orientation == Qt::Vertical][tmpPolicy];
+
+ if (center)
+ buttonLayout->addStretch();
+
+ QList<QAbstractButton *> acceptRoleList = buttonLists[AcceptRole];
+
+ while (*currentLayout != EOL) {
+ int role = (*currentLayout & ~Reverse);
+ bool reverse = (*currentLayout & Reverse);
+
+ switch (role) {
+ case Stretch:
+ if (!center)
+ buttonLayout->addStretch();
+ break;
+ case AcceptRole: {
+ if (acceptRoleList.isEmpty())
+ break;
+ // Only the first one
+ QAbstractButton *button = acceptRoleList.first();
+ buttonLayout->addWidget(button);
+ button->show();
+ }
+ break;
+ case AlternateRole:
+ {
+ if (acceptRoleList.size() < 2)
+ break;
+ QList<QAbstractButton *> list = acceptRoleList;
+ list.removeFirst();
+ addButtonsToLayout(list, reverse);
+ }
+ break;
+ case DestructiveRole:
+ {
+ const QList<QAbstractButton *> &list = buttonLists[role];
+
+ /*
+ Mac: Insert a gap on the left of the destructive
+ buttons to ensure that they don't get too close to
+ the help and action buttons (but only if there are
+ some buttons to the left of the destructive buttons
+ (and the stretch, whence buttonLayout->count() > 1
+ and not 0)).
+ */
+ if (tmpPolicy == QDialogButtonBox::MacLayout
+ && !list.isEmpty() && buttonLayout->count() > 1)
+ buttonLayout->addSpacing(MacGap);
+
+ addButtonsToLayout(list, reverse);
+
+ /*
+ Insert a gap between the destructive buttons and the
+ accept and reject buttons.
+ */
+ if (tmpPolicy == QDialogButtonBox::MacLayout && !list.isEmpty())
+ buttonLayout->addSpacing(MacGap);
+ }
+ break;
+ case RejectRole:
+ case ActionRole:
+ case HelpRole:
+ case YesRole:
+ case NoRole:
+ case ApplyRole:
+ case ResetRole:
+ addButtonsToLayout(buttonLists[role], reverse);
+ }
+ ++currentLayout;
+ }
+
+ QWidget *lastWidget = 0;
+ q->setFocusProxy(0);
+ for (int i = 0; i < buttonLayout->count(); ++i) {
+ QLayoutItem *item = buttonLayout->itemAt(i);
+ if (QWidget *widget = item->widget()) {
+ if (lastWidget)
+ QWidget::setTabOrder(lastWidget, widget);
+ else
+ q->setFocusProxy(widget);
+ lastWidget = widget;
+ }
+ }
+
+ if (center)
+ buttonLayout->addStretch();
+}
+
+QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton,
+ bool doLayout)
+{
+ Q_Q(QDialogButtonBox);
+ const char *buttonText = 0;
+ int icon = 0;
+
+ switch (sbutton) {
+ case QDialogButtonBox::Ok:
+ icon = QStyle::SP_DialogOkButton;
+ break;
+ case QDialogButtonBox::Save:
+ icon = QStyle::SP_DialogSaveButton;
+ break;
+ case QDialogButtonBox::Open:
+ icon = QStyle::SP_DialogOpenButton;
+ break;
+ case QDialogButtonBox::Cancel:
+ icon = QStyle::SP_DialogCancelButton;
+ break;
+ case QDialogButtonBox::Close:
+ icon = QStyle::SP_DialogCloseButton;
+ break;
+ case QDialogButtonBox::Apply:
+ icon = QStyle::SP_DialogApplyButton;
+ break;
+ case QDialogButtonBox::Reset:
+ icon = QStyle::SP_DialogResetButton;
+ break;
+ case QDialogButtonBox::Help:
+ icon = QStyle::SP_DialogHelpButton;
+ break;
+ case QDialogButtonBox::Discard:
+ icon = QStyle::SP_DialogDiscardButton;
+ break;
+ case QDialogButtonBox::Yes:
+ icon = QStyle::SP_DialogYesButton;
+ break;
+ case QDialogButtonBox::No:
+ icon = QStyle::SP_DialogNoButton;
+ break;
+ case QDialogButtonBox::YesToAll:
+ case QDialogButtonBox::NoToAll:
+ case QDialogButtonBox::SaveAll:
+ case QDialogButtonBox::Abort:
+ case QDialogButtonBox::Retry:
+ case QDialogButtonBox::Ignore:
+ case QDialogButtonBox::RestoreDefaults:
+ break;
+ case QDialogButtonBox::NoButton:
+ return 0;
+ ;
+ }
+ buttonText = standardButtonText(sbutton);
+
+ QPushButton *button = new QPushButton(QDialogButtonBox::tr(buttonText), q);
+ QStyle *style = q->style();
+ if (style->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons, 0, q) && icon != 0)
+ button->setIcon(style->standardIcon(QStyle::StandardPixmap(icon), 0, q));
+ if (style != QApplication::style()) // Propagate style
+ button->setStyle(style);
+ standardButtonHash.insert(button, sbutton);
+ if (roleFor(sbutton) != QDialogButtonBox::InvalidRole) {
+ addButton(button, roleFor(sbutton), doLayout);
+ } else {
+ qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
+ }
+
+#ifdef Q_WS_MAC
+ // Since mnemonics is off by default on Mac, we add a Cmd-D
+ // shortcut here to e.g. make the "Don't Save" button work nativly:
+ if (sbutton == QDialogButtonBox::Discard)
+ button->setShortcut(QKeySequence(QLatin1String("Ctrl+D")));
+#endif
+
+ return button;
+}
+
+void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
+ bool doLayout)
+{
+ Q_Q(QDialogButtonBox);
+ QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_handleButtonClicked()));
+ QObject::connect(button, SIGNAL(destroyed()), q, SLOT(_q_handleButtonDestroyed()));
+ buttonLists[role].append(button);
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+ QAction *action = createSoftKey(button, role);
+ softKeyActions.insert(button, action);
+ new QDialogButtonEnabledProxy(action, button, action);
+#endif
+ if (doLayout)
+ layoutButtons();
+}
+
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+QAction* QDialogButtonBoxPrivate::createSoftKey(QAbstractButton *button, QDialogButtonBox::ButtonRole role)
+{
+ Q_Q(QDialogButtonBox);
+ QAction::SoftKeyRole softkeyRole;
+
+ QAction *action = new QAction(button->text(), button);
+
+ switch (role) {
+ case ApplyRole:
+ case AcceptRole:
+ case YesRole:
+ case ActionRole:
+ case HelpRole:
+ softkeyRole = QAction::PositiveSoftKey;
+ break;
+ case RejectRole:
+ case DestructiveRole:
+ case NoRole:
+ case ResetRole:
+ softkeyRole = QAction::NegativeSoftKey;
+ break;
+ default:
+ break;
+ }
+ QObject::connect(action, SIGNAL(triggered()), button, SIGNAL(clicked()));
+ action->setSoftKeyRole(softkeyRole);
+
+
+ QWidget *dialog = 0;
+ QWidget *p = q;
+ while (p && !p->isWindow()) {
+ p = p->parentWidget();
+ if ((dialog = qobject_cast<QDialog *>(p)))
+ break;
+ }
+
+ if (dialog) {
+ dialog->addAction(action);
+ } else {
+ q->addAction(action);
+ }
+
+ return action;
+}
+#endif
+
+void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardButtons buttons)
+{
+ uint i = QDialogButtonBox::FirstButton;
+ while (i <= QDialogButtonBox::LastButton) {
+ if (i & buttons) {
+ createButton(QDialogButtonBox::StandardButton(i), false);
+ }
+ i = i << 1;
+ }
+ layoutButtons();
+}
+
+const char *QDialogButtonBoxPrivate::standardButtonText(QDialogButtonBox::StandardButton sbutton) const
+{
+ const char *buttonText = 0;
+ bool gnomeLayout = (layoutPolicy == QDialogButtonBox::GnomeLayout);
+ switch (sbutton) {
+ case QDialogButtonBox::Ok:
+ buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&OK") : QT_TRANSLATE_NOOP("QDialogButtonBox", "OK");
+ break;
+ case QDialogButtonBox::Save:
+ buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Save") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Save");
+ break;
+ case QDialogButtonBox::Open:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Open");
+ break;
+ case QDialogButtonBox::Cancel:
+ buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Cancel") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Cancel");
+ break;
+ case QDialogButtonBox::Close:
+ buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Close") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Close");
+ break;
+ case QDialogButtonBox::Apply:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Apply");
+ break;
+ case QDialogButtonBox::Reset:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Reset");
+ break;
+ case QDialogButtonBox::Help:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Help");
+ break;
+ case QDialogButtonBox::Discard:
+ if (layoutPolicy == QDialogButtonBox::MacLayout)
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Don't Save");
+ else if (layoutPolicy == QDialogButtonBox::GnomeLayout)
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Close without Saving");
+ else
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Discard");
+ break;
+ case QDialogButtonBox::Yes:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&Yes");
+ break;
+ case QDialogButtonBox::YesToAll:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Yes to &All");
+ break;
+ case QDialogButtonBox::No:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&No");
+ break;
+ case QDialogButtonBox::NoToAll:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "N&o to All");
+ break;
+ case QDialogButtonBox::SaveAll:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Save All");
+ break;
+ case QDialogButtonBox::Abort:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Abort");
+ break;
+ case QDialogButtonBox::Retry:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Retry");
+ break;
+ case QDialogButtonBox::Ignore:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Ignore");
+ break;
+ case QDialogButtonBox::RestoreDefaults:
+ buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Restore Defaults");
+ break;
+ case QDialogButtonBox::NoButton:
+ ;
+ } // switch
+ return buttonText;
+}
+
+void QDialogButtonBoxPrivate::retranslateStrings()
+{
+ const char *buttonText = 0;
+ QHash<QPushButton *, QDialogButtonBox::StandardButton>::iterator it = standardButtonHash.begin();
+ while (it != standardButtonHash.end()) {
+ buttonText = standardButtonText(it.value());
+ if (buttonText) {
+ QPushButton *button = it.key();
+ button->setText(QDialogButtonBox::tr(buttonText));
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+ QAction *action = softKeyActions.value(button, 0);
+ if (action)
+ action->setText(button->text());
+#endif
+ }
+ ++it;
+ }
+}
+
+/*!
+ Constructs an empty, horizontal button box with the given \a parent.
+
+ \sa orientation, addButton()
+*/
+QDialogButtonBox::QDialogButtonBox(QWidget *parent)
+ : QWidget(*new QDialogButtonBoxPrivate(Qt::Horizontal), parent, 0)
+{
+ d_func()->initLayout();
+}
+
+/*!
+ Constructs an empty button box with the given \a orientation and \a parent.
+
+ \sa orientation, addButton()
+*/
+QDialogButtonBox::QDialogButtonBox(Qt::Orientation orientation, QWidget *parent)
+ : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0)
+{
+ d_func()->initLayout();
+}
+
+/*!
+ Constructs a button box with the given \a orientation and \a parent, containing
+ the standard buttons specified by \a buttons.
+
+ \sa orientation, addButton()
+*/
+QDialogButtonBox::QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation,
+ QWidget *parent)
+ : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0)
+{
+ d_func()->initLayout();
+ d_func()->createStandardButtons(buttons);
+}
+
+/*!
+ Destroys the button box.
+*/
+QDialogButtonBox::~QDialogButtonBox()
+{
+}
+
+/*!
+ \enum QDialogButtonBox::ButtonRole
+ \enum QMessageBox::ButtonRole
+
+ This enum describes the roles that can be used to describe buttons in
+ the button box. Combinations of these roles are as flags used to
+ describe different aspects of their behavior.
+
+ \value InvalidRole The button is invalid.
+ \value AcceptRole Clicking the button causes the dialog to be accepted
+ (e.g. OK).
+ \value RejectRole Clicking the button causes the dialog to be rejected
+ (e.g. Cancel).
+ \value DestructiveRole Clicking the button causes a destructive change
+ (e.g. for Discarding Changes) and closes the dialog.
+ \value ActionRole Clicking the button causes changes to the elements within
+ the dialog.
+ \value HelpRole The button can be clicked to request help.
+ \value YesRole The button is a "Yes"-like button.
+ \value NoRole The button is a "No"-like button.
+ \value ApplyRole The button applies current changes.
+ \value ResetRole The button resets the dialog's fields to default values.
+
+ \omitvalue NRoles
+
+ \sa StandardButton
+*/
+
+/*!
+ \enum QDialogButtonBox::StandardButton
+
+ These enums describe flags for standard buttons. Each button has a
+ defined \l ButtonRole.
+
+ \value Ok An "OK" button defined with the \l AcceptRole.
+ \value Open A "Open" button defined with the \l AcceptRole.
+ \value Save A "Save" button defined with the \l AcceptRole.
+ \value Cancel A "Cancel" button defined with the \l RejectRole.
+ \value Close A "Close" button defined with the \l RejectRole.
+ \value Discard A "Discard" or "Don't Save" button, depending on the platform,
+ defined with the \l DestructiveRole.
+ \value Apply An "Apply" button defined with the \l ApplyRole.
+ \value Reset A "Reset" button defined with the \l ResetRole.
+ \value RestoreDefaults A "Restore Defaults" button defined with the \l ResetRole.
+ \value Help A "Help" button defined with the \l HelpRole.
+ \value SaveAll A "Save All" button defined with the \l AcceptRole.
+ \value Yes A "Yes" button defined with the \l YesRole.
+ \value YesToAll A "Yes to All" button defined with the \l YesRole.
+ \value No A "No" button defined with the \l NoRole.
+ \value NoToAll A "No to All" button defined with the \l NoRole.
+ \value Abort An "Abort" button defined with the \l RejectRole.
+ \value Retry A "Retry" button defined with the \l AcceptRole.
+ \value Ignore An "Ignore" button defined with the \l AcceptRole.
+
+ \value NoButton An invalid button.
+
+ \omitvalue FirstButton
+ \omitvalue LastButton
+
+ \sa ButtonRole, standardButtons
+*/
+
+/*!
+ \enum QDialogButtonBox::ButtonLayout
+
+ This enum describes the layout policy to be used when arranging the buttons
+ contained in the button box.
+
+ \value WinLayout Use a policy appropriate for applications on Windows.
+ \value MacLayout Use a policy appropriate for applications on Mac OS X.
+ \value KdeLayout Use a policy appropriate for applications on KDE.
+ \value GnomeLayout Use a policy appropriate for applications on GNOME.
+
+ The button layout is specified by the \l{style()}{current style}. However,
+ on the X11 platform, it may be influenced by the desktop environment.
+*/
+
+/*!
+ \fn void QDialogButtonBox::clicked(QAbstractButton *button)
+
+ This signal is emitted when a button inside the button box is clicked. The
+ specific button that was pressed is specified by \a button.
+
+ \sa accepted(), rejected(), helpRequested()
+*/
+
+/*!
+ \fn void QDialogButtonBox::accepted()
+
+ This signal is emitted when a button inside the button box is clicked, as long
+ as it was defined with the \l AcceptRole or \l YesRole.
+
+ \sa rejected(), clicked() helpRequested()
+*/
+
+/*!
+ \fn void QDialogButtonBox::rejected()
+
+ This signal is emitted when a button inside the button box is clicked, as long
+ as it was defined with the \l RejectRole or \l NoRole.
+
+ \sa accepted() helpRequested() clicked()
+*/
+
+/*!
+ \fn void QDialogButtonBox::helpRequested()
+
+ This signal is emitted when a button inside the button box is clicked, as long
+ as it was defined with the \l HelpRole.
+
+ \sa accepted() rejected() clicked()
+*/
+
+/*!
+ \property QDialogButtonBox::orientation
+ \brief the orientation of the button box
+
+ By default, the orientation is horizontal (i.e. the buttons are laid out
+ side by side). The possible orientations are Qt::Horizontal and
+ Qt::Vertical.
+*/
+Qt::Orientation QDialogButtonBox::orientation() const
+{
+ return d_func()->orientation;
+}
+
+void QDialogButtonBox::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QDialogButtonBox);
+ if (orientation == d->orientation)
+ return;
+
+ d->orientation = orientation;
+ d->resetLayout();
+}
+
+/*!
+ Clears the button box, deleting all buttons within it.
+
+ \sa removeButton(), addButton()
+*/
+void QDialogButtonBox::clear()
+{
+ Q_D(QDialogButtonBox);
+#ifdef QT_SOFTKEYS_ENABLED
+ // Delete softkey actions as they have the buttons as parents
+ qDeleteAll(d->softKeyActions.values());
+ d->softKeyActions.clear();
+#endif
+ // Remove the created standard buttons, they should be in the other lists, which will
+ // do the deletion
+ d->standardButtonHash.clear();
+ for (int i = 0; i < NRoles; ++i) {
+ QList<QAbstractButton *> &list = d->buttonLists[i];
+ while (list.count()) {
+ QAbstractButton *button = list.takeAt(0);
+ QObject::disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
+ delete button;
+ }
+ }
+}
+
+/*!
+ Returns a list of all the buttons that have been added to the button box.
+
+ \sa buttonRole(), addButton(), removeButton()
+*/
+QList<QAbstractButton *> QDialogButtonBox::buttons() const
+{
+ Q_D(const QDialogButtonBox);
+ QList<QAbstractButton *> finalList;
+ for (int i = 0; i < NRoles; ++i) {
+ const QList<QAbstractButton *> &list = d->buttonLists[i];
+ for (int j = 0; j < list.count(); ++j)
+ finalList.append(list.at(j));
+ }
+ return finalList;
+}
+
+/*!
+ Returns the button role for the specified \a button. This function returns
+ \l InvalidRole if \a button is 0 or has not been added to the button box.
+
+ \sa buttons(), addButton()
+*/
+QDialogButtonBox::ButtonRole QDialogButtonBox::buttonRole(QAbstractButton *button) const
+{
+ Q_D(const QDialogButtonBox);
+ for (int i = 0; i < NRoles; ++i) {
+ const QList<QAbstractButton *> &list = d->buttonLists[i];
+ for (int j = 0; j < list.count(); ++j) {
+ if (list.at(j) == button)
+ return ButtonRole(i);
+ }
+ }
+ return InvalidRole;
+}
+
+/*!
+ Removes \a button from the button box without deleting it and sets its parent to zero.
+
+ \sa clear(), buttons(), addButton()
+*/
+void QDialogButtonBox::removeButton(QAbstractButton *button)
+{
+ Q_D(QDialogButtonBox);
+
+ if (!button)
+ return;
+
+ // Remove it from the standard button hash first and then from the roles
+ if (QPushButton *pushButton = qobject_cast<QPushButton *>(button))
+ d->standardButtonHash.remove(pushButton);
+ for (int i = 0; i < NRoles; ++i) {
+ QList<QAbstractButton *> &list = d->buttonLists[i];
+ for (int j = 0; j < list.count(); ++j) {
+ if (list.at(j) == button) {
+ list.takeAt(j);
+ if (!d->internalRemove) {
+ disconnect(button, SIGNAL(clicked()), this, SLOT(_q_handleButtonClicked()));
+ disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
+ }
+ break;
+ }
+ }
+ }
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+ QAction *action = d->softKeyActions.value(button, 0);
+ if (action) {
+ d->softKeyActions.remove(button);
+ delete action;
+ }
+#endif
+ if (!d->internalRemove)
+ button->setParent(0);
+}
+
+/*!
+ Adds the given \a button to the button box with the specified \a role.
+ If the role is invalid, the button is not added.
+
+ If the button has already been added, it is removed and added again with the
+ new role.
+
+ \note The button box takes ownership of the button.
+
+ \sa removeButton(), clear()
+*/
+void QDialogButtonBox::addButton(QAbstractButton *button, ButtonRole role)
+{
+ Q_D(QDialogButtonBox);
+ if (role <= InvalidRole || role >= NRoles) {
+ qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
+ return;
+ }
+ removeButton(button);
+ button->setParent(this);
+ d->addButton(button, role);
+}
+
+/*!
+ Creates a push button with the given \a text, adds it to the button box for the
+ specified \a role, and returns the corresponding push button. If \a role is
+ invalid, no button is created, and zero is returned.
+
+ \sa removeButton(), clear()
+*/
+QPushButton *QDialogButtonBox::addButton(const QString &text, ButtonRole role)
+{
+ Q_D(QDialogButtonBox);
+ if (role <= InvalidRole || role >= NRoles) {
+ qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
+ return 0;
+ }
+ QPushButton *button = new QPushButton(text, this);
+ d->addButton(button, role);
+ return button;
+}
+
+/*!
+ Adds a standard \a button to the button box if it is valid to do so, and returns
+ a push button. If \a button is invalid, it is not added to the button box, and
+ zero is returned.
+
+ \sa removeButton(), clear()
+*/
+QPushButton *QDialogButtonBox::addButton(StandardButton button)
+{
+ Q_D(QDialogButtonBox);
+ return d->createButton(button);
+}
+
+/*!
+ \property QDialogButtonBox::standardButtons
+ \brief collection of standard buttons in the button box
+
+ This property controls which standard buttons are used by the button box.
+
+ \sa addButton()
+*/
+void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
+{
+ Q_D(QDialogButtonBox);
+#ifdef QT_SOFTKEYS_ENABLED
+ // Delete softkey actions since they have the buttons as parents
+ qDeleteAll(d->softKeyActions.values());
+ d->softKeyActions.clear();
+#endif
+ // Clear out all the old standard buttons, then recreate them.
+ qDeleteAll(d->standardButtonHash.keys());
+ d->standardButtonHash.clear();
+
+ d->createStandardButtons(buttons);
+}
+
+QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
+{
+ Q_D(const QDialogButtonBox);
+ StandardButtons standardButtons = NoButton;
+ QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin();
+ while (it != d->standardButtonHash.constEnd()) {
+ standardButtons |= it.value();
+ ++it;
+ }
+ return standardButtons;
+}
+
+/*!
+ Returns the QPushButton corresponding to the standard button \a which,
+ or 0 if the standard button doesn't exist in this button box.
+
+ \sa standardButton(), standardButtons(), buttons()
+*/
+QPushButton *QDialogButtonBox::button(StandardButton which) const
+{
+ Q_D(const QDialogButtonBox);
+ return d->standardButtonHash.key(which);
+}
+
+/*!
+ Returns the standard button enum value corresponding to the given \a button,
+ or NoButton if the given \a button isn't a standard button.
+
+ \sa button(), buttons(), standardButtons()
+*/
+QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const
+{
+ Q_D(const QDialogButtonBox);
+ return d->standardButtonHash.value(static_cast<QPushButton *>(button));
+}
+
+void QDialogButtonBoxPrivate::_q_handleButtonClicked()
+{
+ Q_Q(QDialogButtonBox);
+ if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) {
+ emit q->clicked(button);
+
+ switch (q->buttonRole(button)) {
+ case AcceptRole:
+ case YesRole:
+ emit q->accepted();
+ break;
+ case RejectRole:
+ case NoRole:
+ emit q->rejected();
+ break;
+ case HelpRole:
+ emit q->helpRequested();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void QDialogButtonBoxPrivate::_q_handleButtonDestroyed()
+{
+ Q_Q(QDialogButtonBox);
+ if (QObject *object = q->sender()) {
+ QBoolBlocker skippy(internalRemove);
+ q->removeButton(static_cast<QAbstractButton *>(object));
+ }
+}
+
+/*!
+ \property QDialogButtonBox::centerButtons
+ \brief whether the buttons in the button box are centered
+
+ By default, this property is false. This behavior is appopriate
+ for most types of dialogs. A notable exception is message boxes
+ on most platforms (e.g. Windows), where the button box is
+ centered horizontally.
+
+ \sa QMessageBox
+*/
+void QDialogButtonBox::setCenterButtons(bool center)
+{
+ Q_D(QDialogButtonBox);
+ if (d->center != center) {
+ d->center = center;
+ d->resetLayout();
+ }
+}
+
+bool QDialogButtonBox::centerButtons() const
+{
+ Q_D(const QDialogButtonBox);
+ return d->center;
+}
+
+/*!
+ \reimp
+*/
+void QDialogButtonBox::changeEvent(QEvent *event)
+{
+ typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash;
+
+ Q_D(QDialogButtonBox);
+ switch (event->type()) {
+ case QEvent::StyleChange: // Propagate style
+ if (!d->standardButtonHash.empty()) {
+ QStyle *newStyle = style();
+ const StandardButtonHash::iterator end = d->standardButtonHash.end();
+ for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it)
+ it.key()->setStyle(newStyle);
+ }
+ // fallthrough intended
+#ifdef Q_WS_MAC
+ case QEvent::MacSizeChange:
+#endif
+ d->resetLayout();
+ QWidget::changeEvent(event);
+ break;
+ default:
+ QWidget::changeEvent(event);
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QDialogButtonBox::event(QEvent *event)
+{
+ Q_D(QDialogButtonBox);
+ if (event->type() == QEvent::Show) {
+ QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole];
+ QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0));
+ bool hasDefault = false;
+ QWidget *dialog = 0;
+ QWidget *p = this;
+ while (p && !p->isWindow()) {
+ p = p->parentWidget();
+ if ((dialog = qobject_cast<QDialog *>(p)))
+ break;
+ }
+
+ foreach (QPushButton *pb, (dialog ? dialog : this)->findChildren<QPushButton *>()) {
+ if (pb->isDefault() && pb != firstAcceptButton) {
+ hasDefault = true;
+ break;
+ }
+ }
+ if (!hasDefault && firstAcceptButton)
+ firstAcceptButton->setDefault(true);
+#ifdef QT_SOFTKEYS_ENABLED
+ if (dialog)
+ setFixedSize(0,0);
+#endif
+ }else if (event->type() == QEvent::LanguageChange) {
+ d->retranslateStrings();
+ }
+#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
+ else if (event->type() == QEvent::ParentChange) {
+ QWidget *dialog = 0;
+ QWidget *p = this;
+ while (p && !p->isWindow()) {
+ p = p->parentWidget();
+ if ((dialog = qobject_cast<QDialog *>(p)))
+ break;
+ }
+
+ // If the parent changes, then move the softkeys
+ for (QHash<QAbstractButton *, QAction *>::const_iterator it = d->softKeyActions.constBegin();
+ it != d->softKeyActions.constEnd(); ++it) {
+ QAction *current = it.value();
+ QList<QWidget *> widgets = current->associatedWidgets();
+ foreach (QWidget *w, widgets)
+ w->removeAction(current);
+ if (dialog)
+ dialog->addAction(current);
+ else
+ addAction(current);
+ }
+ }
+#endif
+
+ return QWidget::event(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdialogbuttonbox.cpp"
diff --git a/src/widgets/widgets/qdialogbuttonbox.h b/src/widgets/widgets/qdialogbuttonbox.h
new file mode 100644
index 0000000000..0a6e231e3f
--- /dev/null
+++ b/src/widgets/widgets/qdialogbuttonbox.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIALOGBUTTONBOX_H
+#define QDIALOGBUTTONBOX_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QAbstractButton;
+class QPushButton;
+class QDialogButtonBoxPrivate;
+
+class Q_WIDGETS_EXPORT QDialogButtonBox : public QWidget
+{
+ Q_OBJECT
+ Q_FLAGS(StandardButtons)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons)
+ Q_PROPERTY(bool centerButtons READ centerButtons WRITE setCenterButtons)
+
+public:
+ enum ButtonRole {
+ // keep this in sync with QMessageBox::ButtonRole
+ InvalidRole = -1,
+ AcceptRole,
+ RejectRole,
+ DestructiveRole,
+ ActionRole,
+ HelpRole,
+ YesRole,
+ NoRole,
+ ResetRole,
+ ApplyRole,
+
+ NRoles
+ };
+
+ enum StandardButton {
+ // keep this in sync with QMessageBox::StandardButton
+ NoButton = 0x00000000,
+ Ok = 0x00000400,
+ Save = 0x00000800,
+ SaveAll = 0x00001000,
+ Open = 0x00002000,
+ Yes = 0x00004000,
+ YesToAll = 0x00008000,
+ No = 0x00010000,
+ NoToAll = 0x00020000,
+ Abort = 0x00040000,
+ Retry = 0x00080000,
+ Ignore = 0x00100000,
+ Close = 0x00200000,
+ Cancel = 0x00400000,
+ Discard = 0x00800000,
+ Help = 0x01000000,
+ Apply = 0x02000000,
+ Reset = 0x04000000,
+ RestoreDefaults = 0x08000000,
+
+#ifndef Q_MOC_RUN
+ FirstButton = Ok,
+ LastButton = RestoreDefaults
+#endif
+ };
+
+ Q_DECLARE_FLAGS(StandardButtons, StandardButton)
+
+ enum ButtonLayout {
+ WinLayout,
+ MacLayout,
+ KdeLayout,
+ GnomeLayout
+ };
+
+ QDialogButtonBox(QWidget *parent = 0);
+ QDialogButtonBox(Qt::Orientation orientation, QWidget *parent = 0);
+ QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation = Qt::Horizontal,
+ QWidget *parent = 0);
+ ~QDialogButtonBox();
+
+ void setOrientation(Qt::Orientation orientation);
+ Qt::Orientation orientation() const;
+
+ void addButton(QAbstractButton *button, ButtonRole role);
+ QPushButton *addButton(const QString &text, ButtonRole role);
+ QPushButton *addButton(StandardButton button);
+ void removeButton(QAbstractButton *button);
+ void clear();
+
+ QList<QAbstractButton *> buttons() const;
+ ButtonRole buttonRole(QAbstractButton *button) const;
+
+ void setStandardButtons(StandardButtons buttons);
+ StandardButtons standardButtons() const;
+ StandardButton standardButton(QAbstractButton *button) const;
+ QPushButton *button(StandardButton which) const;
+
+ void setCenterButtons(bool center);
+ bool centerButtons() const;
+
+Q_SIGNALS:
+ void clicked(QAbstractButton *button);
+ void accepted();
+ void helpRequested();
+ void rejected();
+
+protected:
+ void changeEvent(QEvent *event);
+ bool event(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QDialogButtonBox)
+ Q_DECLARE_PRIVATE(QDialogButtonBox)
+ Q_PRIVATE_SLOT(d_func(), void _q_handleButtonClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_handleButtonDestroyed())
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDialogButtonBox::StandardButtons)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDIALOGBUTTONBOX_H
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
new file mode 100644
index 0000000000..aa627ef4f8
--- /dev/null
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -0,0 +1,3329 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtWidgets/qapplication.h"
+#include "QtWidgets/qwidget.h"
+#include "QtWidgets/qtabbar.h"
+#include "QtWidgets/qstyle.h"
+#include "QtWidgets/qdesktopwidget.h"
+#include "QtCore/qvariant.h"
+#include "qdockarealayout_p.h"
+#include "qdockwidget.h"
+#include "qmainwindow.h"
+#include "qwidgetanimator_p.h"
+#include "qmainwindowlayout_p.h"
+#include "qdockwidget_p.h"
+#include <private/qlayoutengine_p.h>
+
+#include <qpainter.h>
+#include <qstyleoption.h>
+
+#ifndef QT_NO_DOCKWIDGET
+
+QT_BEGIN_NAMESPACE
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+enum { StateFlagVisible = 1, StateFlagFloating = 2 };
+
+/******************************************************************************
+** QPlaceHolderItem
+*/
+
+QPlaceHolderItem::QPlaceHolderItem(QWidget *w)
+{
+ objectName = w->objectName();
+ hidden = w->isHidden();
+ window = w->isWindow();
+ if (window)
+ topLevelRect = w->geometry();
+}
+
+/******************************************************************************
+** QDockAreaLayoutItem
+*/
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QLayoutItem *_widgetItem)
+ : widgetItem(_widgetItem), subinfo(0), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo)
+ : widgetItem(0), subinfo(_subinfo), placeHolderItem(0), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem)
+ : widgetItem(0), subinfo(0), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags)
+{
+}
+
+QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other)
+ : widgetItem(other.widgetItem), subinfo(0), placeHolderItem(0), pos(other.pos),
+ size(other.size), flags(other.flags)
+{
+ if (other.subinfo != 0)
+ subinfo = new QDockAreaLayoutInfo(*other.subinfo);
+ else if (other.placeHolderItem != 0)
+ placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
+}
+
+QDockAreaLayoutItem::~QDockAreaLayoutItem()
+{
+ delete subinfo;
+ delete placeHolderItem;
+}
+
+bool QDockAreaLayoutItem::skip() const
+{
+ if (placeHolderItem != 0)
+ return true;
+
+ if (flags & GapItem)
+ return false;
+
+ if (widgetItem != 0)
+ return widgetItem->isEmpty();
+
+ if (subinfo != 0) {
+ for (int i = 0; i < subinfo->item_list.count(); ++i) {
+ if (!subinfo->item_list.at(i).skip())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QSize QDockAreaLayoutItem::minimumSize() const
+{
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->minimumSize() + QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->minimumSize();
+ return QSize(0, 0);
+}
+
+QSize QDockAreaLayoutItem::maximumSize() const
+{
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->maximumSize()+ QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->maximumSize();
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+}
+
+bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const
+{
+ return perp(o, minimumSize()) == perp(o, maximumSize());
+}
+
+bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const
+{
+ if ((flags & GapItem) || placeHolderItem != 0)
+ return false;
+ if (widgetItem != 0)
+ return ((widgetItem->expandingDirections() & o) == o);
+ if (subinfo != 0)
+ return subinfo->expansive(o);
+ return false;
+}
+
+QSize QDockAreaLayoutItem::sizeHint() const
+{
+ if (placeHolderItem != 0)
+ return QSize(0, 0);
+ if (widgetItem != 0) {
+ int left, top, right, bottom;
+ widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
+ return widgetItem->sizeHint() + QSize(left+right, top+bottom);
+ }
+ if (subinfo != 0)
+ return subinfo->sizeHint();
+ return QSize(-1, -1);
+}
+
+QDockAreaLayoutItem
+ &QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other)
+{
+ widgetItem = other.widgetItem;
+ if (other.subinfo == 0)
+ subinfo = 0;
+ else
+ subinfo = new QDockAreaLayoutInfo(*other.subinfo);
+
+ delete placeHolderItem;
+ if (other.placeHolderItem == 0)
+ placeHolderItem = 0;
+ else
+ placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem);
+
+ pos = other.pos;
+ size = other.size;
+ flags = other.flags;
+
+ return *this;
+}
+
+/******************************************************************************
+** QDockAreaLayoutInfo
+*/
+
+#ifndef QT_NO_TABBAR
+static quintptr tabId(const QDockAreaLayoutItem &item)
+{
+ if (item.widgetItem == 0)
+ return 0;
+ return reinterpret_cast<quintptr>(item.widgetItem->widget());
+}
+#endif
+
+static const int zero = 0;
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo()
+ : sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0)
+#ifndef QT_NO_TABBAR
+ , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth)
+#endif
+{
+}
+
+QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos,
+ Qt::Orientation _o, int tbshape,
+ QMainWindow *window)
+ : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window)
+#ifndef QT_NO_TABBAR
+ , tabbed(false), tabBar(0), tabBarShape(static_cast<QTabBar::Shape>(tbshape))
+#endif
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(tbshape);
+#endif
+}
+
+QSize QDockAreaLayoutInfo::size() const
+{
+ return isEmpty() ? QSize(0, 0) : rect.size();
+}
+
+void QDockAreaLayoutInfo::clear()
+{
+ item_list.clear();
+ rect = QRect();
+#ifndef QT_NO_TABBAR
+ tabbed = false;
+ tabBar = 0;
+#endif
+}
+
+bool QDockAreaLayoutInfo::isEmpty() const
+{
+ return next(-1) == -1;
+}
+
+QSize QDockAreaLayoutInfo::minimumSize() const
+{
+ if (isEmpty())
+ return QSize(0, 0);
+
+ int a = 0, b = 0;
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ QSize min_size = item.minimumSize();
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMax(a, pick(o, min_size));
+ } else
+#endif
+ {
+ if (!first)
+ a += *sep;
+ a += pick(o, min_size);
+ }
+ b = qMax(b, perp(o, min_size));
+
+ first = false;
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ QSize tbm = tabBarMinimumSize();
+ if (!tbm.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularSouth:
+ result.rheight() += tbm.height();
+ result.rwidth() = qMax(tbm.width(), result.width());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ result.rheight() = qMax(tbm.height(), result.height());
+ result.rwidth() += tbm.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+QSize QDockAreaLayoutInfo::maximumSize() const
+{
+ if (isEmpty())
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+
+ int a = 0, b = QWIDGETSIZE_MAX;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ a = QWIDGETSIZE_MAX;
+#endif
+
+ int min_perp = 0;
+
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ QSize max_size = item.maximumSize();
+ min_perp = qMax(min_perp, perp(o, item.minimumSize()));
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMin(a, pick(o, max_size));
+ } else
+#endif
+ {
+ if (!first)
+ a += *sep;
+ a += pick(o, max_size);
+ }
+ b = qMin(b, perp(o, max_size));
+
+ a = qMin(a, int(QWIDGETSIZE_MAX));
+ b = qMin(b, int(QWIDGETSIZE_MAX));
+
+ first = false;
+ }
+
+ b = qMax(b, min_perp);
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ QSize tbh = tabBarSizeHint();
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ result.rheight() += tbh.height();
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ result.rwidth() += tbh.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+QSize QDockAreaLayoutInfo::sizeHint() const
+{
+ if (isEmpty())
+ return QSize(0, 0);
+
+ int a = 0, b = 0;
+ int min_perp = 0;
+ int max_perp = QWIDGETSIZE_MAX;
+ const QDockAreaLayoutItem *previous = 0;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+
+ QSize size_hint = item.sizeHint();
+ min_perp = qMax(min_perp, perp(o, item.minimumSize()));
+ max_perp = qMin(max_perp, perp(o, item.maximumSize()));
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ a = qMax(a, gap ? item.size : pick(o, size_hint));
+ } else
+#endif
+ {
+ if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem)
+ && !previous->hasFixedSize(o)) {
+ a += *sep;
+ }
+ a += gap ? item.size : pick(o, size_hint);
+ }
+ b = qMax(b, perp(o, size_hint));
+
+ previous = &item;
+ }
+
+ max_perp = qMax(max_perp, min_perp);
+ b = qMax(b, min_perp);
+ b = qMin(b, max_perp);
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ QSize tbh = tabBarSizeHint();
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularSouth:
+ result.rheight() += tbh.height();
+ result.rwidth() = qMax(tbh.width(), result.width());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ result.rheight() = qMax(tbh.height(), result.height());
+ result.rwidth() += tbh.width();
+ break;
+ default:
+ break;
+ }
+ }
+#endif // QT_NO_TABBAR
+
+ return result;
+}
+
+bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ if (item_list.at(i).expansive(o))
+ return true;
+ }
+ return false;
+}
+
+/* QDockAreaLayoutInfo::maximumSize() doesn't return the real max size. For example,
+ if the layout is empty, it returns QWIDGETSIZE_MAX. This is so that empty dock areas
+ don't constrain the size of the QMainWindow, but sometimes we really need to know the
+ maximum size. Also, these functions take into account widgets that want to keep their
+ size (f.ex. when they are hidden and then shown, they should not change size).
+*/
+
+static int realMinSize(const QDockAreaLayoutInfo &info)
+{
+ int result = 0;
+ bool first = true;
+ for (int i = 0; i < info.item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = info.item_list.at(i);
+ if (item.skip())
+ continue;
+
+ int min = 0;
+ if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
+ min = item.size;
+ else
+ min = pick(info.o, item.minimumSize());
+
+ if (!first)
+ result += *info.sep;
+ result += min;
+
+ first = false;
+ }
+
+ return result;
+}
+
+static int realMaxSize(const QDockAreaLayoutInfo &info)
+{
+ int result = 0;
+ bool first = true;
+ for (int i = 0; i < info.item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = info.item_list.at(i);
+ if (item.skip())
+ continue;
+
+ int max = 0;
+ if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1)
+ max = item.size;
+ else
+ max = pick(info.o, item.maximumSize());
+
+ if (!first)
+ result += *info.sep;
+ result += max;
+
+ if (result >= QWIDGETSIZE_MAX)
+ return QWIDGETSIZE_MAX;
+
+ first = false;
+ }
+
+ return result;
+}
+
+void QDockAreaLayoutInfo::fitItems()
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ return;
+ }
+#endif
+
+ QVector<QLayoutStruct> layout_struct_list(item_list.size()*2);
+ int j = 0;
+
+ int size = pick(o, rect.size());
+ int min_size = realMinSize(*this);
+ int max_size = realMaxSize(*this);
+ int last_index = -1;
+
+ const QDockAreaLayoutItem *previous = 0;
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+ if (previous && !gap) {
+ if (!(previous->flags & QDockAreaLayoutItem::GapItem)) {
+ QLayoutStruct &ls = layout_struct_list[j++];
+ ls.init();
+ ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : *sep;
+ ls.empty = false;
+ }
+ }
+
+ if (item.flags & QDockAreaLayoutItem::KeepSize) {
+ // Check if the item can keep its size, without violating size constraints
+ // of other items.
+
+ if (size < min_size) {
+ // There is too little space to keep this widget's size
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ min_size -= item.size;
+ min_size += pick(o, item.minimumSize());
+ min_size = qMax(0, min_size);
+ } else if (size > max_size) {
+ // There is too much space to keep this widget's size
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ max_size -= item.size;
+ max_size += pick(o, item.maximumSize());
+ max_size = qMin<int>(QWIDGETSIZE_MAX, max_size);
+ }
+ }
+
+ last_index = j;
+ QLayoutStruct &ls = layout_struct_list[j++];
+ ls.init();
+ ls.empty = false;
+ if (item.flags & QDockAreaLayoutItem::KeepSize) {
+ ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
+ ls.expansive = false;
+ ls.stretch = 0;
+ } else {
+ ls.maximumSize = pick(o, item.maximumSize());
+ ls.expansive = item.expansive(o);
+ ls.minimumSize = pick(o, item.minimumSize());
+ ls.sizeHint = item.size == -1 ? pick(o, item.sizeHint()) : item.size;
+ ls.stretch = ls.expansive ? ls.sizeHint : 0;
+ }
+
+ item.flags &= ~QDockAreaLayoutItem::KeepSize;
+ previous = &item;
+ }
+ layout_struct_list.resize(j);
+
+ // If there is more space than the widgets can take (due to maximum size constraints),
+ // we detect it here and stretch the last widget to take up the rest of the space.
+ if (size > max_size && last_index != -1) {
+ layout_struct_list[last_index].maximumSize = QWIDGETSIZE_MAX;
+ layout_struct_list[last_index].expansive = true;
+ }
+
+ qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0);
+
+ j = 0;
+ bool prev_gap = false;
+ bool first = true;
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+
+ bool gap = item.flags & QDockAreaLayoutItem::GapItem;
+ if (!first && !gap && !prev_gap)
+ ++j;
+
+ const QLayoutStruct &ls = layout_struct_list.at(j++);
+ item.size = ls.size;
+ item.pos = ls.pos;
+
+ if (item.subinfo != 0) {
+ item.subinfo->rect = itemRect(i);
+ item.subinfo->fitItems();
+ }
+
+ prev_gap = gap;
+ first = false;
+ }
+}
+
+static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos,
+ Qt::Orientation o,
+ bool nestingEnabled,
+ QDockAreaLayoutInfo::TabMode tabMode)
+{
+ if (tabMode == QDockAreaLayoutInfo::ForceTabs)
+ return QInternal::DockCount;
+
+ QPoint pos = _pos - rect.topLeft();
+
+ int x = pos.x();
+ int y = pos.y();
+ int w = rect.width();
+ int h = rect.height();
+
+ if (tabMode != QDockAreaLayoutInfo::NoTabs) {
+ // is it in the center?
+ if (nestingEnabled) {
+ /* 2/3
+ +--------------+
+ | |
+ | CCCCCCCC |
+ 2/3 | CCCCCCCC |
+ | CCCCCCCC |
+ | |
+ +--------------+ */
+
+ QRect center(w/6, h/6, 2*w/3, 2*h/3);
+ if (center.contains(pos))
+ return QInternal::DockCount;
+ } else if (o == Qt::Horizontal) {
+ /* 2/3
+ +--------------+
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ | CCCCCCCC |
+ +--------------+ */
+
+ if (x > w/6 && x < w*5/6)
+ return QInternal::DockCount;
+ } else {
+ /*
+ +--------------+
+ | |
+ 2/3 |CCCCCCCCCCCCCC|
+ |CCCCCCCCCCCCCC|
+ | |
+ +--------------+ */
+ if (y > h/6 && y < 5*h/6)
+ return QInternal::DockCount;
+ }
+ }
+
+ // not in the center. which edge?
+ if (nestingEnabled) {
+ if (o == Qt::Horizontal) {
+ /* 1/3 1/3 1/3
+ +------------+ (we've already ruled out the center)
+ |LLLLTTTTRRRR|
+ |LLLLTTTTRRRR|
+ |LLLLBBBBRRRR|
+ |LLLLBBBBRRRR|
+ +------------+ */
+
+ if (x < w/3)
+ return QInternal::LeftDock;
+ if (x > 2*w/3)
+ return QInternal::RightDock;
+ if (y < h/2)
+ return QInternal::TopDock;
+ return QInternal::BottomDock;
+ } else {
+ /* +------------+ (we've already ruled out the center)
+ 1/3 |TTTTTTTTTTTT|
+ |LLLLLLRRRRRR|
+ 1/3 |LLLLLLRRRRRR|
+ 1/3 |BBBBBBBBBBBB|
+ +------------+ */
+
+ if (y < h/3)
+ return QInternal::TopDock;
+ if (y > 2*h/3)
+ return QInternal::BottomDock;
+ if (x < w/2)
+ return QInternal::LeftDock;
+ return QInternal::RightDock;
+ }
+ } else {
+ if (o == Qt::Horizontal) {
+ return x < w/2
+ ? QInternal::LeftDock
+ : QInternal::RightDock;
+ } else {
+ return y < h/2
+ ? QInternal::TopDock
+ : QInternal::BottomDock;
+ }
+ }
+}
+
+QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos,
+ bool nestingEnabled, TabMode tabMode) const
+{
+ QList<int> result;
+ QRect item_rect;
+ int item_index = 0;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ item_rect = tabContentRect();
+ } else
+#endif
+ {
+ int pos = pick(o, _pos);
+
+ int last = -1;
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+ last = i;
+
+ if (item.pos + item.size < pos)
+ continue;
+
+ if (item.subinfo != 0
+#ifndef QT_NO_TABBAR
+ && !item.subinfo->tabbed
+#endif
+ ) {
+ result = item.subinfo->gapIndex(_pos, nestingEnabled,
+ tabMode);
+ result.prepend(i);
+ return result;
+ }
+
+ item_rect = itemRect(i);
+ item_index = i;
+ break;
+ }
+
+ if (item_rect.isNull()) {
+ result.append(last + 1);
+ return result;
+ }
+ }
+
+ Q_ASSERT(!item_rect.isNull());
+
+ QInternal::DockPosition dock_pos
+ = dockPosHelper(item_rect, _pos, o, nestingEnabled, tabMode);
+
+ switch (dock_pos) {
+ case QInternal::LeftDock:
+ if (o == Qt::Horizontal)
+ result << item_index;
+ else
+ result << item_index << 0; // this subinfo doesn't exist yet, but insertGap()
+ // handles this by inserting it
+ break;
+ case QInternal::RightDock:
+ if (o == Qt::Horizontal)
+ result << item_index + 1;
+ else
+ result << item_index << 1;
+ break;
+ case QInternal::TopDock:
+ if (o == Qt::Horizontal)
+ result << item_index << 0;
+ else
+ result << item_index;
+ break;
+ case QInternal::BottomDock:
+ if (o == Qt::Horizontal)
+ result << item_index << 1;
+ else
+ result << item_index + 1;
+ break;
+ case QInternal::DockCount:
+ result << (-item_index - 1) << 0; // negative item_index means "on top of"
+ // -item_index - 1, insertGap()
+ // will insert a tabbed subinfo
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static inline int shrink(QLayoutStruct &ls, int delta)
+{
+ if (ls.empty)
+ return 0;
+ int old_size = ls.size;
+ ls.size = qMax(ls.size - delta, ls.minimumSize);
+ return old_size - ls.size;
+}
+
+static inline int grow(QLayoutStruct &ls, int delta)
+{
+ if (ls.empty)
+ return 0;
+ int old_size = ls.size;
+ ls.size = qMin(ls.size + delta, ls.maximumSize);
+ return ls.size - old_size;
+}
+
+static int separatorMoveHelper(QVector<QLayoutStruct> &list, int index, int delta, int sep)
+{
+ // adjust sizes
+ int pos = -1;
+ for (int i = 0; i < list.size(); ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (!ls.empty) {
+ pos = ls.pos;
+ break;
+ }
+ }
+ if (pos == -1)
+ return 0;
+
+ if (delta > 0) {
+ int growlimit = 0;
+ for (int i = 0; i<=index; ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (ls.empty)
+ continue;
+ if (ls.maximumSize == QLAYOUTSIZE_MAX) {
+ growlimit = QLAYOUTSIZE_MAX;
+ break;
+ }
+ growlimit += ls.maximumSize - ls.size;
+ }
+ if (delta > growlimit)
+ delta = growlimit;
+
+ int d = 0;
+ for (int i = index + 1; d < delta && i < list.count(); ++i)
+ d += shrink(list[i], delta - d);
+ delta = d;
+ d = 0;
+ for (int i = index; d < delta && i >= 0; --i)
+ d += grow(list[i], delta - d);
+ } else if (delta < 0) {
+ int growlimit = 0;
+ for (int i = index + 1; i < list.count(); ++i) {
+ const QLayoutStruct &ls = list.at(i);
+ if (ls.empty)
+ continue;
+ if (ls.maximumSize == QLAYOUTSIZE_MAX) {
+ growlimit = QLAYOUTSIZE_MAX;
+ break;
+ }
+ growlimit += ls.maximumSize - ls.size;
+ }
+ if (-delta > growlimit)
+ delta = -growlimit;
+
+ int d = 0;
+ for (int i = index; d < -delta && i >= 0; --i)
+ d += shrink(list[i], -delta - d);
+ delta = -d;
+ d = 0;
+ for (int i = index + 1; d < -delta && i < list.count(); ++i)
+ d += grow(list[i], -delta - d);
+ }
+
+ // adjust positions
+ bool first = true;
+ for (int i = 0; i < list.size(); ++i) {
+ QLayoutStruct &ls = list[i];
+ if (ls.empty) {
+ ls.pos = pos + (first ? 0 : sep);
+ continue;
+ }
+ if (!first)
+ pos += sep;
+ ls.pos = pos;
+ pos += ls.size;
+ first = false;
+ }
+
+ return delta;
+}
+
+int QDockAreaLayoutInfo::separatorMove(int index, int delta)
+{
+#ifndef QT_NO_TABBAR
+ Q_ASSERT(!tabbed);
+#endif
+
+ QVector<QLayoutStruct> list(item_list.size());
+ for (int i = 0; i < list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ QLayoutStruct &ls = list[i];
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ if (item.skip()) {
+ ls.empty = true;
+ } else {
+ const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
+ ls.empty = false;
+ ls.pos = item.pos;
+ ls.size = item.size + separatorSpace;
+ ls.minimumSize = pick(o, item.minimumSize()) + separatorSpace;
+ ls.maximumSize = pick(o, item.maximumSize()) + separatorSpace;
+
+ }
+ }
+
+ //the separator space has been added to the size, so we pass 0 as a parameter
+ delta = separatorMoveHelper(list, index, delta, 0 /*separator*/);
+
+ for (int i = 0; i < list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.skip())
+ continue;
+ QLayoutStruct &ls = list[i];
+ const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep;
+ item.size = ls.size - separatorSpace;
+ item.pos = ls.pos;
+ if (item.subinfo != 0) {
+ item.subinfo->rect = itemRect(i);
+ item.subinfo->fitItems();
+ }
+ }
+
+ return delta;
+}
+
+void QDockAreaLayoutInfo::unnest(int index)
+{
+ QDockAreaLayoutItem &item = item_list[index];
+ if (item.subinfo == 0)
+ return;
+ if (item.subinfo->item_list.count() > 1)
+ return;
+
+ if (item.subinfo->item_list.count() == 0) {
+ item_list.removeAt(index);
+ } else if (item.subinfo->item_list.count() == 1) {
+ QDockAreaLayoutItem &child = item.subinfo->item_list.first();
+ if (child.widgetItem != 0) {
+ item.widgetItem = child.widgetItem;
+ delete item.subinfo;
+ item.subinfo = 0;
+ } else if (child.subinfo != 0) {
+ QDockAreaLayoutInfo *tmp = item.subinfo;
+ item.subinfo = child.subinfo;
+ child.subinfo = 0;
+ tmp->item_list.clear();
+ delete tmp;
+ }
+ }
+}
+
+void QDockAreaLayoutInfo::remove(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ if (path.count() > 1) {
+ const int index = path.first();
+ QDockAreaLayoutItem &item = item_list[index];
+ Q_ASSERT(item.subinfo != 0);
+ item.subinfo->remove(path.mid(1));
+ unnest(index);
+ } else {
+ int index = path.first();
+ item_list.removeAt(index);
+ }
+}
+
+QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ int index = path.first();
+ if (index < 0)
+ index = -index - 1;
+
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->plug(path.mid(1));
+ }
+
+ QDockAreaLayoutItem &item = item_list[index];
+
+ Q_ASSERT(item.widgetItem != 0);
+ Q_ASSERT(item.flags & QDockAreaLayoutItem::GapItem);
+ item.flags &= ~QDockAreaLayoutItem::GapItem;
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ } else
+#endif
+ {
+ int prev = this->prev(index);
+ int next = this->next(index);
+
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ item.pos += *sep;
+ item.size -= *sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ item.size -= *sep;
+
+ QPoint pos;
+ rpick(o, pos) = item.pos;
+ rperp(o, pos) = perp(o, rect.topLeft());
+ QSize s;
+ rpick(o, s) = item.size;
+ rperp(o, s) = perp(o, rect.size());
+ result = QRect(pos, s);
+ }
+
+ return item.widgetItem;
+}
+
+QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->unplug(path.mid(1));
+ }
+
+ QDockAreaLayoutItem &item = item_list[index];
+ int prev = this->prev(index);
+ int next = this->next(index);
+
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ item.flags |= QDockAreaLayoutItem::GapItem;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ } else
+#endif
+ {
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ item.pos -= *sep;
+ item.size += *sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ item.size += *sep;
+ }
+
+ return item.widgetItem;
+}
+
+#ifndef QT_NO_TABBAR
+
+quintptr QDockAreaLayoutInfo::currentTabId() const
+{
+ if (!tabbed || tabBar == 0)
+ return 0;
+
+ int index = tabBar->currentIndex();
+ if (index == -1)
+ return 0;
+
+ return qvariant_cast<quintptr>(tabBar->tabData(index));
+}
+
+void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
+{
+ setCurrentTabId(reinterpret_cast<quintptr>(widget));
+}
+
+void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
+{
+ if (!tabbed || tabBar == 0)
+ return;
+
+ for (int i = 0; i < tabBar->count(); ++i) {
+ if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) {
+ tabBar->setCurrentIndex(i);
+ return;
+ }
+ }
+}
+
+#endif // QT_NO_TABBAR
+
+static QRect dockedGeometry(QWidget *widget)
+{
+ int titleHeight = 0;
+
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(widget->layout());
+ if(layout != 0 && layout->nativeWindowDeco())
+ titleHeight = layout->titleHeight();
+
+ QRect result = widget->geometry();
+ result.adjust(0, -titleHeight, 0, 0);
+ return result;
+}
+
+bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ bool insert_tabbed = false;
+ int index = path.first();
+ if (index < 0) {
+ insert_tabbed = true;
+ index = -index - 1;
+ }
+
+// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
+
+ if (path.count() > 1) {
+ QDockAreaLayoutItem &item = item_list[index];
+
+ if (item.subinfo == 0
+#ifndef QT_NO_TABBAR
+ || (item.subinfo->tabbed && !insert_tabbed)
+#endif
+ ) {
+
+ // this is not yet a nested layout - make it
+
+ QDockAreaLayoutInfo *subinfo = item.subinfo;
+ QLayoutItem *widgetItem = item.widgetItem;
+ QPlaceHolderItem *placeHolderItem = item.placeHolderItem;
+ QRect r = subinfo == 0 ? widgetItem ? dockedGeometry(widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect;
+
+ Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow);
+
+ //item become a new top-level
+ item.subinfo = new_info;
+ item.widgetItem = 0;
+ item.placeHolderItem = 0;
+
+ QDockAreaLayoutItem new_item
+ = widgetItem == 0
+ ? QDockAreaLayoutItem(subinfo)
+ : widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem);
+ new_item.size = pick(opposite, r.size());
+ new_item.pos = pick(opposite, r.topLeft());
+ new_info->item_list.append(new_item);
+#ifndef QT_NO_TABBAR
+ if (insert_tabbed) {
+ new_info->tabbed = true;
+ }
+#endif
+ }
+
+ return item.subinfo->insertGap(path.mid(1), dockWidgetItem);
+ }
+
+ // create the gap item
+ QDockAreaLayoutItem gap_item;
+ gap_item.flags |= QDockAreaLayoutItem::GapItem;
+ gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and
+ // sizeHint() will work
+#ifndef QT_NO_TABBAR
+ if (!tabbed)
+#endif
+ {
+ int prev = this->prev(index);
+ int next = this->next(index - 1);
+ // find out how much space we have in the layout
+ int space = 0;
+ if (isEmpty()) {
+ // I am an empty dock area, therefore I am a top-level dock area.
+ switch (dockPos) {
+ case QInternal::LeftDock:
+ case QInternal::RightDock:
+ if (o == Qt::Vertical) {
+ // the "size" is the height of the dock area (remember we are empty)
+ space = pick(Qt::Vertical, rect.size());
+ } else {
+ space = pick(Qt::Horizontal, dockWidgetItem->widget()->size());
+ }
+ break;
+ case QInternal::TopDock:
+ case QInternal::BottomDock:
+ default:
+ if (o == Qt::Horizontal) {
+ // the "size" is width of the dock area
+ space = pick(Qt::Horizontal, rect.size());
+ } else {
+ space = pick(Qt::Vertical, dockWidgetItem->widget()->size());
+ }
+ break;
+ }
+ } else {
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+ Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem));
+ space += item.size - pick(o, item.minimumSize());
+ }
+ }
+
+ // find the actual size of the gap
+ int gap_size = 0;
+ int sep_size = 0;
+ if (isEmpty()) {
+ gap_size = space;
+ sep_size = 0;
+ } else {
+ QRect r = dockedGeometry(dockWidgetItem->widget());
+ gap_size = pick(o, r.size());
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem))
+ sep_size += *sep;
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ sep_size += *sep;
+ }
+ if (gap_size + sep_size > space)
+ gap_size = pick(o, gap_item.minimumSize());
+ gap_item.size = gap_size + sep_size;
+ }
+
+ // finally, insert the gap
+ item_list.insert(index, gap_item);
+
+// dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString());
+
+ return true;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget)
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed && widget == tabBar)
+ return this;
+#endif
+
+ if (item.widgetItem != 0 && item.widgetItem->widget() == widget)
+ return this;
+
+ if (item.subinfo != 0) {
+ if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path)
+{
+ int index = path.first();
+ if (index < 0)
+ index = -index - 1;
+ if (index >= item_list.count())
+ return this;
+ if (path.count() == 1 || item_list[index].subinfo == 0)
+ return this;
+ return item_list[index].subinfo->info(path.mid(1));
+}
+
+QRect QDockAreaLayoutInfo::itemRect(int index) const
+{
+ const QDockAreaLayoutItem &item = item_list.at(index);
+
+ if (item.skip())
+ return QRect();
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ if (tabId(item) == currentTabId())
+ result = tabContentRect();
+ } else
+#endif
+ {
+ QPoint pos;
+ rpick(o, pos) = item.pos;
+ rperp(o, pos) = perp(o, rect.topLeft());
+ QSize s;
+ rpick(o, s) = item.size;
+ rperp(o, s) = perp(o, rect.size());
+ result = QRect(pos, s);
+ }
+
+ return result;
+}
+
+QRect QDockAreaLayoutInfo::itemRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->itemRect(path.mid(1));
+ }
+
+ return itemRect(index);
+}
+
+QRect QDockAreaLayoutInfo::separatorRect(int index) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return QRect();
+#endif
+
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ if (item.skip())
+ return QRect();
+
+ QPoint pos = rect.topLeft();
+ rpick(o, pos) = item.pos + item.size;
+ QSize s = rect.size();
+ rpick(o, s) = *sep;
+
+ return QRect(pos, s);
+}
+
+QRect QDockAreaLayoutInfo::separatorRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->separatorRect(path.mid(1));
+ }
+ return separatorRect(index);
+}
+
+QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return QList<int>();
+#endif
+
+ int pos = pick(o, _pos);
+
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem))
+ continue;
+
+ if (item.pos + item.size > pos) {
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->findSeparator(_pos);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ } else {
+ return QList<int>();
+ }
+ }
+ }
+
+ int next = this->next(i);
+ if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ continue;
+
+ QRect sepRect = separatorRect(i);
+ if (!sepRect.isNull() && *sep == 1)
+ sepRect.adjust(-2, -2, 2, 2);
+ //we also make sure we don't find a separator that's not there
+ if (sepRect.contains(_pos) && !item.hasFixedSize(o)) {
+ return QList<int>() << i;
+ }
+
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->indexOfPlaceHolder(objectName);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ continue;
+ }
+
+ if (item.placeHolderItem != 0 && item.placeHolderItem->objectName == objectName) {
+ QList<int> result;
+ result << i;
+ return result;
+ }
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget) const
+{
+ for (int i = 0; i < item_list.size(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.placeHolderItem != 0)
+ continue;
+
+ if (item.subinfo != 0) {
+ QList<int> result = item.subinfo->indexOf(widget);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ continue;
+ }
+
+ if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem->widget() == widget) {
+ QList<int> result;
+ result << i;
+ return result;
+ }
+ }
+
+ return QList<int>();
+}
+
+QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const
+{
+ QMainWindowLayout *result = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT(result != 0);
+ return result;
+}
+
+bool QDockAreaLayoutInfo::hasFixedSize() const
+{
+ return perp(o, minimumSize()) == perp(o, maximumSize());
+}
+
+
+void QDockAreaLayoutInfo::apply(bool animate)
+{
+ QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator;
+
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ QRect tab_rect;
+ QSize tbh = tabBarSizeHint();
+
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
+ rect.width(), tbh.height());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
+ tbh.width(), rect.height());
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ tab_rect = QRect(rect.left(), rect.top(),
+ tbh.width(), rect.height());
+ break;
+ default:
+ break;
+ }
+ }
+
+ widgetAnimator.animate(tabBar, tab_rect, animate);
+ }
+#endif // QT_NO_TABBAR
+
+ for (int i = 0; i < item_list.size(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+
+ if (item.flags & QDockAreaLayoutItem::GapItem)
+ continue;
+
+ if (item.subinfo != 0) {
+ item.subinfo->apply(animate);
+ continue;
+ }
+
+ if (item.skip())
+ continue;
+
+ Q_ASSERT(item.widgetItem);
+ QRect r = itemRect(i);
+ QWidget *w = item.widgetItem->widget();
+
+ QRect geo = w->geometry();
+ widgetAnimator.animate(w, r, animate);
+ if (!w->isHidden() && w->window()->isVisible()) {
+ QDockWidget *dw = qobject_cast<QDockWidget*>(w);
+ if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) {
+ dw->lower();
+ emit dw->visibilityChanged(false);
+ } else if (r.isValid()
+ && (geo.right() < 0 || geo.bottom() < 0)) {
+ emit dw->visibilityChanged(true);
+ }
+ }
+ }
+#ifndef QT_NO_TABBAR
+ if (*sep == 1)
+ updateSeparatorWidgets();
+#endif //QT_NO_TABBAR
+}
+
+static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
+{
+ QStyleOption opt(0);
+ opt.state = QStyle::State_None;
+ if (w->isEnabled())
+ opt.state |= QStyle::State_Enabled;
+ if (o != Qt::Horizontal)
+ opt.state |= QStyle::State_Horizontal;
+ if (mouse_over)
+ opt.state |= QStyle::State_MouseOver;
+ opt.rect = r;
+ opt.palette = w->palette();
+
+ w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w);
+}
+
+QRegion QDockAreaLayoutInfo::separatorRegion() const
+{
+ QRegion result;
+
+ if (isEmpty())
+ return result;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return result;
+#endif
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+
+ if (item.subinfo)
+ result |= item.subinfo->separatorRegion();
+
+ if (next == -1)
+ break;
+ result |= separatorRect(i);
+ }
+
+ return result;
+}
+
+void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget,
+ const QRegion &clip,
+ const QPoint &mouse) const
+{
+ if (isEmpty())
+ return;
+#ifndef QT_NO_TABBAR
+ if (tabbed)
+ return;
+#endif
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+ if ((item.flags & QDockAreaLayoutItem::GapItem)
+ || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
+ continue;
+
+ if (item.subinfo) {
+ if (clip.contains(item.subinfo->rect))
+ item.subinfo->paintSeparators(p, widget, clip, mouse);
+ }
+
+ if (next == -1)
+ break;
+ QRect r = separatorRect(i);
+ if (clip.contains(r) && !item.hasFixedSize(o))
+ paintSep(p, widget, r, o, r.contains(mouse));
+ }
+}
+
+int QDockAreaLayoutInfo::next(int index) const
+{
+ for (int i = index + 1; i < item_list.size(); ++i) {
+ if (!item_list.at(i).skip())
+ return i;
+ }
+ return -1;
+}
+
+int QDockAreaLayoutInfo::prev(int index) const
+{
+ for (int i = index - 1; i >= 0; --i) {
+ if (!item_list.at(i).skip())
+ return i;
+ }
+ return -1;
+}
+
+void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(index);
+ Q_UNUSED(dockWidgetItem);
+#else
+ if (tabbed) {
+ item_list.append(QDockAreaLayoutItem(dockWidgetItem));
+ updateTabBar();
+ setCurrentTab(dockWidgetItem->widget());
+ } else {
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow);
+ item_list[index].subinfo = new_info;
+ new_info->item_list.append(item_list.at(index).widgetItem);
+ item_list[index].widgetItem = 0;
+ new_info->item_list.append(dockWidgetItem);
+ new_info->tabbed = true;
+ new_info->updateTabBar();
+ new_info->setCurrentTab(dockWidgetItem->widget());
+ }
+#endif // QT_NO_TABBAR
+}
+
+void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation,
+ QLayoutItem *dockWidgetItem)
+{
+ if (orientation == o) {
+ item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem));
+ } else {
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutInfo *new_info
+ = new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow);
+ item_list[index].subinfo = new_info;
+ new_info->item_list.append(item_list.at(index).widgetItem);
+ item_list[index].widgetItem = 0;
+ new_info->item_list.append(dockWidgetItem);
+ }
+}
+
+QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ if (path.count() > 1) {
+ const QDockAreaLayoutItem &item = item_list[index];
+ Q_ASSERT(item.subinfo != 0);
+ return item.subinfo->item(path.mid(1));
+ }
+ return item_list[index];
+}
+
+QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.placeHolderItem != 0)
+ continue;
+ if (item.subinfo) {
+ if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
+ return ret;
+ } else if (item.widgetItem) {
+ if ((*x)++ == index)
+ return item.widgetItem;
+ }
+ }
+ return 0;
+}
+
+QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.placeHolderItem != 0)
+ continue;
+ else if (item.subinfo) {
+ if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
+ unnest(i);
+ return ret;
+ }
+ } else if (item.widgetItem) {
+ if ((*x)++ == index) {
+ item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget());
+ QLayoutItem *ret = item.widgetItem;
+ item.widgetItem = 0;
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+void QDockAreaLayoutInfo::deleteAllLayoutItems()
+{
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item= item_list[i];
+ if (item.subinfo) {
+ item.subinfo->deleteAllLayoutItems();
+ } else {
+ delete item.widgetItem;
+ item.widgetItem = 0;
+ }
+ }
+}
+
+void QDockAreaLayoutInfo::saveState(QDataStream &stream) const
+{
+#ifndef QT_NO_TABBAR
+ if (tabbed) {
+ stream << (uchar) TabMarker;
+
+ // write the index in item_list of the widget that's currently on top.
+ quintptr id = currentTabId();
+ int index = -1;
+ for (int i = 0; i < item_list.count(); ++i) {
+ if (tabId(item_list.at(i)) == id) {
+ index = i;
+ break;
+ }
+ }
+ stream << index;
+ } else
+#endif // QT_NO_TABBAR
+ {
+ stream << (uchar) SequenceMarker;
+ }
+
+ stream << (uchar) o << item_list.count();
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.widgetItem != 0) {
+ stream << (uchar) WidgetMarker;
+ QWidget *w = item.widgetItem->widget();
+ QString name = w->objectName();
+ if (name.isEmpty()) {
+ qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%s;",
+ w, qPrintable(w->windowTitle()));
+ }
+ stream << name;
+
+ uchar flags = 0;
+ if (!w->isHidden())
+ flags |= StateFlagVisible;
+ if (w->isWindow())
+ flags |= StateFlagFloating;
+ stream << flags;
+
+ if (w->isWindow()) {
+ stream << w->x() << w->y() << w->width() << w->height();
+ } else {
+ stream << item.pos << item.size << pick(o, item.minimumSize())
+ << pick(o, item.maximumSize());
+ }
+ } else if (item.placeHolderItem != 0) {
+ stream << (uchar) WidgetMarker;
+ stream << item.placeHolderItem->objectName;
+ uchar flags = 0;
+ if (!item.placeHolderItem->hidden)
+ flags |= StateFlagVisible;
+ if (item.placeHolderItem->window)
+ flags |= StateFlagFloating;
+ stream << flags;
+ if (item.placeHolderItem->window) {
+ QRect r = item.placeHolderItem->topLevelRect;
+ stream << r.x() << r.y() << r.width() << r.height();
+ } else {
+ stream << item.pos << item.size << (int)0 << (int)0;
+ }
+ } else if (item.subinfo != 0) {
+ stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize());
+ item.subinfo->saveState(stream);
+ }
+ }
+}
+
+static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
+{
+ switch (pos) {
+ case QInternal::LeftDock: return Qt::LeftDockWidgetArea;
+ case QInternal::RightDock: return Qt::RightDockWidgetArea;
+ case QInternal::TopDock: return Qt::TopDockWidgetArea;
+ case QInternal::BottomDock: return Qt::BottomDockWidgetArea;
+ default: break;
+ }
+ return Qt::NoDockWidgetArea;
+}
+
+static QRect constrainedRect(QRect rect, const QRect &desktop)
+{
+ if (desktop.isValid()) {
+ rect.setWidth(qMin(rect.width(), desktop.width()));
+ rect.setHeight(qMin(rect.height(), desktop.height()));
+ rect.moveLeft(qMax(rect.left(), desktop.left()));
+ rect.moveTop(qMax(rect.top(), desktop.top()));
+ rect.moveRight(qMin(rect.right(), desktop.right()));
+ rect.moveBottom(qMin(rect.bottom(), desktop.bottom()));
+ }
+
+ return rect;
+}
+
+bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing)
+{
+ uchar marker;
+ stream >> marker;
+ if (marker != TabMarker && marker != SequenceMarker)
+ return false;
+
+#ifndef QT_NO_TABBAR
+ tabbed = marker == TabMarker;
+
+ int index = -1;
+ if (tabbed)
+ stream >> index;
+#endif
+
+ uchar orientation;
+ stream >> orientation;
+ o = static_cast<Qt::Orientation>(orientation);
+
+ int cnt;
+ stream >> cnt;
+
+ for (int i = 0; i < cnt; ++i) {
+ uchar nextMarker;
+ stream >> nextMarker;
+ if (nextMarker == WidgetMarker) {
+ QString name;
+ uchar flags;
+ stream >> name >> flags;
+ if (name.isEmpty()) {
+ int dummy;
+ stream >> dummy >> dummy >> dummy >> dummy;
+ continue;
+ }
+
+ QDockWidget *widget = 0;
+ for (int j = 0; j < widgets.count(); ++j) {
+ if (widgets.at(j)->objectName() == name) {
+ widget = widgets.takeAt(j);
+ break;
+ }
+ }
+
+ if (widget == 0) {
+ QPlaceHolderItem *placeHolder = new QPlaceHolderItem;
+ QDockAreaLayoutItem item(placeHolder);
+
+ placeHolder->objectName = name;
+ placeHolder->window = flags & StateFlagFloating;
+ placeHolder->hidden = !(flags & StateFlagVisible);
+ if (placeHolder->window) {
+ int x, y, w, h;
+ stream >> x >> y >> w >> h;
+ placeHolder->topLevelRect = QRect(x, y, w, h);
+ } else {
+ int dummy;
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ }
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+ if (!testing)
+ item_list.append(item);
+ } else {
+ QDockAreaLayoutItem item(new QDockWidgetItem(widget));
+ if (flags & StateFlagFloating) {
+ bool drawer = false;
+#ifdef Q_WS_MAC // drawer support
+ extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
+ extern bool qt_mac_set_drawer_preferred_edge(QWidget *, Qt::DockWidgetArea); //qwidget_mac.cpp
+ drawer = qt_mac_is_macdrawer(widget);
+#endif
+
+ if (!testing) {
+ widget->hide();
+ if (!drawer)
+ widget->setFloating(true);
+ }
+
+ int x, y, w, h;
+ stream >> x >> y >> w >> h;
+
+#ifdef Q_WS_MAC // drawer support
+ if (drawer) {
+ mainWindow->window()->createWinId();
+ widget->window()->createWinId();
+ qt_mac_set_drawer_preferred_edge(widget, toDockWidgetArea(dockPos));
+ } else
+#endif
+ if (!testing) {
+ QRect r(x, y, w, h);
+ QDesktopWidget *desktop = QApplication::desktop();
+ if (desktop->isVirtualDesktop())
+ r = constrainedRect(r, desktop->screenGeometry(desktop->screenNumber(r.topLeft())));
+ else
+ r = constrainedRect(r, desktop->screenGeometry(widget));
+ widget->move(r.topLeft());
+ widget->resize(r.size());
+ }
+
+ if (!testing) {
+ widget->setVisible(flags & StateFlagVisible);
+ item_list.append(item);
+ }
+ } else {
+ int dummy;
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ if (!testing) {
+ item_list.append(item);
+ widget->setFloating(false);
+ widget->setVisible(flags & StateFlagVisible);
+ emit widget->dockLocationChanged(toDockWidgetArea(dockPos));
+ }
+ }
+ if (testing) {
+ //was it is not really added to the layout, we need to delete the object here
+ delete item.widgetItem;
+ }
+ }
+ } else if (nextMarker == SequenceMarker) {
+ int dummy;
+#ifdef QT_NO_TABBAR
+ const int tabBarShape = 0;
+#endif
+ QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o,
+ tabBarShape, mainWindow));
+ stream >> item.pos >> item.size >> dummy >> dummy;
+ //we need to make sure the element is in the list so the dock widget can eventually be docked correctly
+ if (!testing)
+ item_list.append(item);
+
+ //here we need to make sure we change the item in the item_list
+ QDockAreaLayoutItem &lastItem = testing ? item : item_list.last();
+
+ if (!lastItem.subinfo->restoreState(stream, widgets, testing))
+ return false;
+
+ } else {
+ return false;
+ }
+ }
+
+#ifndef QT_NO_TABBAR
+ if (!testing && tabbed && index >= 0 && index < item_list.count()) {
+ updateTabBar();
+ setCurrentTabId(tabId(item_list.at(index)));
+ }
+ if (!testing && *sep == 1)
+ updateSeparatorWidgets();
+#endif
+
+ return true;
+}
+
+#ifndef QT_NO_TABBAR
+void QDockAreaLayoutInfo::updateSeparatorWidgets() const
+{
+ if (tabbed) {
+ separatorWidgets.clear();
+ return;
+ }
+
+ int j = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+
+ if (item.skip())
+ continue;
+
+ int next = this->next(i);
+ if ((item.flags & QDockAreaLayoutItem::GapItem)
+ || (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)))
+ continue;
+
+ if (item.subinfo) {
+ item.subinfo->updateSeparatorWidgets();
+ }
+
+ if (next == -1)
+ break;
+
+ QWidget *sepWidget;
+ if (j < separatorWidgets.size() && separatorWidgets.at(j)) {
+ sepWidget = separatorWidgets.at(j);
+ } else {
+ sepWidget = mainWindowLayout()->getSeparatorWidget();
+ separatorWidgets.append(sepWidget);
+ }
+ j++;
+
+#ifndef QT_MAC_USE_COCOA
+ sepWidget->raise();
+#endif
+ QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
+ sepWidget->setGeometry(sepRect);
+ sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
+ sepWidget->show();
+ }
+
+ for (int k = j; k < separatorWidgets.size(); ++k) {
+ separatorWidgets[k]->hide();
+ }
+ separatorWidgets.resize(j);
+ Q_ASSERT(separatorWidgets.size() == j);
+}
+#endif //QT_NO_TABBAR
+
+#ifndef QT_NO_TABBAR
+//returns whether the tabbar is visible or not
+bool QDockAreaLayoutInfo::updateTabBar() const
+{
+ if (!tabbed)
+ return false;
+
+ QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
+
+ if (that->tabBar == 0) {
+ that->tabBar = mainWindowLayout()->getTabBar();
+ that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
+ that->tabBar->setDrawBase(true);
+ }
+
+ bool blocked = tabBar->blockSignals(true);
+ bool gap = false;
+
+ int tab_idx = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.skip())
+ continue;
+ if (item.flags & QDockAreaLayoutItem::GapItem) {
+ gap = true;
+ continue;
+ }
+ if (item.widgetItem == 0)
+ continue;
+
+ QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget());
+ QString title = dw->d_func()->fixedWindowTitle;
+ quintptr id = tabId(item);
+ if (tab_idx == tabBar->count()) {
+ tabBar->insertTab(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ tabBar->setTabData(tab_idx, id);
+ } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
+ if (tab_idx + 1 < tabBar->count()
+ && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id)
+ tabBar->removeTab(tab_idx);
+ else {
+ tabBar->insertTab(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ tabBar->setTabData(tab_idx, id);
+ }
+ }
+
+ if (title != tabBar->tabText(tab_idx)) {
+ tabBar->setTabText(tab_idx, title);
+#ifndef QT_NO_TOOLTIP
+ tabBar->setTabToolTip(tab_idx, title);
+#endif
+ }
+
+ ++tab_idx;
+ }
+
+ while (tab_idx < tabBar->count()) {
+ tabBar->removeTab(tab_idx);
+ }
+
+ tabBar->blockSignals(blocked);
+
+ //returns if the tabbar is visible or not
+ return ( (gap ? 1 : 0) + tabBar->count()) > 1;
+}
+
+void QDockAreaLayoutInfo::setTabBarShape(int shape)
+{
+ if (shape == tabBarShape)
+ return;
+ tabBarShape = shape;
+ if (tabBar != 0)
+ tabBar->setShape(static_cast<QTabBar::Shape>(shape));
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ QDockAreaLayoutItem &item = item_list[i];
+ if (item.subinfo != 0)
+ item.subinfo->setTabBarShape(shape);
+ }
+}
+
+QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
+{
+ if (!updateTabBar())
+ return QSize(0, 0);
+
+ return tabBar->minimumSizeHint();
+}
+
+QSize QDockAreaLayoutInfo::tabBarSizeHint() const
+{
+ if (!updateTabBar())
+ return QSize(0, 0);
+
+ return tabBar->sizeHint();
+}
+
+QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
+{
+ QSet<QTabBar*> result;
+
+ if (tabbed) {
+ updateTabBar();
+ result.insert(tabBar);
+ }
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.subinfo != 0)
+ result += item.subinfo->usedTabBars();
+ }
+
+ return result;
+}
+
+// returns a set of all used separator widgets for this dockarelayout info
+// and all subinfos
+QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const
+{
+ QSet<QWidget*> result;
+
+ for (int i = 0; i < separatorWidgets.count(); ++i)
+ result << separatorWidgets.at(i);
+
+ for (int i = 0; i < item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = item_list.at(i);
+ if (item.subinfo != 0)
+ result += item.subinfo->usedSeparatorWidgets();
+ }
+
+ return result;
+}
+
+QRect QDockAreaLayoutInfo::tabContentRect() const
+{
+ if (!tabbed)
+ return QRect();
+
+ QRect result = rect;
+ QSize tbh = tabBarSizeHint();
+
+ if (!tbh.isNull()) {
+ switch (tabBarShape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ result.adjust(0, tbh.height(), 0, 0);
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ result.adjust(0, 0, 0, -tbh.height());
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ result.adjust(0, 0, -tbh.width(), 0);
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ result.adjust(tbh.width(), 0, 0, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+}
+#endif // QT_NO_TABBAR
+
+/******************************************************************************
+** QDockAreaLayout
+*/
+
+QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true)
+{
+ mainWindow = win;
+ sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, win);
+#ifndef QT_NO_TABBAR
+ const int tabShape = QTabBar::RoundedSouth;
+#else
+ const int tabShape = 0;
+#endif
+ docks[QInternal::LeftDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::LeftDock, Qt::Vertical, tabShape, win);
+ docks[QInternal::RightDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::RightDock, Qt::Vertical, tabShape, win);
+ docks[QInternal::TopDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::TopDock, Qt::Horizontal, tabShape, win);
+ docks[QInternal::BottomDock]
+ = QDockAreaLayoutInfo(&sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win);
+ centralWidgetItem = 0;
+
+
+ corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
+ corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
+ corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
+ corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
+}
+
+bool QDockAreaLayout::isValid() const
+{
+ return rect.isValid();
+}
+
+void QDockAreaLayout::saveState(QDataStream &stream) const
+{
+ stream << (uchar) DockWidgetStateMarker;
+ int cnt = 0;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (!docks[i].item_list.isEmpty())
+ ++cnt;
+ }
+ stream << cnt;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (docks[i].item_list.isEmpty())
+ continue;
+ stream << i << docks[i].rect.size();
+ docks[i].saveState(stream);
+ }
+
+ stream << centralWidgetRect.size();
+
+ for (int i = 0; i < 4; ++i)
+ stream << static_cast<int>(corners[i]);
+}
+
+bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing)
+{
+ QList<QDockWidget*> dockwidgets = _dockwidgets;
+
+ int cnt;
+ stream >> cnt;
+ for (int i = 0; i < cnt; ++i) {
+ int pos;
+ stream >> pos;
+ QSize size;
+ stream >> size;
+ if (!testing) {
+ docks[pos].rect = QRect(QPoint(0, 0), size);
+ }
+ if (!docks[pos].restoreState(stream, dockwidgets, testing)) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return false;
+ }
+ }
+
+ QSize size;
+ stream >> size;
+ centralWidgetRect = QRect(QPoint(0, 0), size);
+
+ bool ok = stream.status() == QDataStream::Ok;
+
+ if (ok) {
+ int cornerData[4];
+ for (int i = 0; i < 4; ++i)
+ stream >> cornerData[i];
+ if (stream.status() == QDataStream::Ok) {
+ for (int i = 0; i < 4; ++i)
+ corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
+ }
+
+ if (!testing)
+ fallbackToSizeHints = false;
+ }
+
+ return ok;
+}
+
+QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QList<int> result = docks[i].indexOfPlaceHolder(objectName);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ }
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QList<int> result = docks[i].indexOf(dockWidget);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ return result;
+ }
+ }
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::gapIndex(const QPoint &pos) const
+{
+ QMainWindow::DockOptions opts = mainWindow->dockOptions();
+ bool nestingEnabled = opts & QMainWindow::AllowNestedDocks;
+ QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs;
+#ifndef QT_NO_TABBAR
+ if (opts & QMainWindow::AllowTabbedDocks
+ || opts & QMainWindow::VerticalTabs)
+ tabMode = QDockAreaLayoutInfo::AllowTabs;
+ if (opts & QMainWindow::ForceTabbedDocks)
+ tabMode = QDockAreaLayoutInfo::ForceTabs;
+
+ if (tabMode == QDockAreaLayoutInfo::ForceTabs)
+ nestingEnabled = false;
+#endif
+
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+
+ if (!info.isEmpty() && info.rect.contains(pos)) {
+ QList<int> result
+ = docks[i].gapIndex(pos, nestingEnabled, tabMode);
+ if (!result.isEmpty())
+ result.prepend(i);
+ return result;
+ }
+ }
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+
+ if (info.isEmpty()) {
+ QRect r;
+ switch (i) {
+ case QInternal::LeftDock:
+ r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
+ break;
+ case QInternal::RightDock:
+ r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
+ EmptyDropAreaSize, rect.height());
+ break;
+ case QInternal::TopDock:
+ r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
+ break;
+ case QInternal::BottomDock:
+ r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
+ rect.width(), EmptyDropAreaSize);
+ break;
+ }
+ if (r.contains(pos)) {
+ if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) {
+ //in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed
+ //it mustn't be completely empty otherwise it won't work
+ return QList<int>() << i << -1 << 0;
+ } else {
+ return QList<int>() << i << 0;
+ }
+ }
+ }
+ }
+
+ return QList<int>();
+}
+
+QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const
+{
+ QList<int> result;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &info = docks[i];
+ if (info.isEmpty())
+ continue;
+ QRect rect = separatorRect(i);
+ if (!rect.isNull() && sep == 1)
+ rect.adjust(-2, -2, 2, 2);
+ if (rect.contains(pos) && !info.hasFixedSize()) {
+ result << i;
+ break;
+ } else if (info.rect.contains(pos)) {
+ result = docks[i].findSeparator(pos);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget)
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (QDockAreaLayoutInfo *result = docks[i].info(widget))
+ return result;
+ }
+
+ return 0;
+}
+
+QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+
+ if (path.count() == 1)
+ return &docks[index];
+
+ return docks[index].info(path.mid(1));
+}
+
+const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const
+{
+ return const_cast<QDockAreaLayout*>(this)->info(path);
+}
+
+QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].item(path.mid(1));
+}
+
+QRect QDockAreaLayout::itemRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].itemRect(path.mid(1));
+}
+
+QRect QDockAreaLayout::separatorRect(int index) const
+{
+ const QDockAreaLayoutInfo &dock = docks[index];
+ if (dock.isEmpty())
+ return QRect();
+ QRect r = dock.rect;
+ switch (index) {
+ case QInternal::LeftDock:
+ return QRect(r.right() + 1, r.top(), sep, r.height());
+ case QInternal::RightDock:
+ return QRect(r.left() - sep, r.top(), sep, r.height());
+ case QInternal::TopDock:
+ return QRect(r.left(), r.bottom() + 1, r.width(), sep);
+ case QInternal::BottomDock:
+ return QRect(r.left(), r.top() - sep, r.width(), sep);
+ default:
+ break;
+ }
+ return QRect();
+}
+
+QRect QDockAreaLayout::separatorRect(const QList<int> &path) const
+{
+ Q_ASSERT(!path.isEmpty());
+
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+
+ if (path.count() == 1)
+ return separatorRect(index);
+ else
+ return docks[index].separatorRect(path.mid(1));
+}
+
+bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].insertGap(path.mid(1), dockWidgetItem);
+}
+
+QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].plug(path.mid(1));
+}
+
+QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ return docks[index].unplug(path.mid(1));
+}
+
+void QDockAreaLayout::remove(const QList<int> &path)
+{
+ Q_ASSERT(!path.isEmpty());
+ const int index = path.first();
+ Q_ASSERT(index >= 0 && index < QInternal::DockCount);
+ docks[index].remove(path.mid(1));
+}
+
+static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); }
+static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
+
+void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
+ QVector<QLayoutStruct> *_hor_struct_list)
+{
+ QSize center_hint(0, 0);
+ QSize center_min(0, 0);
+ const bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty();
+ if (have_central) {
+ center_hint = centralWidgetRect.size();
+ if (!center_hint.isValid())
+ center_hint = centralWidgetItem->sizeHint();
+ center_min = centralWidgetItem->minimumSize();
+ }
+
+ QRect center_rect = rect;
+ if (!docks[QInternal::LeftDock].isEmpty())
+ center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep);
+ if (!docks[QInternal::TopDock].isEmpty())
+ center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep);
+ if (!docks[QInternal::RightDock].isEmpty())
+ center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep);
+ if (!docks[QInternal::BottomDock].isEmpty())
+ center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep);
+
+ QSize left_hint = docks[QInternal::LeftDock].size();
+ if (left_hint.isNull() || fallbackToSizeHints)
+ left_hint = docks[QInternal::LeftDock].sizeHint();
+ QSize left_min = docks[QInternal::LeftDock].minimumSize();
+ QSize left_max = docks[QInternal::LeftDock].maximumSize();
+ left_hint = left_hint.boundedTo(left_max).expandedTo(left_min);
+
+ QSize right_hint = docks[QInternal::RightDock].size();
+ if (right_hint.isNull() || fallbackToSizeHints)
+ right_hint = docks[QInternal::RightDock].sizeHint();
+ QSize right_min = docks[QInternal::RightDock].minimumSize();
+ QSize right_max = docks[QInternal::RightDock].maximumSize();
+ right_hint = right_hint.boundedTo(right_max).expandedTo(right_min);
+
+ QSize top_hint = docks[QInternal::TopDock].size();
+ if (top_hint.isNull() || fallbackToSizeHints)
+ top_hint = docks[QInternal::TopDock].sizeHint();
+ QSize top_min = docks[QInternal::TopDock].minimumSize();
+ QSize top_max = docks[QInternal::TopDock].maximumSize();
+ top_hint = top_hint.boundedTo(top_max).expandedTo(top_min);
+
+ QSize bottom_hint = docks[QInternal::BottomDock].size();
+ if (bottom_hint.isNull() || fallbackToSizeHints)
+ bottom_hint = docks[QInternal::BottomDock].sizeHint();
+ QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
+ QSize bottom_max = docks[QInternal::BottomDock].maximumSize();
+ bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min);
+
+ fallbackToSizeHints = false;
+
+ if (_ver_struct_list != 0) {
+ QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
+ ver_struct_list.resize(3);
+
+ // top --------------------------------------------------
+ ver_struct_list[0].init();
+ ver_struct_list[0].stretch = 0;
+ ver_struct_list[0].sizeHint = top_hint.height();
+ ver_struct_list[0].minimumSize = top_min.height();
+ ver_struct_list[0].maximumSize = top_max.height();
+ ver_struct_list[0].expansive = false;
+ ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty();
+ ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top();
+ ver_struct_list[0].size = docks[QInternal::TopDock].rect.height();
+
+ // center --------------------------------------------------
+ ver_struct_list[1].init();
+ ver_struct_list[1].stretch = center_hint.height();
+
+ bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty();
+ bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty();
+ bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty();
+ bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty();
+
+ int left = (tl_significant && bl_significant) ? left_hint.height() : 0;
+ int right = (tr_significant && br_significant) ? right_hint.height() : 0;
+ ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
+
+ left = (tl_significant && bl_significant) ? left_min.height() : 0;
+ right = (tr_significant && br_significant) ? right_min.height() : 0;
+ ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
+ ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
+ ver_struct_list[1].expansive = have_central;
+ ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty()
+ && !have_central
+ && docks[QInternal::RightDock].isEmpty();
+ ver_struct_list[1].pos = center_rect.top();
+ ver_struct_list[1].size = center_rect.height();
+
+ // bottom --------------------------------------------------
+ ver_struct_list[2].init();
+ ver_struct_list[2].stretch = 0;
+ ver_struct_list[2].sizeHint = bottom_hint.height();
+ ver_struct_list[2].minimumSize = bottom_min.height();
+ ver_struct_list[2].maximumSize = bottom_max.height();
+ ver_struct_list[2].expansive = false;
+ ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty();
+ ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top();
+ ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height();
+
+ for (int i = 0; i < 3; ++i) {
+ ver_struct_list[i].sizeHint
+ = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
+ }
+ }
+
+ if (_hor_struct_list != 0) {
+ QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
+ hor_struct_list.resize(3);
+
+ // left --------------------------------------------------
+ hor_struct_list[0].init();
+ hor_struct_list[0].stretch = 0;
+ hor_struct_list[0].sizeHint = left_hint.width();
+ hor_struct_list[0].minimumSize = left_min.width();
+ hor_struct_list[0].maximumSize = left_max.width();
+ hor_struct_list[0].expansive = false;
+ hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty();
+ hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left();
+ hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width();
+
+ // center --------------------------------------------------
+ hor_struct_list[1].init();
+ hor_struct_list[1].stretch = center_hint.width();
+
+ bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty();
+ bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty();
+ bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty();
+ bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty();
+
+ int top = (tl_significant && tr_significant) ? top_hint.width() : 0;
+ int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0;
+ hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
+
+ top = (tl_significant && tr_significant) ? top_min.width() : 0;
+ bottom = (bl_significant && br_significant) ? bottom_min.width() : 0;
+ hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
+
+ hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
+ hor_struct_list[1].expansive = have_central;
+ hor_struct_list[1].empty = !have_central;
+ hor_struct_list[1].pos = center_rect.left();
+ hor_struct_list[1].size = center_rect.width();
+
+ // right --------------------------------------------------
+ hor_struct_list[2].init();
+ hor_struct_list[2].stretch = 0;
+ hor_struct_list[2].sizeHint = right_hint.width();
+ hor_struct_list[2].minimumSize = right_min.width();
+ hor_struct_list[2].maximumSize = right_max.width();
+ hor_struct_list[2].expansive = false;
+ hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty();
+ hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left();
+ hor_struct_list[2].size = docks[QInternal::RightDock].rect.width();
+
+ for (int i = 0; i < 3; ++i) {
+ hor_struct_list[i].sizeHint
+ = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
+ }
+ }
+}
+
+void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
+ QVector<QLayoutStruct> *hor_struct_list)
+{
+
+ // top ---------------------------------------------------
+
+ if (!docks[QInternal::TopDock].isEmpty()) {
+ QRect r = docks[QInternal::TopDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty()
+ ? rect.left() : hor_struct_list->at(1).pos);
+ r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty()
+ ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(rect.top());
+ r.setBottom(ver_struct_list->at(1).pos - sep - 1);
+ }
+ docks[QInternal::TopDock].rect = r;
+ docks[QInternal::TopDock].fitItems();
+ }
+
+ // bottom ---------------------------------------------------
+
+ if (!docks[QInternal::BottomDock].isEmpty()) {
+ QRect r = docks[QInternal::BottomDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::LeftDock].isEmpty()
+ ? rect.left() : hor_struct_list->at(1).pos);
+ r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
+ || docks[QInternal::RightDock].isEmpty()
+ ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(ver_struct_list->at(2).pos);
+ r.setBottom(rect.bottom());
+ }
+ docks[QInternal::BottomDock].rect = r;
+ docks[QInternal::BottomDock].fitItems();
+ }
+
+ // left ---------------------------------------------------
+
+ if (!docks[QInternal::LeftDock].isEmpty()) {
+ QRect r = docks[QInternal::LeftDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(rect.left());
+ r.setRight(hor_struct_list->at(1).pos - sep - 1);
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty()
+ ? rect.top() : ver_struct_list->at(1).pos);
+ r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty()
+ ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
+ }
+ docks[QInternal::LeftDock].rect = r;
+ docks[QInternal::LeftDock].fitItems();
+ }
+
+ // right ---------------------------------------------------
+
+ if (!docks[QInternal::RightDock].isEmpty()) {
+ QRect r = docks[QInternal::RightDock].rect;
+ if (hor_struct_list != 0) {
+ r.setLeft(hor_struct_list->at(2).pos);
+ r.setRight(rect.right());
+ }
+ if (ver_struct_list != 0) {
+ r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::TopDock].isEmpty()
+ ? rect.top() : ver_struct_list->at(1).pos);
+ r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
+ || docks[QInternal::BottomDock].isEmpty()
+ ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
+ }
+ docks[QInternal::RightDock].rect = r;
+ docks[QInternal::RightDock].fitItems();
+ }
+
+ // center ---------------------------------------------------
+
+ if (hor_struct_list != 0) {
+ centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
+ centralWidgetRect.setWidth(hor_struct_list->at(1).size);
+ }
+ if (ver_struct_list != 0) {
+ centralWidgetRect.setTop(ver_struct_list->at(1).pos);
+ centralWidgetRect.setHeight(ver_struct_list->at(1).size);
+ }
+}
+
+void QDockAreaLayout::fitLayout()
+{
+ QVector<QLayoutStruct> ver_struct_list(3);
+ QVector<QLayoutStruct> hor_struct_list(3);
+ getGrid(&ver_struct_list, &hor_struct_list);
+
+ qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
+ qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
+
+ setGrid(&ver_struct_list, &hor_struct_list);
+}
+
+void QDockAreaLayout::clear()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].clear();
+
+ rect = QRect();
+ centralWidgetRect = QRect();
+}
+
+QSize QDockAreaLayout::sizeHint() const
+{
+ int left_sep = 0;
+ int right_sep = 0;
+ int top_sep = 0;
+ int bottom_sep = 0;
+
+ if (centralWidgetItem != 0) {
+ left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
+ right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
+ top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
+ bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
+ }
+
+ QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0);
+ QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0);
+ QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep);
+ QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep);
+ QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint();
+
+ int row1 = top.width();
+ int row2 = left.width() + center.width() + right.width();
+ int row3 = bottom.width();
+ int col1 = left.height();
+ int col2 = top.height() + center.height() + bottom.height();
+ int col3 = right.height();
+
+ if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
+ row1 += left.width();
+ else
+ col1 += top.height();
+
+ if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
+ row1 += right.width();
+ else
+ col3 += top.height();
+
+ if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
+ row3 += left.width();
+ else
+ col1 += bottom.height();
+
+ if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
+ row3 += right.width();
+ else
+ col3 += bottom.height();
+
+ return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
+}
+
+QSize QDockAreaLayout::minimumSize() const
+{
+ int left_sep = 0;
+ int right_sep = 0;
+ int top_sep = 0;
+ int bottom_sep = 0;
+
+ if (centralWidgetItem != 0) {
+ left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep;
+ right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep;
+ top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep;
+ bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep;
+ }
+
+ QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0);
+ QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0);
+ QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep);
+ QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep);
+ QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize();
+
+ int row1 = top.width();
+ int row2 = left.width() + center.width() + right.width();
+ int row3 = bottom.width();
+ int col1 = left.height();
+ int col2 = top.height() + center.height() + bottom.height();
+ int col3 = right.height();
+
+ if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
+ row1 += left.width();
+ else
+ col1 += top.height();
+
+ if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
+ row1 += right.width();
+ else
+ col3 += top.height();
+
+ if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
+ row3 += left.width();
+ else
+ col1 += bottom.height();
+
+ if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
+ row3 += right.width();
+ else
+ col3 += bottom.height();
+
+ return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
+}
+
+bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
+{
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (index.isEmpty())
+ return false;
+
+ QDockAreaLayoutItem &item = this->item(index);
+ QPlaceHolderItem *placeHolder = item.placeHolderItem;
+ Q_ASSERT(placeHolder != 0);
+
+ item.widgetItem = new QDockWidgetItem(dockWidget);
+
+ if (placeHolder->window) {
+ QDesktopWidget desktop;
+ QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget));
+ dockWidget->d_func()->setWindowState(true, true, r);
+ }
+ dockWidget->setVisible(!placeHolder->hidden);
+#ifdef Q_WS_X11
+ if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag
+ dockWidget->d_func()->setWindowState(true);
+#endif
+
+ item.placeHolderItem = 0;
+ delete placeHolder;
+
+ return true;
+}
+
+void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget,
+ Qt::Orientation orientation)
+{
+ QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget);
+ QDockAreaLayoutInfo &info = docks[pos];
+ if (orientation == info.o || info.item_list.count() <= 1) {
+ // empty dock areas, or dock areas containing exactly one widget can have their orientation
+ // switched.
+ info.o = orientation;
+
+ QDockAreaLayoutItem new_item(dockWidgetItem);
+ info.item_list.append(new_item);
+#ifndef QT_NO_TABBAR
+ if (info.tabbed && !new_item.skip()) {
+ info.updateTabBar();
+ info.setCurrentTabId(tabId(new_item));
+ }
+#endif
+ } else {
+#ifndef QT_NO_TABBAR
+ int tbshape = info.tabBarShape;
+#else
+ int tbshape = 0;
+#endif
+ QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow);
+ new_info.item_list.append(new QDockAreaLayoutInfo(info));
+ new_info.item_list.append(dockWidgetItem);
+ info = new_info;
+ }
+
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
+{
+ QList<int> path = indexOf(first);
+ if (path.isEmpty())
+ return;
+
+ QDockAreaLayoutInfo *info = this->info(path);
+ Q_ASSERT(info != 0);
+ info->tab(path.last(), new QDockWidgetItem(second));
+
+ QList<int> index = indexOfPlaceHolder(second->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::splitDockWidget(QDockWidget *after,
+ QDockWidget *dockWidget,
+ Qt::Orientation orientation)
+{
+ QList<int> path = indexOf(after);
+ if (path.isEmpty())
+ return;
+
+ QDockAreaLayoutInfo *info = this->info(path);
+ Q_ASSERT(info != 0);
+ info->split(path.last(), orientation, new QDockWidgetItem(dockWidget));
+
+ QList<int> index = indexOfPlaceHolder(dockWidget->objectName());
+ if (!index.isEmpty())
+ remove(index);
+}
+
+void QDockAreaLayout::apply(bool animate)
+{
+ QWidgetAnimator &widgetAnimator = qt_mainwindow_layout(mainWindow)->widgetAnimator;
+
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].apply(animate);
+ if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) {
+ widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect,
+ animate);
+ }
+#ifndef QT_NO_TABBAR
+ if (sep == 1)
+ updateSeparatorWidgets();
+#endif //QT_NO_TABBAR
+}
+
+void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget,
+ const QRegion &clip,
+ const QPoint &mouse) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+ QRect r = separatorRect(i);
+ if (clip.contains(r) && !dock.hasFixedSize()) {
+ Qt::Orientation opposite = dock.o == Qt::Horizontal
+ ? Qt::Vertical : Qt::Horizontal;
+ paintSep(p, widget, r, opposite, r.contains(mouse));
+ }
+ if (clip.contains(dock.rect))
+ dock.paintSeparators(p, widget, clip, mouse);
+ }
+}
+
+QRegion QDockAreaLayout::separatorRegion() const
+{
+ QRegion result;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+ result |= separatorRect(i);
+ result |= dock.separatorRegion();
+ }
+
+ return result;
+}
+
+int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin,
+ const QPoint &dest)
+{
+ int delta = 0;
+ int index = separator.last();
+
+ if (separator.count() > 1) {
+ QDockAreaLayoutInfo *info = this->info(separator);
+ delta = pick(info->o, dest - origin);
+ if (delta != 0)
+ delta = info->separatorMove(index, delta);
+ info->apply(false);
+ return delta;
+ }
+
+ QVector<QLayoutStruct> list;
+
+ if (index == QInternal::LeftDock || index == QInternal::RightDock)
+ getGrid(0, &list);
+ else
+ getGrid(&list, 0);
+
+ int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock
+ ? 0 : 1;
+ Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock
+ ? Qt::Horizontal
+ : Qt::Vertical;
+
+ delta = pick(o, dest - origin);
+ delta = separatorMoveHelper(list, sep_index, delta, sep);
+
+ if (index == QInternal::LeftDock || index == QInternal::RightDock)
+ setGrid(0, &list);
+ else
+ setGrid(&list, 0);
+
+ apply(false);
+
+ return delta;
+}
+
+#ifndef QT_NO_TABBAR
+// Sets the correct positions for the separator widgets
+// Allocates new sepearator widgets with getSeparatorWidget
+void QDockAreaLayout::updateSeparatorWidgets() const
+{
+ int j = 0;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (dock.isEmpty())
+ continue;
+
+ QWidget *sepWidget;
+ if (j < separatorWidgets.size()) {
+ sepWidget = separatorWidgets.at(j);
+ } else {
+ sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
+ separatorWidgets.append(sepWidget);
+ }
+ j++;
+
+#ifndef QT_MAC_USE_COCOA
+ sepWidget->raise();
+#endif
+ QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
+ sepWidget->setGeometry(sepRect);
+ sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft())));
+ sepWidget->show();
+ }
+ for (int i = j; i < separatorWidgets.size(); ++i)
+ separatorWidgets.at(i)->hide();
+
+ separatorWidgets.resize(j);
+}
+#endif //QT_NO_TABBAR
+
+QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ if (QLayoutItem *ret = dock.itemAt(x, index))
+ return ret;
+ }
+
+ if (centralWidgetItem && (*x)++ == index)
+ return centralWidgetItem;
+
+ return 0;
+}
+
+QLayoutItem *QDockAreaLayout::takeAt(int *x, int index)
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QDockAreaLayoutInfo &dock = docks[i];
+ if (QLayoutItem *ret = dock.takeAt(x, index))
+ return ret;
+ }
+
+ if (centralWidgetItem && (*x)++ == index) {
+ QLayoutItem *ret = centralWidgetItem;
+ centralWidgetItem = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+void QDockAreaLayout::deleteAllLayoutItems()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].deleteAllLayoutItems();
+}
+
+#ifndef QT_NO_TABBAR
+QSet<QTabBar*> QDockAreaLayout::usedTabBars() const
+{
+ QSet<QTabBar*> result;
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ result += dock.usedTabBars();
+ }
+ return result;
+}
+
+// Returns the set of all used separator widgets
+QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const
+{
+ QSet<QWidget*> result;
+
+ for (int i = 0; i < separatorWidgets.count(); ++i)
+ result << separatorWidgets.at(i);
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QDockAreaLayoutInfo &dock = docks[i];
+ result += dock.usedSeparatorWidgets();
+ }
+ return result;
+}
+#endif
+
+QRect QDockAreaLayout::gapRect(const QList<int> &path) const
+{
+ const QDockAreaLayoutInfo *info = this->info(path);
+ if (info == 0)
+ return QRect();
+ const QList<QDockAreaLayoutItem> &item_list = info->item_list;
+ Qt::Orientation o = info->o;
+ int index = path.last();
+ if (index < 0 || index >= item_list.count())
+ return QRect();
+ const QDockAreaLayoutItem &item = item_list.at(index);
+ if (!(item.flags & QDockAreaLayoutItem::GapItem))
+ return QRect();
+
+ QRect result;
+
+#ifndef QT_NO_TABBAR
+ if (info->tabbed) {
+ result = info->tabContentRect();
+ } else
+#endif
+ {
+ int pos = item.pos;
+ int size = item.size;
+
+ int prev = info->prev(index);
+ int next = info->next(index);
+
+ if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) {
+ pos += sep;
+ size -= sep;
+ }
+ if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem))
+ size -= sep;
+
+ QPoint p;
+ rpick(o, p) = pos;
+ rperp(o, p) = perp(o, info->rect.topLeft());
+ QSize s;
+ rpick(o, s) = size;
+ rperp(o, s) = perp(o, info->rect.size());
+
+ result = QRect(p, s);
+ }
+
+ return result;
+}
+
+void QDockAreaLayout::keepSize(QDockWidget *w)
+{
+ QList<int> path = indexOf(w);
+ if (path.isEmpty())
+ return;
+ QDockAreaLayoutItem &item = this->item(path);
+ if (item.size != -1)
+ item.flags |= QDockAreaLayoutItem::KeepSize;
+}
+
+void QDockAreaLayout::styleChangedEvent()
+{
+ sep = mainWindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainWindow);
+ fitLayout();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DOCKWIDGET
diff --git a/src/widgets/widgets/qdockarealayout_p.h b/src/widgets/widgets/qdockarealayout_p.h
new file mode 100644
index 0000000000..a341ad487b
--- /dev/null
+++ b/src/widgets/widgets/qdockarealayout_p.h
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDOCKAREALAYOUT_P_H
+#define QDOCKAREALAYOUT_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 "QtCore/qrect.h"
+#include "QtCore/qpair.h"
+#include "QtCore/qlist.h"
+#include "QtCore/qvector.h"
+#include "QtWidgets/qlayout.h"
+
+#ifndef QT_NO_DOCKWIDGET
+
+QT_BEGIN_NAMESPACE
+
+class QLayoutItem;
+class QWidget;
+class QLayoutItem;
+class QDockAreaLayoutInfo;
+class QPlaceHolderItem;
+class QDockWidget;
+class QMainWindow;
+class QWidgetAnimator;
+class QMainWindowLayout;
+struct QLayoutStruct;
+class QTabBar;
+
+// The classes in this file represent the tree structure that represents all the docks
+// Also see the wiki internal documentation
+// At the root of the tree is: QDockAreaLayout, which handles all 4 sides, so there is only one.
+// For each side it has one QDockAreaLayoutInfo child. (See QDockAreaLayout::docks.)
+// The QDockAreaLayoutInfo have QDockAreaLayoutItems as children (See QDockAreaLayoutInfo::item_list),
+// which then has one QDockAreaLayoutInfo as a child. (QDockAreaLayoutItem::subInfo) or
+// a widgetItem if this is a node of the tree (QDockAreaLayoutItem::widgetItem)
+//
+// A path indetifies uniquely one object in this tree, the first number being the side and all the following
+// indexes into the QDockAreaLayoutInfo::item_list.
+
+struct QDockAreaLayoutItem
+{
+ enum ItemFlags { NoFlags = 0, GapItem = 1, KeepSize = 2 };
+
+ QDockAreaLayoutItem(QLayoutItem *_widgetItem = 0);
+ QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo);
+ QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem);
+ QDockAreaLayoutItem(const QDockAreaLayoutItem &other);
+ ~QDockAreaLayoutItem();
+
+ QDockAreaLayoutItem &operator = (const QDockAreaLayoutItem &other);
+
+ bool skip() const;
+ QSize minimumSize() const;
+ QSize maximumSize() const;
+ QSize sizeHint() const;
+ bool expansive(Qt::Orientation o) const;
+ bool hasFixedSize(Qt::Orientation o) const;
+
+ QLayoutItem *widgetItem;
+ QDockAreaLayoutInfo *subinfo;
+ QPlaceHolderItem *placeHolderItem;
+ int pos;
+ int size;
+ uint flags;
+};
+
+class Q_AUTOTEST_EXPORT QPlaceHolderItem
+{
+public:
+ QPlaceHolderItem() : hidden(false), window(false) {}
+ QPlaceHolderItem(QWidget *w);
+
+ QString objectName;
+ bool hidden, window;
+ QRect topLevelRect;
+};
+
+class Q_AUTOTEST_EXPORT QDockAreaLayoutInfo
+{
+public:
+ QDockAreaLayoutInfo();
+ QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos, Qt::Orientation _o,
+ int tbhape, QMainWindow *window);
+
+ QSize minimumSize() const;
+ QSize maximumSize() const;
+ QSize sizeHint() const;
+ QSize size() const;
+
+ bool insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem);
+ QLayoutItem *plug(const QList<int> &path);
+ QLayoutItem *unplug(const QList<int> &path);
+ enum TabMode { NoTabs, AllowTabs, ForceTabs };
+ QList<int> gapIndex(const QPoint &pos, bool nestingEnabled,
+ TabMode tabMode) const;
+ void remove(const QList<int> &path);
+ void unnest(int index);
+ void split(int index, Qt::Orientation orientation, QLayoutItem *dockWidgetItem);
+ void tab(int index, QLayoutItem *dockWidgetItem);
+ QDockAreaLayoutItem &item(const QList<int> &path);
+ QDockAreaLayoutInfo *info(const QList<int> &path);
+ QDockAreaLayoutInfo *info(QWidget *widget);
+
+ enum { // sentinel values used to validate state data
+ SequenceMarker = 0xfc,
+ TabMarker = 0xfa,
+ WidgetMarker = 0xfb
+ };
+ void saveState(QDataStream &stream) const;
+ bool restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing);
+
+ void fitItems();
+ bool expansive(Qt::Orientation o) const;
+ int changeSize(int index, int size, bool below);
+ QRect itemRect(int index) const;
+ QRect itemRect(const QList<int> &path) const;
+ QRect separatorRect(int index) const;
+ QRect separatorRect(const QList<int> &path) const;
+
+ void clear();
+ bool isEmpty() const;
+ bool hasFixedSize() const;
+ QList<int> findSeparator(const QPoint &pos) const;
+ int next(int idx) const;
+ int prev(int idx) const;
+
+ QList<int> indexOf(QWidget *widget) const;
+ QList<int> indexOfPlaceHolder(const QString &objectName) const;
+
+ void apply(bool animate);
+
+ void paintSeparators(QPainter *p, QWidget *widget, const QRegion &clip,
+ const QPoint &mouse) const;
+ QRegion separatorRegion() const;
+ int separatorMove(int index, int delta);
+
+ QLayoutItem *itemAt(int *x, int index) const;
+ QLayoutItem *takeAt(int *x, int index);
+ void deleteAllLayoutItems();
+
+ QMainWindowLayout *mainWindowLayout() const;
+
+ const int *sep;
+ mutable QVector<QWidget*> separatorWidgets;
+ QInternal::DockPosition dockPos;
+ Qt::Orientation o;
+ QRect rect;
+ QMainWindow *mainWindow;
+ QList<QDockAreaLayoutItem> item_list;
+#ifndef QT_NO_TABBAR
+ void updateSeparatorWidgets() const;
+ QSet<QWidget*> usedSeparatorWidgets() const;
+#endif //QT_NO_TABBAR
+
+#ifndef QT_NO_TABBAR
+ quintptr currentTabId() const;
+ void setCurrentTab(QWidget *widget);
+ void setCurrentTabId(quintptr id);
+ QRect tabContentRect() const;
+ bool tabbed;
+ QTabBar *tabBar;
+ int tabBarShape;
+
+ bool updateTabBar() const;
+ void setTabBarShape(int shape);
+ QSize tabBarMinimumSize() const;
+ QSize tabBarSizeHint() const;
+
+ QSet<QTabBar*> usedTabBars() const;
+#endif // QT_NO_TABBAR
+};
+
+class Q_AUTOTEST_EXPORT QDockAreaLayout
+{
+public:
+ enum { EmptyDropAreaSize = 80 }; // when a dock area is empty, how "wide" is it?
+
+ Qt::DockWidgetArea corners[4]; // use a Qt::Corner for indexing
+ QRect rect;
+ QLayoutItem *centralWidgetItem;
+ QMainWindow *mainWindow;
+ QRect centralWidgetRect;
+ QDockAreaLayout(QMainWindow *win);
+ QDockAreaLayoutInfo docks[4];
+ int sep; // separator extent
+ bool fallbackToSizeHints; //determines if we should use the sizehint for the dock areas (true until the layout is restored or the central widget is set)
+ mutable QVector<QWidget*> separatorWidgets;
+
+ bool isValid() const;
+
+ enum { DockWidgetStateMarker = 0xfd };
+ void saveState(QDataStream &stream) const;
+ bool restoreState(QDataStream &stream, const QList<QDockWidget*> &widgets, bool testing = false);
+
+ QList<int> indexOfPlaceHolder(const QString &objectName) const;
+ QList<int> indexOf(QWidget *dockWidget) const;
+ QList<int> gapIndex(const QPoint &pos) const;
+ QList<int> findSeparator(const QPoint &pos) const;
+
+ QDockAreaLayoutItem &item(const QList<int> &path);
+ QDockAreaLayoutInfo *info(const QList<int> &path);
+ const QDockAreaLayoutInfo *info(const QList<int> &path) const;
+ QDockAreaLayoutInfo *info(QWidget *widget);
+ QRect itemRect(const QList<int> &path) const;
+ QRect separatorRect(int index) const;
+ QRect separatorRect(const QList<int> &path) const;
+
+ bool insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem);
+ QLayoutItem *plug(const QList<int> &path);
+ QLayoutItem *unplug(const QList<int> &path);
+ void remove(const QList<int> &path);
+
+ void fitLayout();
+
+ void clear();
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+
+ void addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget, Qt::Orientation orientation);
+ bool restoreDockWidget(QDockWidget *dockWidget);
+ void splitDockWidget(QDockWidget *after, QDockWidget *dockWidget,
+ Qt::Orientation orientation);
+ void tabifyDockWidget(QDockWidget *first, QDockWidget *second);
+
+ void apply(bool animate);
+
+ void paintSeparators(QPainter *p, QWidget *widget, const QRegion &clip,
+ const QPoint &mouse) const;
+ QRegion separatorRegion() const;
+ int separatorMove(const QList<int> &separator, const QPoint &origin, const QPoint &dest);
+#ifndef QT_NO_TABBAR
+ void updateSeparatorWidgets() const;
+#endif //QT_NO_TABBAR
+
+ QLayoutItem *itemAt(int *x, int index) const;
+ QLayoutItem *takeAt(int *x, int index);
+ void deleteAllLayoutItems();
+
+ void getGrid(QVector<QLayoutStruct> *ver_struct_list,
+ QVector<QLayoutStruct> *hor_struct_list);
+ void setGrid(QVector<QLayoutStruct> *ver_struct_list,
+ QVector<QLayoutStruct> *hor_struct_list);
+
+ QRect gapRect(const QList<int> &path) const;
+
+ void keepSize(QDockWidget *w);
+#ifndef QT_NO_TABBAR
+ QSet<QTabBar*> usedTabBars() const;
+ QSet<QWidget*> usedSeparatorWidgets() const;
+#endif //QT_NO_TABBAR
+ void styleChangedEvent();
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QDOCKWIDGET
+
+#endif // QDOCKAREALAYOUT_P_H
diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp
new file mode 100644
index 0000000000..53e007aea5
--- /dev/null
+++ b/src/widgets/widgets/qdockwidget.cpp
@@ -0,0 +1,1605 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdockwidget.h"
+
+#ifndef QT_NO_DOCKWIDGET
+#include <qaction.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qdrawutil.h>
+#include <qevent.h>
+#include <qfontmetrics.h>
+#include <qmainwindow.h>
+#include <qrubberband.h>
+#include <qstylepainter.h>
+#include <qtoolbutton.h>
+#include <qdebug.h>
+
+#include <private/qwidgetresizehandler_p.h>
+
+#include "qdockwidget_p.h"
+#include "qmainwindowlayout_p.h"
+#ifdef Q_WS_MAC
+#include <private/qapplication_p.h>
+#include <private/qt_mac_p.h>
+#include <qmacstyle_mac.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+static inline bool hasFeature(const QDockWidgetPrivate *priv, QDockWidget::DockWidgetFeature feature)
+{ return (priv->features & feature) == feature; }
+
+static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
+{ return (dockwidget->features() & feature) == feature; }
+
+
+/*
+ A Dock Window:
+
+ [+] is the float button
+ [X] is the close button
+
+ +-------------------------------+
+ | Dock Window Title [+][X]|
+ +-------------------------------+
+ | |
+ | place to put the single |
+ | QDockWidget child (this space |
+ | does not yet have a name) |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +-------------------------------+
+
+*/
+
+/******************************************************************************
+** QDockWidgetTitleButton
+*/
+
+class QDockWidgetTitleButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ QDockWidgetTitleButton(QDockWidget *dockWidget);
+
+ QSize sizeHint() const;
+ inline QSize minimumSizeHint() const
+ { return sizeHint(); }
+
+ void enterEvent(QEvent *event);
+ void leaveEvent(QEvent *event);
+ void paintEvent(QPaintEvent *event);
+};
+
+
+QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
+ : QAbstractButton(dockWidget)
+{
+ setFocusPolicy(Qt::NoFocus);
+}
+
+QSize QDockWidgetTitleButton::sizeHint() const
+{
+ ensurePolished();
+
+ int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
+ if (!icon().isNull()) {
+ int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ QSize sz = icon().actualSize(QSize(iconSize, iconSize));
+ size += qMax(sz.width(), sz.height());
+ }
+
+ return QSize(size, size);
+}
+
+void QDockWidgetTitleButton::enterEvent(QEvent *event)
+{
+ if (isEnabled()) update();
+ QAbstractButton::enterEvent(event);
+}
+
+void QDockWidgetTitleButton::leaveEvent(QEvent *event)
+{
+ if (isEnabled()) update();
+ QAbstractButton::leaveEvent(event);
+}
+
+void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+
+ QStyleOptionToolButton opt;
+ opt.init(this);
+ opt.state |= QStyle::State_AutoRaise;
+
+ if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, 0, this))
+ {
+ if (isEnabled() && underMouse() && !isChecked() && !isDown())
+ opt.state |= QStyle::State_Raised;
+ if (isChecked())
+ opt.state |= QStyle::State_On;
+ if (isDown())
+ opt.state |= QStyle::State_Sunken;
+ style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
+ }
+
+ opt.icon = icon();
+ opt.subControls = 0;
+ opt.activeSubControls = 0;
+ opt.features = QStyleOptionToolButton::None;
+ opt.arrowType = Qt::NoArrow;
+ int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ opt.iconSize = QSize(size, size);
+ style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
+}
+
+/******************************************************************************
+** QDockWidgetLayout
+*/
+
+QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
+ : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
+{
+}
+
+QDockWidgetLayout::~QDockWidgetLayout()
+{
+ qDeleteAll(item_list);
+}
+
+bool QDockWidgetLayout::nativeWindowDeco() const
+{
+ return nativeWindowDeco(parentWidget()->isWindow());
+}
+
+bool QDockWidgetLayout::nativeWindowDeco(bool floating) const
+{
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_WINCE)
+ Q_UNUSED(floating);
+ return false;
+#else
+ return floating && item_list[QDockWidgetLayout::TitleBar] == 0;
+#endif
+}
+
+
+void QDockWidgetLayout::addItem(QLayoutItem*)
+{
+ qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
+ return;
+}
+
+QLayoutItem *QDockWidgetLayout::itemAt(int index) const
+{
+ int cnt = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ QLayoutItem *item = item_list.at(i);
+ if (item == 0)
+ continue;
+ if (index == cnt++)
+ return item;
+ }
+ return 0;
+}
+
+QLayoutItem *QDockWidgetLayout::takeAt(int index)
+{
+ int j = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ QLayoutItem *item = item_list.at(i);
+ if (item == 0)
+ continue;
+ if (index == j) {
+ item_list[i] = 0;
+ invalidate();
+ return item;
+ }
+ ++j;
+ }
+ return 0;
+}
+
+int QDockWidgetLayout::count() const
+{
+ int result = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ if (item_list.at(i))
+ ++result;
+ }
+ return result;
+}
+
+QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) const
+{
+ QSize result = content;
+
+ if (verticalTitleBar) {
+ result.setHeight(qMax(result.height(), minimumTitleWidth()));
+ result.setWidth(qMax(content.width(), 0));
+ } else {
+ result.setHeight(qMax(result.height(), 0));
+ result.setWidth(qMax(content.width(), minimumTitleWidth()));
+ }
+
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+ const bool nativeDeco = nativeWindowDeco(floating);
+
+ int fw = floating && !nativeDeco
+ ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, w)
+ : 0;
+
+ const int th = titleHeight();
+ if (!nativeDeco) {
+ if (verticalTitleBar)
+ result += QSize(th + 2*fw, 2*fw);
+ else
+ result += QSize(2*fw, th + 2*fw);
+ }
+
+ result.setHeight(qMin(result.height(), (int) QWIDGETSIZE_MAX));
+ result.setWidth(qMin(result.width(), (int) QWIDGETSIZE_MAX));
+
+ if (content.width() < 0)
+ result.setWidth(-1);
+ if (content.height() < 0)
+ result.setHeight(-1);
+
+ int left, top, right, bottom;
+ w->getContentsMargins(&left, &top, &right, &bottom);
+ //we need to substract the contents margin (it will be added by the caller)
+ QSize min = w->minimumSize() - QSize(left + right, top + bottom);
+ QSize max = w->maximumSize() - QSize(left + right, top + bottom);
+
+ /* A floating dockwidget will automatically get its minimumSize set to the layout's
+ minimum size + deco. We're *not* interested in this, we only take minimumSize()
+ into account if the user set it herself. Otherwise we end up expanding the result
+ of a calculation for a non-floating dock widget to a floating dock widget's
+ minimum size + window decorations. */
+
+ uint explicitMin = 0;
+ uint explicitMax = 0;
+ if (w->d_func()->extra != 0) {
+ explicitMin = w->d_func()->extra->explicitMinSize;
+ explicitMax = w->d_func()->extra->explicitMaxSize;
+ }
+
+ if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
+ min.setWidth(-1);
+ if (!(explicitMin & Qt::Vertical) || min.height() == 0)
+ min.setHeight(-1);
+
+ if (!(explicitMax & Qt::Horizontal))
+ max.setWidth(QWIDGETSIZE_MAX);
+ if (!(explicitMax & Qt::Vertical))
+ max.setHeight(QWIDGETSIZE_MAX);
+
+ return result.boundedTo(max).expandedTo(min);
+}
+
+QSize QDockWidgetLayout::sizeHint() const
+{
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+
+ QSize content(-1, -1);
+ if (item_list[Content] != 0)
+ content = item_list[Content]->sizeHint();
+
+ return sizeFromContent(content, w->isFloating());
+}
+
+QSize QDockWidgetLayout::maximumSize() const
+{
+ if (item_list[Content] != 0) {
+ const QSize content = item_list[Content]->maximumSize();
+ return sizeFromContent(content, parentWidget()->isWindow());
+ } else {
+ return parentWidget()->maximumSize();
+ }
+
+}
+
+QSize QDockWidgetLayout::minimumSize() const
+{
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+
+ QSize content(0, 0);
+ if (item_list[Content] != 0)
+ content = item_list[Content]->minimumSize();
+
+ return sizeFromContent(content, w->isFloating());
+}
+
+QWidget *QDockWidgetLayout::widgetForRole(Role r) const
+{
+ QLayoutItem *item = item_list.at(r);
+ return item == 0 ? 0 : item->widget();
+}
+
+QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
+{
+ return item_list.at(r);
+}
+
+void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w)
+{
+ QWidget *old = widgetForRole(r);
+ if (old != 0) {
+ old->hide();
+ removeWidget(old);
+ }
+
+ if (w != 0) {
+ addChildWidget(w);
+ item_list[r] = new QWidgetItemV2(w);
+ w->show();
+ } else {
+ item_list[r] = 0;
+ }
+
+ invalidate();
+}
+
+static inline int pick(bool vertical, const QSize &size)
+{
+ return vertical ? size.height() : size.width();
+}
+
+static inline int perp(bool vertical, const QSize &size)
+{
+ return vertical ? size.width() : size.height();
+}
+
+int QDockWidgetLayout::minimumTitleWidth() const
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ if (QWidget *title = widgetForRole(TitleBar))
+ return pick(verticalTitleBar, title->minimumSizeHint());
+
+ QSize closeSize(0, 0);
+ QSize floatSize(0, 0);
+ if (hasFeature(q, QDockWidget::DockWidgetClosable)) {
+ if (QLayoutItem *item = item_list[CloseButton])
+ closeSize = item->widget()->sizeHint();
+ }
+ if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
+ if (QLayoutItem *item = item_list[FloatButton])
+ floatSize = item->widget()->sizeHint();
+ }
+
+ int titleHeight = this->titleHeight();
+
+ int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
+ int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
+
+ return pick(verticalTitleBar, closeSize)
+ + pick(verticalTitleBar, floatSize)
+ + titleHeight + 2*fw + 3*mw;
+}
+
+int QDockWidgetLayout::titleHeight() const
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ if (QWidget *title = widgetForRole(TitleBar))
+ return perp(verticalTitleBar, title->sizeHint());
+
+ QSize closeSize(0, 0);
+ QSize floatSize(0, 0);
+ if (QLayoutItem *item = item_list[CloseButton])
+ closeSize = item->widget()->sizeHint();
+ if (QLayoutItem *item = item_list[FloatButton])
+ floatSize = item->widget()->sizeHint();
+
+ int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
+ perp(verticalTitleBar, floatSize));
+
+ QFontMetrics titleFontMetrics = q->fontMetrics();
+#ifdef Q_WS_MAC
+ if (qobject_cast<QMacStyle *>(q->style())) {
+ //### this breaks on proxy styles. (But is this code still called?)
+ QFont font = qt_app_fonts_hash()->value("QToolButton", q->font());
+ titleFontMetrics = QFontMetrics(font);
+ }
+#endif
+
+ int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
+
+ return qMax(buttonHeight + 2, titleFontMetrics.height() + 2*mw);
+}
+
+void QDockWidgetLayout::setGeometry(const QRect &geometry)
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ bool nativeDeco = nativeWindowDeco();
+
+ int fw = q->isFloating() && !nativeDeco
+ ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q)
+ : 0;
+
+ if (nativeDeco) {
+ if (QLayoutItem *item = item_list[Content])
+ item->setGeometry(geometry);
+ } else {
+ int titleHeight = this->titleHeight();
+
+ if (verticalTitleBar) {
+ _titleArea = QRect(QPoint(fw, fw),
+ QSize(titleHeight, geometry.height() - (fw * 2)));
+ } else {
+ _titleArea = QRect(QPoint(fw, fw),
+ QSize(geometry.width() - (fw * 2), titleHeight));
+ }
+
+ if (QLayoutItem *item = item_list[TitleBar]) {
+ item->setGeometry(_titleArea);
+ } else {
+ QStyleOptionDockWidgetV2 opt;
+ q->initStyleOption(&opt);
+
+ if (QLayoutItem *item = item_list[CloseButton]) {
+ if (!item->isEmpty()) {
+ QRect r = q->style()
+ ->subElementRect(QStyle::SE_DockWidgetCloseButton,
+ &opt, q);
+ if (!r.isNull())
+ item->setGeometry(r);
+ }
+ }
+
+ if (QLayoutItem *item = item_list[FloatButton]) {
+ if (!item->isEmpty()) {
+ QRect r = q->style()
+ ->subElementRect(QStyle::SE_DockWidgetFloatButton,
+ &opt, q);
+ if (!r.isNull())
+ item->setGeometry(r);
+ }
+ }
+ }
+
+ if (QLayoutItem *item = item_list[Content]) {
+ QRect r = geometry;
+ if (verticalTitleBar) {
+ r.setLeft(_titleArea.right() + 1);
+ r.adjust(0, fw, -fw, -fw);
+ } else {
+ r.setTop(_titleArea.bottom() + 1);
+ r.adjust(fw, 0, -fw, -fw);
+ }
+ item->setGeometry(r);
+ }
+ }
+}
+
+void QDockWidgetLayout::setVerticalTitleBar(bool b)
+{
+ if (b == verticalTitleBar)
+ return;
+ verticalTitleBar = b;
+ invalidate();
+ parentWidget()->update();
+}
+
+/******************************************************************************
+** QDockWidgetItem
+*/
+
+QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
+ : QWidgetItem(dockWidget)
+{
+}
+
+QSize QDockWidgetItem::minimumSize() const
+{
+ QSize widgetMin(0, 0);
+ if (QLayoutItem *item = dockWidgetChildItem())
+ widgetMin = item->minimumSize();
+ return dockWidgetLayout()->sizeFromContent(widgetMin, false);
+}
+
+QSize QDockWidgetItem::maximumSize() const
+{
+ if (QLayoutItem *item = dockWidgetChildItem()) {
+ return dockWidgetLayout()->sizeFromContent(item->maximumSize(), false);
+ } else {
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ }
+}
+
+
+QSize QDockWidgetItem::sizeHint() const
+{
+ if (QLayoutItem *item = dockWidgetChildItem()) {
+ return dockWidgetLayout()->sizeFromContent(item->sizeHint(), false);
+ } else {
+ return QWidgetItem::sizeHint();
+ }
+}
+
+/******************************************************************************
+** QDockWidgetPrivate
+*/
+
+void QDockWidgetPrivate::init()
+{
+ Q_Q(QDockWidget);
+
+ QDockWidgetLayout *layout = new QDockWidgetLayout(q);
+ layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
+
+ QAbstractButton *button = new QDockWidgetTitleButton(q);
+ button->setObjectName(QLatin1String("qt_dockwidget_floatbutton"));
+ QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
+ layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
+
+ button = new QDockWidgetTitleButton(q);
+ button->setObjectName(QLatin1String("qt_dockwidget_closebutton"));
+ QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
+ layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
+
+ resizer = new QWidgetResizeHandler(q);
+ resizer->setMovingEnabled(false);
+ resizer->setActive(false);
+
+#ifndef QT_NO_ACTION
+ toggleViewAction = new QAction(q);
+ toggleViewAction->setCheckable(true);
+ fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
+ toggleViewAction->setText(fixedWindowTitle);
+ QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
+ q, SLOT(_q_toggleView(bool)));
+#endif
+
+ updateButtons();
+}
+
+/*!
+ Initialize \a option with the values from this QDockWidget. This method
+ is useful for subclasses when they need a QStyleOptionDockWidget, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
+{
+ Q_D(const QDockWidget);
+
+ if (!option)
+ return;
+ QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
+
+ option->initFrom(this);
+ option->rect = dwlayout->titleArea();
+ option->title = d->fixedWindowTitle;
+ option->closable = hasFeature(this, QDockWidget::DockWidgetClosable);
+ option->movable = hasFeature(this, QDockWidget::DockWidgetMovable);
+ option->floatable = hasFeature(this, QDockWidget::DockWidgetFloatable);
+
+ QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
+ QStyleOptionDockWidgetV2 *v2
+ = qstyleoption_cast<QStyleOptionDockWidgetV2*>(option);
+ if (v2 != 0)
+ v2->verticalTitleBar = l->verticalTitleBar;
+}
+
+void QDockWidgetPrivate::_q_toggleView(bool b)
+{
+ Q_Q(QDockWidget);
+ if (b == q->isHidden()) {
+ if (b)
+ q->show();
+ else
+ q->close();
+ }
+}
+
+void QDockWidgetPrivate::updateButtons()
+{
+ Q_Q(QDockWidget);
+ QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
+
+ QStyleOptionDockWidget opt;
+ q->initStyleOption(&opt);
+
+ bool customTitleBar = dwLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
+ bool nativeDeco = dwLayout->nativeWindowDeco();
+ bool hideButtons = nativeDeco || customTitleBar;
+
+ bool canClose = hasFeature(this, QDockWidget::DockWidgetClosable);
+ bool canFloat = hasFeature(this, QDockWidget::DockWidgetFloatable);
+
+ QAbstractButton *button
+ = qobject_cast<QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::FloatButton));
+ button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
+ button->setVisible(canFloat && !hideButtons);
+
+ button
+ = qobject_cast <QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::CloseButton));
+ button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
+ button->setVisible(canClose && !hideButtons);
+
+ q->setAttribute(Qt::WA_ContentsPropagated,
+ (canFloat || canClose) && !hideButtons);
+
+ layout->invalidate();
+}
+
+void QDockWidgetPrivate::_q_toggleTopLevel()
+{
+ Q_Q(QDockWidget);
+ q->setFloating(!q->isFloating());
+}
+
+void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
+{
+ if (state != 0)
+ return;
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parent);
+ Q_ASSERT(win != 0);
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+ Q_ASSERT(layout != 0);
+ if (layout->pluggingWidget != 0) // the main window is animating a docking operation
+ return;
+
+ state = new QDockWidgetPrivate::DragState;
+ state->pressPos = pos;
+ state->dragging = false;
+ state->widgetItem = 0;
+ state->ownWidgetItem = false;
+ state->nca = nca;
+ state->ctrlDrag = false;
+}
+
+void QDockWidgetPrivate::startDrag()
+{
+ Q_Q(QDockWidget);
+
+ if (state == 0 || state->dragging)
+ return;
+
+ QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ Q_ASSERT(layout != 0);
+
+ state->widgetItem = layout->unplug(q);
+ if (state->widgetItem == 0) {
+ /* I have a QMainWindow parent, but I was never inserted with
+ QMainWindow::addDockWidget, so the QMainWindowLayout has no
+ widget item for me. :( I have to create it myself, and then
+ delete it if I don't get dropped into a dock area. */
+ state->widgetItem = new QDockWidgetItem(q);
+ state->ownWidgetItem = true;
+ }
+
+ if (state->ctrlDrag)
+ layout->restore();
+
+ state->dragging = true;
+}
+
+void QDockWidgetPrivate::endDrag(bool abort)
+{
+ Q_Q(QDockWidget);
+ Q_ASSERT(state != 0);
+
+ q->releaseMouse();
+
+ if (state->dragging) {
+ QMainWindowLayout *mwLayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ Q_ASSERT(mwLayout != 0);
+
+ if (abort || !mwLayout->plug(state->widgetItem)) {
+ if (hasFeature(this, QDockWidget::DockWidgetFloatable)) {
+ if (state->ownWidgetItem)
+ delete state->widgetItem;
+ mwLayout->restore();
+#ifdef Q_WS_X11
+ // get rid of the X11BypassWindowManager window flag and activate the resizer
+ Qt::WindowFlags flags = q->windowFlags();
+ flags &= ~Qt::X11BypassWindowManagerHint;
+ q->setWindowFlags(flags);
+ resizer->setActive(QWidgetResizeHandler::Resize, true);
+ q->show();
+#else
+ QDockWidgetLayout *myLayout
+ = qobject_cast<QDockWidgetLayout*>(layout);
+ resizer->setActive(QWidgetResizeHandler::Resize,
+ myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
+#endif
+ undockedGeometry = q->geometry();
+ q->activateWindow();
+ } else {
+ mwLayout->revert(state->widgetItem);
+ }
+ }
+ }
+ delete state;
+ state = 0;
+}
+
+bool QDockWidgetPrivate::isAnimating() const
+{
+ Q_Q(const QDockWidget);
+
+ QMainWindow *mainWin = qobject_cast<QMainWindow*>(parent);
+ if (mainWin == 0)
+ return false;
+
+ QMainWindowLayout *mainWinLayout = qt_mainwindow_layout(mainWin);
+ if (mainWinLayout == 0)
+ return false;
+
+ return (void*)mainWinLayout->pluggingWidget == (void*)q;
+}
+
+bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
+{
+#if !defined(QT_NO_MAINWINDOW)
+ Q_Q(QDockWidget);
+
+ QDockWidgetLayout *dwLayout
+ = qobject_cast<QDockWidgetLayout*>(layout);
+
+ if (!dwLayout->nativeWindowDeco()) {
+ QRect titleArea = dwLayout->titleArea();
+
+ if (event->button() != Qt::LeftButton ||
+ !titleArea.contains(event->pos()) ||
+ // check if the tool window is movable... do nothing if it
+ // is not (but allow moving if the window is floating)
+ (!hasFeature(this, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
+ qobject_cast<QMainWindow*>(parent) == 0 ||
+ isAnimating() || state != 0) {
+ return false;
+ }
+
+ initDrag(event->pos(), false);
+
+ if (state)
+ state->ctrlDrag = hasFeature(this, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
+
+ return true;
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return false;
+}
+
+bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
+
+ if (!dwLayout->nativeWindowDeco()) {
+ QRect titleArea = dwLayout->titleArea();
+
+ if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
+ hasFeature(this, QDockWidget::DockWidgetFloatable)) {
+ _q_toggleTopLevel();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
+{
+ bool ret = false;
+#if !defined(QT_NO_MAINWINDOW)
+ Q_Q(QDockWidget);
+
+ if (!state)
+ return ret;
+
+ QDockWidgetLayout *dwlayout
+ = qobject_cast<QDockWidgetLayout *>(layout);
+ QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ if (!dwlayout->nativeWindowDeco()) {
+ if (!state->dragging
+ && mwlayout->pluggingWidget == 0
+ && (event->pos() - state->pressPos).manhattanLength()
+ > QApplication::startDragDistance()) {
+ startDrag();
+#ifdef Q_WS_WIN
+ grabMouseWhileInWindow();
+#else
+ q->grabMouse();
+#endif
+ ret = true;
+ }
+ }
+
+ if (state->dragging && !state->nca) {
+ QPoint pos = event->globalPos() - state->pressPos;
+ q->move(pos);
+
+ if (!state->ctrlDrag)
+ mwlayout->hover(state->widgetItem, event->globalPos());
+
+ ret = true;
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return ret;
+}
+
+bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
+{
+#if !defined(QT_NO_MAINWINDOW)
+
+ if (event->button() == Qt::LeftButton && state && !state->nca) {
+ endDrag();
+ return true; //filter out the event
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return false;
+}
+
+void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
+{
+ Q_Q(QDockWidget);
+
+ int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
+
+ QRect geo = q->geometry();
+ QRect titleRect = q->frameGeometry();
+#ifdef Q_WS_MAC
+ if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
+ titleRect.setTop(geo.top());
+ titleRect.setBottom(geo.bottom());
+ titleRect.setRight(geo.left() - 1);
+ } else
+#endif
+ {
+ titleRect.setLeft(geo.left());
+ titleRect.setRight(geo.right());
+ titleRect.setBottom(geo.top() - 1);
+ titleRect.adjust(0, fw, 0, 0);
+ }
+
+ switch (event->type()) {
+ case QEvent::NonClientAreaMouseButtonPress:
+ if (!titleRect.contains(event->globalPos()))
+ break;
+ if (state != 0)
+ break;
+ if (qobject_cast<QMainWindow*>(parent) == 0)
+ break;
+ if (isAnimating())
+ break;
+ initDrag(event->pos(), true);
+ if (state == 0)
+ break;
+#ifdef Q_WS_WIN
+ // On Windows, NCA mouse events don't contain modifier info
+ state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
+#else
+ state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
+#endif
+ startDrag();
+ break;
+ case QEvent::NonClientAreaMouseMove:
+ if (state == 0 || !state->dragging)
+ break;
+ if (state->nca) {
+ endDrag();
+ }
+#ifdef Q_OS_MAC
+ else { // workaround for lack of mouse-grab on Mac
+ QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ Q_ASSERT(layout != 0);
+
+ q->move(event->globalPos() - state->pressPos);
+ if (!state->ctrlDrag)
+ layout->hover(state->widgetItem, event->globalPos());
+ }
+#endif
+ break;
+ case QEvent::NonClientAreaMouseButtonRelease:
+#ifdef Q_OS_MAC
+ if (state)
+ endDrag();
+#endif
+ break;
+ case QEvent::NonClientAreaMouseButtonDblClick:
+ _q_toggleTopLevel();
+ break;
+ default:
+ break;
+ }
+}
+
+void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
+{
+ Q_Q(QDockWidget);
+
+ if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
+ return;
+
+ // When the native window frame is being dragged, all we get is these mouse
+ // move events.
+
+ if (state->ctrlDrag)
+ return;
+
+ QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ Q_ASSERT(layout != 0);
+
+ QPoint globalMousePos = event->pos() + state->pressPos;
+ layout->hover(state->widgetItem, globalMousePos);
+}
+
+void QDockWidgetPrivate::unplug(const QRect &rect)
+{
+ Q_Q(QDockWidget);
+ QRect r = rect;
+ r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
+ QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
+ if (dwLayout->nativeWindowDeco(true))
+ r.adjust(0, dwLayout->titleHeight(), 0, 0);
+ setWindowState(true, true, r);
+}
+
+void QDockWidgetPrivate::plug(const QRect &rect)
+{
+ setWindowState(false, false, rect);
+}
+
+void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
+{
+ Q_Q(QDockWidget);
+
+ if (!floating && parent) {
+ QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea)
+ return; // this dockwidget can't be redocked
+ }
+
+ bool wasFloating = q->isFloating();
+ bool hidden = q->isHidden();
+
+ if (q->isVisible())
+ q->hide();
+
+ Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
+
+ QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
+ const bool nativeDeco = dwLayout->nativeWindowDeco(floating);
+
+ if (nativeDeco) {
+ flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
+ if (hasFeature(this, QDockWidget::DockWidgetClosable))
+ flags |= Qt::WindowCloseButtonHint;
+ } else {
+ flags |= Qt::FramelessWindowHint;
+ }
+
+ if (unplug)
+ flags |= Qt::X11BypassWindowManagerHint;
+
+ q->setWindowFlags(flags);
+
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ if (floating && nativeDeco && (q->features() & QDockWidget::DockWidgetVerticalTitleBar)) {
+ ChangeWindowAttributes(HIViewGetWindow(HIViewRef(q->winId())), kWindowSideTitlebarAttribute, 0);
+ }
+#endif
+
+ if (!rect.isNull())
+ q->setGeometry(rect);
+
+ updateButtons();
+
+ if (!hidden)
+ q->show();
+
+ if (floating != wasFloating) {
+ emit q->topLevelChanged(floating);
+ if (!floating && parent) {
+ QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ if (mwlayout)
+ emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
+ }
+ }
+
+ resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
+}
+
+/*!
+ \class QDockWidget
+
+ \brief The QDockWidget class provides a widget that can be docked
+ inside a QMainWindow or floated as a top-level window on the
+ desktop.
+
+ \ingroup mainwindow-classes
+
+ QDockWidget provides the concept of dock widgets, also know as
+ tool palettes or utility windows. Dock windows are secondary
+ windows placed in the \e {dock widget area} around the
+ \l{QMainWindow::centralWidget()}{central widget} in a
+ QMainWindow.
+
+ \image mainwindow-docks.png
+
+ Dock windows can be moved inside their current area, moved into
+ new areas and floated (e.g., undocked) by the end-user. The
+ QDockWidget API allows the programmer to restrict the dock widgets
+ ability to move, float and close, as well as the areas in which
+ they can be placed.
+
+ \section1 Appearance
+
+ A QDockWidget consists of a title bar and the content area. The
+ title bar displays the dock widgets \link QWidget::windowTitle()
+ window title\endlink, a \e float button and a \e close button.
+ Depending on the state of the QDockWidget, the \e float and \e
+ close buttons may be either disabled or not shown at all.
+
+ The visual appearance of the title bar and buttons is dependent
+ on the \l{QStyle}{style} in use.
+
+ A QDockWidget acts as a wrapper for its child widget, set with setWidget().
+ Custom size hints, minimum and maximum sizes and size policies should be
+ implemented in the child widget. QDockWidget will respect them, adjusting
+ its own constraints to include the frame and title. Size constraints
+ should not be set on the QDockWidget itself, because they change depending
+ on whether it is docked; a docked QDockWidget has no frame and a smaller title
+ bar.
+
+ \sa QMainWindow, {Dock Widgets Example}
+*/
+
+/*!
+ \enum QDockWidget::DockWidgetFeature
+
+ \value DockWidgetClosable The dock widget can be closed. On some systems the dock
+ widget always has a close button when it's floating
+ (for example on MacOS 10.5).
+ \value DockWidgetMovable The dock widget can be moved between docks
+ by the user.
+ \value DockWidgetFloatable The dock widget can be detached from the
+ main window, and floated as an independent
+ window.
+ \value DockWidgetVerticalTitleBar The dock widget displays a vertical title
+ bar on its left side. This can be used to
+ increase the amount of vertical space in
+ a QMainWindow.
+ \value AllDockWidgetFeatures (Deprecated) The dock widget can be closed, moved,
+ and floated. Since new features might be added in future
+ releases, the look and behavior of dock widgets might
+ change if you use this flag. Please specify individual
+ flags instead.
+ \value NoDockWidgetFeatures The dock widget cannot be closed, moved,
+ or floated.
+
+ \omitvalue DockWidgetFeatureMask
+ \omitvalue Reserved
+*/
+
+/*!
+ \property QDockWidget::windowTitle
+ \brief the dock widget title (caption)
+
+ By default, this property contains an empty string.
+*/
+
+/*!
+ Constructs a QDockWidget with parent \a parent and window flags \a
+ flags. The dock widget will be placed in the left dock widget
+ area.
+*/
+QDockWidget::QDockWidget(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*new QDockWidgetPrivate, parent, flags)
+{
+ Q_D(QDockWidget);
+ d->init();
+}
+
+/*!
+ Constructs a QDockWidget with parent \a parent and window flags \a
+ flags. The dock widget will be placed in the left dock widget
+ area.
+
+ The window title is set to \a title. This title is used when the
+ QDockWidget is docked and undocked. It is also used in the context
+ menu provided by QMainWindow.
+
+ \sa setWindowTitle()
+*/
+QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*new QDockWidgetPrivate, parent, flags)
+{
+ Q_D(QDockWidget);
+ d->init();
+ setWindowTitle(title);
+}
+
+/*!
+ Destroys the dock widget.
+*/
+QDockWidget::~QDockWidget()
+{ }
+
+/*!
+ Returns the widget for the dock widget. This function returns zero
+ if the widget has not been set.
+
+ \sa setWidget()
+*/
+QWidget *QDockWidget::widget() const
+{
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+ return layout->widgetForRole(QDockWidgetLayout::Content);
+}
+
+/*!
+ Sets the widget for the dock widget to \a widget.
+
+ If the dock widget is visible when \a widget is added, you must
+ \l{QWidget::}{show()} it explicitly.
+
+ Note that you must add the layout of the \a widget before you call
+ this function; if not, the \a widget will not be visible.
+
+ \sa widget()
+*/
+void QDockWidget::setWidget(QWidget *widget)
+{
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setWidgetForRole(QDockWidgetLayout::Content, widget);
+}
+
+/*!
+ \property QDockWidget::features
+ \brief whether the dock widget is movable, closable, and floatable
+
+ By default, this property is set to a combination of DockWidgetClosable,
+ DockWidgetMovable and DockWidgetFloatable.
+
+ \sa DockWidgetFeature
+*/
+
+void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
+{
+ Q_D(QDockWidget);
+ features &= DockWidgetFeatureMask;
+ if (d->features == features)
+ return;
+ const bool closableChanged = (d->features ^ features) & DockWidgetClosable;
+ d->features = features;
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
+ d->updateButtons();
+ d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
+ emit featuresChanged(d->features);
+ update();
+ if (closableChanged && layout->nativeWindowDeco()) {
+ //this ensures the native decoration is drawn
+ d->setWindowState(true /*floating*/, true /*unplug*/);
+ }
+}
+
+QDockWidget::DockWidgetFeatures QDockWidget::features() const
+{
+ Q_D(const QDockWidget);
+ return d->features;
+}
+
+/*!
+ \property QDockWidget::floating
+ \brief whether the dock widget is floating
+
+ A floating dock widget is presented to the user as an independent
+ window "on top" of its parent QMainWindow, instead of being
+ docked in the QMainWindow.
+
+ By default, this property is true.
+
+ \sa isWindow()
+*/
+void QDockWidget::setFloating(bool floating)
+{
+ Q_D(QDockWidget);
+
+ // the initial click of a double-click may have started a drag...
+ if (d->state != 0)
+ d->endDrag(true);
+
+ QRect r = d->undockedGeometry;
+
+ d->setWindowState(floating, false, floating ? r : QRect());
+
+ if (floating && r.isNull()) {
+ if (x() < 0 || y() < 0) //may happen if we have been hidden
+ move(QPoint());
+ setAttribute(Qt::WA_Moved, false); //we want it at the default position
+ }
+}
+
+/*!
+ \property QDockWidget::allowedAreas
+ \brief areas where the dock widget may be placed
+
+ The default is Qt::AllDockWidgetAreas.
+
+ \sa Qt::DockWidgetArea
+*/
+
+void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
+{
+ Q_D(QDockWidget);
+ areas &= Qt::DockWidgetArea_Mask;
+ if (areas == d->allowedAreas)
+ return;
+ d->allowedAreas = areas;
+ emit allowedAreasChanged(d->allowedAreas);
+}
+
+Qt::DockWidgetAreas QDockWidget::allowedAreas() const
+{
+ Q_D(const QDockWidget);
+ return d->allowedAreas;
+}
+
+/*!
+ \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
+
+ Returns true if this dock widget can be placed in the given \a area;
+ otherwise returns false.
+*/
+
+/*! \reimp */
+void QDockWidget::changeEvent(QEvent *event)
+{
+ Q_D(QDockWidget);
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+
+ switch (event->type()) {
+ case QEvent::ModifiedChange:
+ case QEvent::WindowTitleChange:
+ update(layout->titleArea());
+#ifndef QT_NO_ACTION
+ d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
+ d->toggleViewAction->setText(d->fixedWindowTitle);
+#endif
+#ifndef QT_NO_TABBAR
+ {
+ QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
+ if (QMainWindowLayout *winLayout = qt_mainwindow_layout(win)) {
+ if (QDockAreaLayoutInfo *info = winLayout->layoutState.dockAreaLayout.info(this))
+ info->updateTabBar();
+ }
+ }
+#endif // QT_NO_TABBAR
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(event);
+}
+
+/*! \reimp */
+void QDockWidget::closeEvent(QCloseEvent *event)
+{
+ Q_D(QDockWidget);
+ if (d->state)
+ d->endDrag(true);
+ QWidget::closeEvent(event);
+}
+
+/*! \reimp */
+void QDockWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
+ bool nativeDeco = layout->nativeWindowDeco();
+
+ if (!nativeDeco && !customTitleBar) {
+ QStylePainter p(this);
+ // ### Add PixelMetric to change spacers, so style may show border
+ // when not floating.
+ if (isFloating()) {
+ QStyleOptionFrame framOpt;
+ framOpt.init(this);
+ p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
+ }
+
+ // Title must be painted after the frame, since the areas overlap, and
+ // the title may wish to extend out to all sides (eg. XP style)
+ QStyleOptionDockWidgetV2 titleOpt;
+ initStyleOption(&titleOpt);
+ p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
+ }
+}
+
+/*! \reimp */
+bool QDockWidget::event(QEvent *event)
+{
+ Q_D(QDockWidget);
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+
+ switch (event->type()) {
+#ifndef QT_NO_ACTION
+ case QEvent::Hide:
+ if (layout != 0)
+ layout->keepSize(this);
+ d->toggleViewAction->setChecked(false);
+ emit visibilityChanged(false);
+ break;
+ case QEvent::Show:
+ d->toggleViewAction->setChecked(true);
+ emit visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0);
+ break;
+#endif
+ case QEvent::ApplicationLayoutDirectionChange:
+ case QEvent::LayoutDirectionChange:
+ case QEvent::StyleChange:
+ case QEvent::ParentChange:
+ d->updateButtons();
+ break;
+ case QEvent::ZOrderChange: {
+ bool onTop = false;
+ if (win != 0) {
+ const QObjectList &siblings = win->children();
+ onTop = siblings.count() > 0 && siblings.last() == (QObject*)this;
+ }
+ if (!isFloating() && layout != 0 && onTop)
+ layout->raise(this);
+ break;
+ }
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ update(qobject_cast<QDockWidgetLayout *>(this->layout())->titleArea());
+ break;
+ case QEvent::ContextMenu:
+ if (d->state) {
+ event->accept();
+ return true;
+ }
+ break;
+ // return true after calling the handler since we don't want
+ // them to be passed onto the default handlers
+ case QEvent::MouseButtonPress:
+ if (d->mousePressEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::MouseButtonDblClick:
+ if (d->mouseDoubleClickEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::MouseMove:
+ if (d->mouseMoveEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+#ifdef Q_WS_WIN
+ case QEvent::Leave:
+ if (d->state != 0 && d->state->dragging && !d->state->nca) {
+ // This is a workaround for loosing the mouse on Vista.
+ QPoint pos = QCursor::pos();
+ QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ d->mouseMoveEvent(&fake);
+ }
+ break;
+#endif
+ case QEvent::MouseButtonRelease:
+ if (d->mouseReleaseEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::NonClientAreaMouseMove:
+ case QEvent::NonClientAreaMouseButtonPress:
+ case QEvent::NonClientAreaMouseButtonRelease:
+ case QEvent::NonClientAreaMouseButtonDblClick:
+ d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
+ return true;
+ case QEvent::Move:
+ d->moveEvent(static_cast<QMoveEvent*>(event));
+ break;
+ case QEvent::Resize:
+ // if the mainwindow is plugging us, we don't want to update undocked geometry
+ if (isFloating() && layout != 0 && layout->pluggingWidget != this)
+ d->undockedGeometry = geometry();
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+#ifndef QT_NO_ACTION
+/*!
+ Returns a checkable action that can be used to show or close this
+ dock widget.
+
+ The action's text is set to the dock widget's window title.
+
+ \sa QAction::text QWidget::windowTitle
+ */
+QAction * QDockWidget::toggleViewAction() const
+{
+ Q_D(const QDockWidget);
+ return d->toggleViewAction;
+}
+#endif // QT_NO_ACTION
+
+/*!
+ \fn void QDockWidget::featuresChanged(QDockWidget::DockWidgetFeatures features)
+
+ This signal is emitted when the \l features property changes. The
+ \a features parameter gives the new value of the property.
+*/
+
+/*!
+ \fn void QDockWidget::topLevelChanged(bool topLevel)
+
+ This signal is emitted when the \l floating property changes.
+ The \a topLevel parameter is true if the dock widget is now floating;
+ otherwise it is false.
+
+ \sa isWindow()
+*/
+
+/*!
+ \fn void QDockWidget::allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
+
+ This signal is emitted when the \l allowedAreas property changes. The
+ \a allowedAreas parameter gives the new value of the property.
+*/
+
+/*!
+ \fn void QDockWidget::visibilityChanged(bool visible)
+ \since 4.3
+
+ This signal is emitted when the dock widget becomes \a visible (or
+ invisible). This happens when the widget is hidden or shown, as
+ well as when it is docked in a tabbed dock area and its tab
+ becomes selected or unselected.
+*/
+
+/*!
+ \fn void QDockWidget::dockLocationChanged(Qt::DockWidgetArea area)
+ \since 4.3
+
+ This signal is emitted when the dock widget is moved to another
+ dock \a area, or is moved to a different location in its current
+ dock area. This happens when the dock widget is moved
+ programmatically or is dragged to a new location by the user.
+*/
+
+/*!
+ \since 4.3
+
+ Sets an arbitrary \a widget as the dock widget's title bar. If \a widget
+ is 0, any custom title bar widget previously set on the dock widget is
+ removed, but not deleted, and the default title bar will be used
+ instead.
+
+ If a title bar widget is set, QDockWidget will not use native window
+ decorations when it is floated.
+
+ Here are some tips for implementing custom title bars:
+
+ \list
+ \o Mouse events that are not explicitly handled by the title bar widget
+ must be ignored by calling QMouseEvent::ignore(). These events then
+ propagate to the QDockWidget parent, which handles them in the usual
+ manner, moving when the title bar is dragged, docking and undocking
+ when it is double-clicked, etc.
+
+ \o When DockWidgetVerticalTitleBar is set on QDockWidget, the title
+ bar widget is repositioned accordingly. In resizeEvent(), the title
+ bar should check what orientation it should assume:
+ \snippet doc/src/snippets/code/src_gui_widgets_qdockwidget.cpp 0
+
+ \o The title bar widget must have a valid QWidget::sizeHint() and
+ QWidget::minimumSizeHint(). These functions should take into account
+ the current orientation of the title bar.
+
+ \o It is not possible to remove a title bar from a dock widget. However,
+ a similar effect can be achieved by setting a default constructed
+ QWidget as the title bar widget.
+ \endlist
+
+ Using qobject_cast() as shown above, the title bar widget has full access
+ to its parent QDockWidget. Hence it can perform such operations as docking
+ and hiding in response to user actions.
+
+ \sa titleBarWidget() DockWidgetVerticalTitleBar
+*/
+
+void QDockWidget::setTitleBarWidget(QWidget *widget)
+{
+ Q_D(QDockWidget);
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
+ d->updateButtons();
+ if (isWindow()) {
+ //this ensures the native decoration is drawn
+ d->setWindowState(true /*floating*/, true /*unplug*/);
+ }
+}
+
+/*!
+ \since 4.3
+ Returns the custom title bar widget set on the QDockWidget, or 0 if no
+ custom title bar has been set.
+
+ \sa setTitleBarWidget()
+*/
+
+QWidget *QDockWidget::titleBarWidget() const
+{
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ return layout->widgetForRole(QDockWidgetLayout::TitleBar);
+}
+
+QT_END_NAMESPACE
+
+#include "qdockwidget.moc"
+#include "moc_qdockwidget.cpp"
+
+#endif // QT_NO_DOCKWIDGET
diff --git a/src/widgets/widgets/qdockwidget.h b/src/widgets/widgets/qdockwidget.h
new file mode 100644
index 0000000000..cc81db2fc2
--- /dev/null
+++ b/src/widgets/widgets/qdockwidget.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICDOCKWIDGET_H
+#define QDYNAMICDOCKWIDGET_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_DOCKWIDGET
+
+class QDockAreaLayout;
+class QDockWidgetPrivate;
+class QMainWindow;
+class QStyleOptionDockWidget;
+
+class Q_WIDGETS_EXPORT QDockWidget : public QWidget
+{
+ Q_OBJECT
+
+ Q_FLAGS(DockWidgetFeatures)
+ Q_PROPERTY(bool floating READ isFloating WRITE setFloating)
+ Q_PROPERTY(DockWidgetFeatures features READ features WRITE setFeatures NOTIFY featuresChanged)
+ Q_PROPERTY(Qt::DockWidgetAreas allowedAreas READ allowedAreas
+ WRITE setAllowedAreas NOTIFY allowedAreasChanged)
+ Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle DESIGNABLE true)
+
+public:
+ explicit QDockWidget(const QString &title, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ explicit QDockWidget(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QDockWidget();
+
+ QWidget *widget() const;
+ void setWidget(QWidget *widget);
+
+ enum DockWidgetFeature {
+ DockWidgetClosable = 0x01,
+ DockWidgetMovable = 0x02,
+ DockWidgetFloatable = 0x04,
+ DockWidgetVerticalTitleBar = 0x08,
+
+ DockWidgetFeatureMask = 0x0f,
+ AllDockWidgetFeatures = DockWidgetClosable|DockWidgetMovable|DockWidgetFloatable, // ### remove in 5.0
+ NoDockWidgetFeatures = 0x00,
+
+ Reserved = 0xff
+ };
+ Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
+
+ void setFeatures(DockWidgetFeatures features);
+ DockWidgetFeatures features() const;
+
+ void setFloating(bool floating);
+ inline bool isFloating() const { return isWindow(); }
+
+ void setAllowedAreas(Qt::DockWidgetAreas areas);
+ Qt::DockWidgetAreas allowedAreas() const;
+
+ void setTitleBarWidget(QWidget *widget);
+ QWidget *titleBarWidget() const;
+
+ inline bool isAreaAllowed(Qt::DockWidgetArea area) const
+ { return (allowedAreas() & area) == area; }
+
+#ifndef QT_NO_ACTION
+ QAction *toggleViewAction() const;
+#endif
+
+Q_SIGNALS:
+ void featuresChanged(QDockWidget::DockWidgetFeatures features);
+ void topLevelChanged(bool topLevel);
+ void allowedAreasChanged(Qt::DockWidgetAreas allowedAreas);
+ void visibilityChanged(bool visible);
+ void dockLocationChanged(Qt::DockWidgetArea area);
+
+protected:
+ void changeEvent(QEvent *event);
+ void closeEvent(QCloseEvent *event);
+ void paintEvent(QPaintEvent *event);
+ bool event(QEvent *event);
+ void initStyleOption(QStyleOptionDockWidget *option) const;
+
+private:
+ Q_DECLARE_PRIVATE(QDockWidget)
+ Q_DISABLE_COPY(QDockWidget)
+ Q_PRIVATE_SLOT(d_func(), void _q_toggleView(bool))
+ Q_PRIVATE_SLOT(d_func(), void _q_toggleTopLevel())
+ friend class QDockAreaLayout;
+ friend class QDockWidgetItem;
+ friend class QMainWindowLayout;
+ friend class QDockWidgetLayout;
+ friend class QDockAreaLayoutInfo;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDockWidget::DockWidgetFeatures)
+
+#endif // QT_NO_DOCKWIDGET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDYNAMICDOCKWIDGET_H
diff --git a/src/widgets/widgets/qdockwidget_p.h b/src/widgets/widgets/qdockwidget_p.h
new file mode 100644
index 0000000000..4d3c4f4d70
--- /dev/null
+++ b/src/widgets/widgets/qdockwidget_p.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICDOCKWIDGET_P_H
+#define QDYNAMICDOCKWIDGET_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 "QtWidgets/qstyleoption.h"
+#include "private/qwidget_p.h"
+#include "QtWidgets/qboxlayout.h"
+#include "QtWidgets/qdockwidget.h"
+
+#ifndef QT_NO_DOCKWIDGET
+
+QT_BEGIN_NAMESPACE
+
+class QGridLayout;
+class QWidgetResizeHandler;
+class QRubberBand;
+class QDockWidgetTitleButton;
+class QSpacerItem;
+class QDockWidgetItem;
+
+class QDockWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QDockWidget)
+
+ struct DragState {
+ QPoint pressPos;
+ bool dragging;
+ QLayoutItem *widgetItem;
+ bool ownWidgetItem;
+ bool nca;
+ bool ctrlDrag;
+ };
+
+public:
+ inline QDockWidgetPrivate()
+ : QWidgetPrivate(), state(0),
+ features(QDockWidget::DockWidgetClosable
+ | QDockWidget::DockWidgetMovable
+ | QDockWidget::DockWidgetFloatable),
+ allowedAreas(Qt::AllDockWidgetAreas)
+ { }
+
+ void init();
+ void _q_toggleView(bool); // private slot
+ void _q_toggleTopLevel(); // private slot
+
+ void updateButtons();
+ DragState *state;
+
+ QDockWidget::DockWidgetFeatures features;
+ Qt::DockWidgetAreas allowedAreas;
+
+ QWidgetResizeHandler *resizer;
+
+#ifndef QT_NO_ACTION
+ QAction *toggleViewAction;
+#endif
+
+// QMainWindow *findMainWindow(QWidget *widget) const;
+ QRect undockedGeometry;
+ QString fixedWindowTitle;
+
+ bool mousePressEvent(QMouseEvent *event);
+ bool mouseDoubleClickEvent(QMouseEvent *event);
+ bool mouseMoveEvent(QMouseEvent *event);
+ bool mouseReleaseEvent(QMouseEvent *event);
+ void setWindowState(bool floating, bool unplug = false, const QRect &rect = QRect());
+ void nonClientAreaMouseEvent(QMouseEvent *event);
+ void initDrag(const QPoint &pos, bool nca);
+ void startDrag();
+ void endDrag(bool abort = false);
+ void moveEvent(QMoveEvent *event);
+
+ void unplug(const QRect &rect);
+ void plug(const QRect &rect);
+
+ bool isAnimating() const;
+};
+
+class Q_WIDGETS_EXPORT QDockWidgetLayout : public QLayout
+{
+ Q_OBJECT
+public:
+ QDockWidgetLayout(QWidget *parent = 0);
+ ~QDockWidgetLayout();
+ void addItem(QLayoutItem *item);
+ QLayoutItem *itemAt(int index) const;
+ QLayoutItem *takeAt(int index);
+ int count() const;
+
+ QSize maximumSize() const;
+ QSize minimumSize() const;
+ QSize sizeHint() const;
+
+ QSize sizeFromContent(const QSize &content, bool floating) const;
+
+ void setGeometry(const QRect &r);
+
+ enum Role { Content, CloseButton, FloatButton, TitleBar, RoleCount };
+ QWidget *widgetForRole(Role r) const;
+ void setWidgetForRole(Role r, QWidget *w);
+ QLayoutItem *itemForRole(Role r) const;
+
+ QRect titleArea() const { return _titleArea; }
+
+ int minimumTitleWidth() const;
+ int titleHeight() const;
+ void updateMaxSize();
+ bool nativeWindowDeco() const;
+ bool nativeWindowDeco(bool floating) const;
+
+ void setVerticalTitleBar(bool b);
+
+ bool verticalTitleBar;
+
+private:
+ QVector<QLayoutItem*> item_list;
+ QRect _titleArea;
+};
+
+/* The size hints of a QDockWidget will depend on whether it is docked or not.
+ This layout item always returns the size hints as if the dock widget was docked. */
+
+class QDockWidgetItem : public QWidgetItem
+{
+public:
+ QDockWidgetItem(QDockWidget *dockWidget);
+ QSize minimumSize() const;
+ QSize maximumSize() const;
+ QSize sizeHint() const;
+
+private:
+ inline QLayoutItem *dockWidgetChildItem() const;
+ inline QDockWidgetLayout *dockWidgetLayout() const;
+};
+
+inline QLayoutItem *QDockWidgetItem::dockWidgetChildItem() const
+{
+ if (QDockWidgetLayout *layout = dockWidgetLayout())
+ return layout->itemForRole(QDockWidgetLayout::Content);
+ return 0;
+}
+
+inline QDockWidgetLayout *QDockWidgetItem::dockWidgetLayout() const
+{
+ QWidget *w = const_cast<QDockWidgetItem*>(this)->widget();
+ if (w != 0)
+ return qobject_cast<QDockWidgetLayout*>(w->layout());
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DOCKWIDGET
+
+#endif // QDYNAMICDOCKWIDGET_P_H
diff --git a/src/widgets/widgets/qeffects.cpp b/src/widgets/widgets/qeffects.cpp
new file mode 100644
index 0000000000..adf1cc1f87
--- /dev/null
+++ b/src/widgets/widgets/qeffects.cpp
@@ -0,0 +1,613 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+#ifndef QT_NO_EFFECTS
+#include "qdesktopwidget.h"
+#include "qeffects_p.h"
+#include "qevent.h"
+#include "qimage.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qpointer.h"
+#include "qtimer.h"
+#include "qelapsedtimer.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Internal class QAlphaWidget.
+
+ The QAlphaWidget is shown while the animation lasts
+ and displays the pixmap resulting from the alpha blending.
+*/
+
+class QAlphaWidget: public QWidget, private QEffects
+{
+ Q_OBJECT
+public:
+ QAlphaWidget(QWidget* w, Qt::WindowFlags f = 0);
+ ~QAlphaWidget();
+
+ void run(int time);
+
+protected:
+ void paintEvent(QPaintEvent* e);
+ void closeEvent(QCloseEvent*);
+ void alphaBlend();
+ bool eventFilter(QObject *, QEvent *);
+
+protected slots:
+ void render();
+
+private:
+ QPixmap pm;
+ double alpha;
+ QImage backImage;
+ QImage frontImage;
+ QImage mixedImage;
+ QPointer<QWidget> widget;
+ int duration;
+ int elapsed;
+ bool showWidget;
+ QTimer anim;
+ QElapsedTimer checkTime;
+};
+
+static QAlphaWidget* q_blend = 0;
+
+/*
+ Constructs a QAlphaWidget.
+*/
+QAlphaWidget::QAlphaWidget(QWidget* w, Qt::WindowFlags f)
+ : QWidget(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)), f)
+{
+#ifndef Q_WS_WIN
+ setEnabled(false);
+#endif
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ widget = w;
+ alpha = 0;
+}
+
+QAlphaWidget::~QAlphaWidget()
+{
+#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
+ // Restore user-defined opacity value
+ if (widget)
+ widget->setWindowOpacity(1);
+#endif
+}
+
+/*
+ \reimp
+*/
+void QAlphaWidget::paintEvent(QPaintEvent*)
+{
+ QPainter p(this);
+ p.drawPixmap(0, 0, pm);
+}
+
+/*
+ Starts the alphablending animation.
+ The animation will take about \a time ms
+*/
+void QAlphaWidget::run(int time)
+{
+ duration = time;
+
+ if (duration < 0)
+ duration = 150;
+
+ if (!widget)
+ return;
+
+ elapsed = 0;
+ checkTime.start();
+
+ showWidget = true;
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ qApp->installEventFilter(this);
+ widget->setWindowOpacity(0.0);
+ widget->show();
+ connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
+ anim.start(1);
+#else
+ //This is roughly equivalent to calling setVisible(true) without actually showing the widget
+ widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
+ widget->setAttribute(Qt::WA_WState_Hidden, false);
+
+ qApp->installEventFilter(this);
+
+ move(widget->geometry().x(),widget->geometry().y());
+ resize(widget->size().width(), widget->size().height());
+
+ frontImage = QPixmap::grabWidget(widget).toImage();
+ backImage = QPixmap::grabWindow(QApplication::desktop()->winId(),
+ widget->geometry().x(), widget->geometry().y(),
+ widget->geometry().width(), widget->geometry().height()).toImage();
+
+ if (!backImage.isNull() && checkTime.elapsed() < duration / 2) {
+ mixedImage = backImage.copy();
+ pm = QPixmap::fromImage(mixedImage);
+ show();
+ setEnabled(false);
+
+ connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
+ anim.start(1);
+ } else {
+ duration = 0;
+ render();
+ }
+#endif
+}
+
+/*
+ \reimp
+*/
+bool QAlphaWidget::eventFilter(QObject *o, QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::Move:
+ if (o != widget)
+ break;
+ move(widget->geometry().x(),widget->geometry().y());
+ update();
+ break;
+ case QEvent::Hide:
+ case QEvent::Close:
+ if (o != widget)
+ break;
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ showWidget = false;
+ render();
+ break;
+ case QEvent::KeyPress: {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if (ke->key() == Qt::Key_Escape) {
+ showWidget = false;
+ } else {
+ duration = 0;
+ }
+ render();
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+/*
+ \reimp
+*/
+void QAlphaWidget::closeEvent(QCloseEvent *e)
+{
+ e->accept();
+ if (!q_blend)
+ return;
+
+ showWidget = false;
+ render();
+
+ QWidget::closeEvent(e);
+}
+
+/*
+ Render alphablending for the time elapsed.
+
+ Show the blended widget and free all allocated source
+ if the blending is finished.
+*/
+void QAlphaWidget::render()
+{
+ int tempel = checkTime.elapsed();
+ if (elapsed >= tempel)
+ elapsed++;
+ else
+ elapsed = tempel;
+
+ if (duration != 0)
+ alpha = tempel / double(duration);
+ else
+ alpha = 1;
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ if (alpha >= 1 || !showWidget) {
+ anim.stop();
+ qApp->removeEventFilter(this);
+ widget->setWindowOpacity(1);
+ q_blend = 0;
+ deleteLater();
+ } else {
+ widget->setWindowOpacity(alpha);
+ }
+#else
+ if (alpha >= 1 || !showWidget) {
+ anim.stop();
+ qApp->removeEventFilter(this);
+
+ if (widget) {
+ if (!showWidget) {
+#ifdef Q_WS_WIN
+ setEnabled(true);
+ setFocus();
+#endif // Q_WS_WIN
+ widget->hide();
+ } else {
+ //Since we are faking the visibility of the widget
+ //we need to unset the hidden state on it before calling show
+ widget->setAttribute(Qt::WA_WState_Hidden, true);
+ widget->show();
+ lower();
+ }
+ }
+ q_blend = 0;
+ deleteLater();
+ } else {
+ alphaBlend();
+ pm = QPixmap::fromImage(mixedImage);
+ repaint();
+ }
+#endif // defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+}
+
+/*
+ Calculate an alphablended image.
+*/
+void QAlphaWidget::alphaBlend()
+{
+ const int a = qRound(alpha*256);
+ const int ia = 256 - a;
+
+ const int sw = frontImage.width();
+ const int sh = frontImage.height();
+ const int bpl = frontImage.bytesPerLine();
+ switch(frontImage.depth()) {
+ case 32:
+ {
+ uchar *mixed_data = mixedImage.bits();
+ const uchar *back_data = backImage.bits();
+ const uchar *front_data = frontImage.bits();
+
+ for (int sy = 0; sy < sh; sy++) {
+ quint32* mixed = (quint32*)mixed_data;
+ const quint32* back = (const quint32*)back_data;
+ const quint32* front = (const quint32*)front_data;
+ for (int sx = 0; sx < sw; sx++) {
+ quint32 bp = back[sx];
+ quint32 fp = front[sx];
+
+ mixed[sx] = qRgb((qRed(bp)*ia + qRed(fp)*a)>>8,
+ (qGreen(bp)*ia + qGreen(fp)*a)>>8,
+ (qBlue(bp)*ia + qBlue(fp)*a)>>8);
+ }
+ mixed_data += bpl;
+ back_data += bpl;
+ front_data += bpl;
+ }
+ }
+ default:
+ break;
+ }
+}
+
+/*
+ Internal class QRollEffect
+
+ The QRollEffect widget is shown while the animation lasts
+ and displays a scrolling pixmap.
+*/
+
+class QRollEffect : public QWidget, private QEffects
+{
+ Q_OBJECT
+public:
+ QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient);
+
+ void run(int time);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void closeEvent(QCloseEvent*);
+
+private slots:
+ void scroll();
+
+private:
+ QPointer<QWidget> widget;
+
+ int currentHeight;
+ int currentWidth;
+ int totalHeight;
+ int totalWidth;
+
+ int duration;
+ int elapsed;
+ bool done;
+ bool showWidget;
+ int orientation;
+
+ QTimer anim;
+ QElapsedTimer checkTime;
+
+ QPixmap pm;
+};
+
+static QRollEffect* q_roll = 0;
+
+/*
+ Construct a QRollEffect widget.
+*/
+QRollEffect::QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient)
+ : QWidget(0, f), orientation(orient)
+{
+#ifndef Q_WS_WIN
+ setEnabled(false);
+#endif
+
+ widget = w;
+ Q_ASSERT(widget);
+
+ setAttribute(Qt::WA_NoSystemBackground, true);
+
+ if (widget->testAttribute(Qt::WA_Resized)) {
+ totalWidth = widget->width();
+ totalHeight = widget->height();
+ } else {
+ totalWidth = widget->sizeHint().width();
+ totalHeight = widget->sizeHint().height();
+ }
+
+ currentHeight = totalHeight;
+ currentWidth = totalWidth;
+
+ if (orientation & (RightScroll|LeftScroll))
+ currentWidth = 0;
+ if (orientation & (DownScroll|UpScroll))
+ currentHeight = 0;
+
+ pm = QPixmap::grabWidget(widget);
+}
+
+/*
+ \reimp
+*/
+void QRollEffect::paintEvent(QPaintEvent*)
+{
+ int x = orientation & RightScroll ? qMin(0, currentWidth - totalWidth) : 0;
+ int y = orientation & DownScroll ? qMin(0, currentHeight - totalHeight) : 0;
+
+ QPainter p(this);
+ p.drawPixmap(x, y, pm);
+}
+
+/*
+ \reimp
+*/
+void QRollEffect::closeEvent(QCloseEvent *e)
+{
+ e->accept();
+ if (done)
+ return;
+
+ showWidget = false;
+ done = true;
+ scroll();
+
+ QWidget::closeEvent(e);
+}
+
+/*
+ Start the animation.
+
+ The animation will take about \a time ms, or is
+ calculated if \a time is negative
+*/
+void QRollEffect::run(int time)
+{
+ if (!widget)
+ return;
+
+ duration = time;
+ elapsed = 0;
+
+ if (duration < 0) {
+ int dist = 0;
+ if (orientation & (RightScroll|LeftScroll))
+ dist += totalWidth - currentWidth;
+ if (orientation & (DownScroll|UpScroll))
+ dist += totalHeight - currentHeight;
+ duration = qMin(qMax(dist/3, 50), 120);
+ }
+
+ connect(&anim, SIGNAL(timeout()), this, SLOT(scroll()));
+
+ move(widget->geometry().x(),widget->geometry().y());
+ resize(qMin(currentWidth, totalWidth), qMin(currentHeight, totalHeight));
+
+ //This is roughly equivalent to calling setVisible(true) without actually showing the widget
+ widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
+ widget->setAttribute(Qt::WA_WState_Hidden, false);
+
+ show();
+ setEnabled(false);
+
+ qApp->installEventFilter(this);
+
+ showWidget = true;
+ done = false;
+ anim.start(1);
+ checkTime.start();
+}
+
+/*
+ Roll according to the time elapsed.
+*/
+void QRollEffect::scroll()
+{
+ if (!done && widget) {
+ int tempel = checkTime.elapsed();
+ if (elapsed >= tempel)
+ elapsed++;
+ else
+ elapsed = tempel;
+
+ if (currentWidth != totalWidth) {
+ currentWidth = totalWidth * (elapsed/duration)
+ + (2 * totalWidth * (elapsed%duration) + duration)
+ / (2 * duration);
+ // equiv. to int((totalWidth*elapsed) / duration + 0.5)
+ done = (currentWidth >= totalWidth);
+ }
+ if (currentHeight != totalHeight) {
+ currentHeight = totalHeight * (elapsed/duration)
+ + (2 * totalHeight * (elapsed%duration) + duration)
+ / (2 * duration);
+ // equiv. to int((totalHeight*elapsed) / duration + 0.5)
+ done = (currentHeight >= totalHeight);
+ }
+ done = (currentHeight >= totalHeight) &&
+ (currentWidth >= totalWidth);
+
+ int w = totalWidth;
+ int h = totalHeight;
+ int x = widget->geometry().x();
+ int y = widget->geometry().y();
+
+ if (orientation & RightScroll || orientation & LeftScroll)
+ w = qMin(currentWidth, totalWidth);
+ if (orientation & DownScroll || orientation & UpScroll)
+ h = qMin(currentHeight, totalHeight);
+
+ setUpdatesEnabled(false);
+ if (orientation & UpScroll)
+ y = widget->geometry().y() + qMax(0, totalHeight - currentHeight);
+ if (orientation & LeftScroll)
+ x = widget->geometry().x() + qMax(0, totalWidth - currentWidth);
+ if (orientation & UpScroll || orientation & LeftScroll)
+ move(x, y);
+
+ resize(w, h);
+ setUpdatesEnabled(true);
+ repaint();
+ }
+ if (done) {
+ anim.stop();
+ qApp->removeEventFilter(this);
+ if (widget) {
+ if (!showWidget) {
+#ifdef Q_WS_WIN
+ setEnabled(true);
+ setFocus();
+#endif
+ widget->hide();
+ } else {
+ //Since we are faking the visibility of the widget
+ //we need to unset the hidden state on it before calling show
+ widget->setAttribute(Qt::WA_WState_Hidden, true);
+ widget->show();
+ lower();
+ }
+ }
+ q_roll = 0;
+ deleteLater();
+ }
+}
+
+/*!
+ Scroll widget \a w in \a time ms. \a orient may be 1 (vertical), 2
+ (horizontal) or 3 (diagonal).
+*/
+void qScrollEffect(QWidget* w, QEffects::DirFlags orient, int time)
+{
+ if (q_roll) {
+ q_roll->deleteLater();
+ q_roll = 0;
+ }
+
+ if (!w)
+ return;
+
+ QApplication::sendPostedEvents(w, QEvent::Move);
+ QApplication::sendPostedEvents(w, QEvent::Resize);
+ Qt::WindowFlags flags = Qt::ToolTip;
+
+ // those can be popups - they would steal the focus, but are disabled
+ q_roll = new QRollEffect(w, flags, orient);
+ q_roll->run(time);
+}
+
+/*!
+ Fade in widget \a w in \a time ms.
+*/
+void qFadeEffect(QWidget* w, int time)
+{
+ if (q_blend) {
+ q_blend->deleteLater();
+ q_blend = 0;
+ }
+
+ if (!w)
+ return;
+
+ QApplication::sendPostedEvents(w, QEvent::Move);
+ QApplication::sendPostedEvents(w, QEvent::Resize);
+
+ Qt::WindowFlags flags = Qt::ToolTip;
+
+ // those can be popups - they would steal the focus, but are disabled
+ q_blend = new QAlphaWidget(w, flags);
+
+ q_blend->run(time);
+}
+
+QT_END_NAMESPACE
+
+/*
+ Delete this after timeout
+*/
+
+#include "qeffects.moc"
+
+#endif //QT_NO_EFFECTS
diff --git a/src/widgets/widgets/qeffects_p.h b/src/widgets/widgets/qeffects_p.h
new file mode 100644
index 0000000000..bae2bbf54a
--- /dev/null
+++ b/src/widgets/widgets/qeffects_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEFFECTS_P_H
+#define QEFFECTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qeffects.cpp, qcombobox.cpp, qpopupmenu.cpp and qtooltip.cpp.
+// This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qnamespace.h"
+
+#ifndef QT_NO_EFFECTS
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+
+struct QEffects
+{
+ enum Direction {
+ LeftScroll = 0x0001,
+ RightScroll = 0x0002,
+ UpScroll = 0x0004,
+ DownScroll = 0x0008
+ };
+
+ typedef uint DirFlags;
+};
+
+extern void Q_WIDGETS_EXPORT qScrollEffect(QWidget*, QEffects::DirFlags dir = QEffects::DownScroll, int time = -1);
+extern void Q_WIDGETS_EXPORT qFadeEffect(QWidget*, int time = -1);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_EFFECTS
+
+#endif // QEFFECTS_P_H
diff --git a/src/widgets/widgets/qfocusframe.cpp b/src/widgets/widgets/qfocusframe.cpp
new file mode 100644
index 0000000000..b41a71ab54
--- /dev/null
+++ b/src/widgets/widgets/qfocusframe.cpp
@@ -0,0 +1,339 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfocusframe.h"
+#include "qstyle.h"
+#include "qbitmap.h"
+#include "qstylepainter.h"
+#include "qstyleoption.h"
+#include "qdebug.h"
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFocusFramePrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QFocusFrame)
+ QWidget *widget;
+ QWidget *frameParent;
+ bool showFrameAboveWidget;
+public:
+ QFocusFramePrivate() {
+ widget = 0;
+ frameParent = 0;
+ sendChildEvents = false;
+ showFrameAboveWidget = false;
+ }
+ void updateSize();
+ void update();
+};
+
+void QFocusFramePrivate::update()
+{
+ Q_Q(QFocusFrame);
+ q->setParent(frameParent);
+ updateSize();
+ if (q->parentWidget()->rect().intersects(q->geometry())) {
+ if (showFrameAboveWidget)
+ q->raise();
+ else
+ q->stackUnder(widget);
+ q->show();
+ } else {
+ q->hide();
+ }
+}
+
+void QFocusFramePrivate::updateSize()
+{
+ Q_Q(QFocusFrame);
+ if (!widget)
+ return;
+
+ int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin),
+ hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
+ QPoint pos(widget->x(), widget->y());
+ if (q->parentWidget() != widget->parentWidget())
+ pos = widget->parentWidget()->mapTo(q->parentWidget(), pos);
+ QRect geom(pos.x()-hmargin, pos.y()-vmargin,
+ widget->width()+(hmargin*2), widget->height()+(vmargin*2));
+ if(q->geometry() == geom)
+ return;
+
+ q->setGeometry(geom);
+ QStyleHintReturnMask mask;
+ QStyleOption opt;
+ q->initStyleOption(&opt);
+ if (q->style()->styleHint(QStyle::SH_FocusFrame_Mask, &opt, q, &mask))
+ q->setMask(mask.region);
+}
+
+/*!
+ Initialize \a option with the values from this QFocusFrame. This method is useful
+ for subclasses when they need a QStyleOption, but don't want to fill
+ in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QFocusFrame::initStyleOption(QStyleOption *option) const
+{
+ if (!option)
+ return;
+
+ option->initFrom(this);
+}
+
+/*!
+ \class QFocusFrame
+ \brief The QFocusFrame widget provides a focus frame which can be
+ outside of a widget's normal paintable area.
+
+ \ingroup basicwidgets
+
+
+ Normally an application will not need to create its own
+ QFocusFrame as QStyle will handle this detail for
+ you. A style writer can optionally use a QFocusFrame to have a
+ focus area outside of the widget's paintable geometry. In this way
+ space need not be reserved for the widget to have focus but only
+ set on a QWidget with QFocusFrame::setWidget. It is, however,
+ legal to create your own QFocusFrame on a custom widget and set
+ its geometry manually via QWidget::setGeometry however you will
+ not get auto-placement when the focused widget changes size or
+ placement.
+*/
+
+/*!
+ Constructs a QFocusFrame.
+
+ The focus frame will not monitor \a parent for updates but rather
+ can be placed manually or by using QFocusFrame::setWidget. A
+ QFocusFrame sets Qt::WA_NoChildEventsForParent attribute; as a
+ result the parent will not receive a QEvent::ChildInserted event,
+ this will make it possible to manually set the geometry of the
+ QFocusFrame inside of a QSplitter or other child event monitoring
+ widget.
+
+ \sa QFocusFrame::setWidget()
+*/
+
+QFocusFrame::QFocusFrame(QWidget *parent)
+ : QWidget(*new QFocusFramePrivate, parent, 0)
+{
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+ setFocusPolicy(Qt::NoFocus);
+ setAttribute(Qt::WA_NoChildEventsForParent, true);
+ setAttribute(Qt::WA_AcceptDrops, style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this));
+}
+
+/*!
+ Destructor.
+*/
+
+QFocusFrame::~QFocusFrame()
+{
+}
+
+/*!
+ QFocusFrame will track changes to \a widget and resize itself automatically.
+ If the monitored widget's parent changes, QFocusFrame will follow the widget
+ and place itself around the widget automatically. If the monitored widget is deleted,
+ QFocusFrame will set it to zero.
+
+ \sa QFocusFrame::widget()
+*/
+
+void
+QFocusFrame::setWidget(QWidget *widget)
+{
+ Q_D(QFocusFrame);
+
+ if (style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this))
+ d->showFrameAboveWidget = true;
+ else
+ d->showFrameAboveWidget = false;
+
+ if (widget == d->widget)
+ return;
+ if (d->widget) {
+ // Remove event filters from the widget hierarchy.
+ QWidget *p = d->widget;
+ do {
+ p->removeEventFilter(this);
+ if (!d->showFrameAboveWidget || p == d->frameParent)
+ break;
+ p = p->parentWidget();
+ }while (p);
+ }
+ if (widget && !widget->isWindow() && widget->parentWidget()->windowType() != Qt::SubWindow) {
+ d->widget = widget;
+ d->widget->installEventFilter(this);
+ QWidget *p = widget->parentWidget();
+ QWidget *prev = 0;
+ if (d->showFrameAboveWidget) {
+ // Find the right parent for the focus frame.
+ while (p) {
+ // Traverse the hirerarchy of the 'widget' for setting event filter.
+ // During this if come across toolbar or a top level, use that
+ // as the parent for the focus frame. If we find a scroll area
+ // use its viewport as the parent.
+ bool isScrollArea = false;
+ if (p->isWindow() || p->inherits("QToolBar") || (isScrollArea = p->inherits("QAbstractScrollArea"))) {
+ d->frameParent = p;
+ // The previous one in the hierarchy will be the viewport.
+ if (prev && isScrollArea)
+ d->frameParent = prev;
+ break;
+ } else {
+ p->installEventFilter(this);
+ prev = p;
+ p = p->parentWidget();
+ }
+ }
+ } else {
+ d->frameParent = p;
+ }
+ d->update();
+ } else {
+ d->widget = 0;
+ hide();
+ }
+}
+
+/*!
+ Returns the currently monitored widget for automatically resize and
+ update.
+
+ \sa QFocusFrame::setWidget()
+*/
+
+QWidget *
+QFocusFrame::widget() const
+{
+ Q_D(const QFocusFrame);
+ return d->widget;
+}
+
+
+/*! \reimp */
+void
+QFocusFrame::paintEvent(QPaintEvent *)
+{
+ Q_D(QFocusFrame);
+ QStylePainter p(this);
+ QStyleOption option;
+ initStyleOption(&option);
+ int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
+ int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
+ QWidgetPrivate *wd = qt_widget_private(d->widget);
+ QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2);
+ p.setClipRect(rect);
+ p.drawControl(QStyle::CE_FocusFrame, option);
+}
+
+
+/*! \reimp */
+bool
+QFocusFrame::eventFilter(QObject *o, QEvent *e)
+{
+ Q_D(QFocusFrame);
+ if(o == d->widget) {
+ switch(e->type()) {
+ case QEvent::Move:
+ case QEvent::Resize:
+ d->updateSize();
+ break;
+ case QEvent::Hide:
+ case QEvent::StyleChange:
+ hide();
+ break;
+ case QEvent::ParentChange:
+ if (d->showFrameAboveWidget) {
+ QWidget *w = d->widget;
+ setWidget(0);
+ setWidget(w);
+ } else {
+ d->update();
+ }
+ break;
+ case QEvent::Show:
+ d->update();
+ show();
+ break;
+ case QEvent::PaletteChange:
+ setPalette(d->widget->palette());
+ break;
+ case QEvent::ZOrderChange:
+ if (style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this))
+ raise();
+ else
+ stackUnder(d->widget);
+ break;
+ case QEvent::Destroy:
+ setWidget(0);
+ break;
+ default:
+ break;
+ }
+ } else if (d->showFrameAboveWidget) {
+ // Handle changes in the parent widgets we are monitoring.
+ switch(e->type()) {
+ case QEvent::Move:
+ case QEvent::Resize:
+ d->updateSize();
+ break;
+ case QEvent::ZOrderChange:
+ raise();
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+/*! \reimp */
+bool QFocusFrame::event(QEvent *e)
+{
+ return QWidget::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qfocusframe.h b/src/widgets/widgets/qfocusframe.h
new file mode 100644
index 0000000000..f4f1d1c854
--- /dev/null
+++ b/src/widgets/widgets/qfocusframe.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFOCUSFRAME_H
+#define QFOCUSFRAME_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFocusFramePrivate;
+class QStyleOption;
+
+class Q_WIDGETS_EXPORT QFocusFrame : public QWidget
+{
+ Q_OBJECT
+public:
+ QFocusFrame(QWidget *parent=0);
+ ~QFocusFrame();
+
+ void setWidget(QWidget *widget);
+ QWidget *widget() const;
+
+protected:
+ bool event(QEvent *e);
+
+ bool eventFilter(QObject *, QEvent *);
+ void paintEvent(QPaintEvent *);
+ void initStyleOption(QStyleOption *option) const;
+
+private:
+ Q_DECLARE_PRIVATE(QFocusFrame)
+ Q_DISABLE_COPY(QFocusFrame)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFOCUSFRAME_H
diff --git a/src/widgets/widgets/qfontcombobox.cpp b/src/widgets/widgets/qfontcombobox.cpp
new file mode 100644
index 0000000000..bd53410f31
--- /dev/null
+++ b/src/widgets/widgets/qfontcombobox.cpp
@@ -0,0 +1,474 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfontcombobox.h"
+
+#ifndef QT_NO_FONTCOMBOBOX
+
+#include <qstringlistmodel.h>
+#include <qitemdelegate.h>
+#include <qlistview.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qapplication.h>
+#include <private/qcombobox_p.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin)
+{
+ *hasLatin = true;
+
+ QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase().writingSystems(font.family());
+// qDebug() << font.family() << writingSystems;
+
+ // this just confuses the algorithm below. Vietnamese is Latin with lots of special chars
+ writingSystems.removeAll(QFontDatabase::Vietnamese);
+
+ QFontDatabase::WritingSystem system = QFontDatabase::Any;
+
+ if (!writingSystems.contains(QFontDatabase::Latin)) {
+ *hasLatin = false;
+ // we need to show something
+ if (writingSystems.count())
+ system = writingSystems.last();
+ } else {
+ writingSystems.removeAll(QFontDatabase::Latin);
+ }
+
+ if (writingSystems.isEmpty())
+ return system;
+
+ if (writingSystems.count() == 1 && writingSystems.at(0) > QFontDatabase::Cyrillic) {
+ system = writingSystems.at(0);
+ return system;
+ }
+
+ if (writingSystems.count() <= 2
+ && writingSystems.last() > QFontDatabase::Armenian
+ && writingSystems.last() < QFontDatabase::Vietnamese) {
+ system = writingSystems.last();
+ return system;
+ }
+
+ if (writingSystems.count() <= 5
+ && writingSystems.last() >= QFontDatabase::SimplifiedChinese
+ && writingSystems.last() <= QFontDatabase::Korean)
+ system = writingSystems.last();
+
+ return system;
+}
+
+class QFontFamilyDelegate : public QAbstractItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit QFontFamilyDelegate(QObject *parent);
+
+ // painting
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+ QIcon truetype;
+ QIcon bitmap;
+ QFontDatabase::WritingSystem writingSystem;
+};
+
+QFontFamilyDelegate::QFontFamilyDelegate(QObject *parent)
+ : QAbstractItemDelegate(parent)
+{
+ truetype = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fonttruetype-16.png"));
+ bitmap = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fontbitmap-16.png"));
+ writingSystem = QFontDatabase::Any;
+}
+
+void QFontFamilyDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QString text = index.data(Qt::DisplayRole).toString();
+ QFont font(option.font);
+ font.setPointSize(QFontInfo(font).pointSize() * 3 / 2);
+ QFont font2 = font;
+ font2.setFamily(text);
+
+ bool hasLatin;
+ QFontDatabase::WritingSystem system = writingSystemForFont(font2, &hasLatin);
+ if (hasLatin)
+ font = font2;
+
+ QRect r = option.rect;
+
+ if (option.state & QStyle::State_Selected) {
+ painter->save();
+ painter->setBrush(option.palette.highlight());
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(option.rect);
+ painter->setPen(QPen(option.palette.highlightedText(), 0));
+ }
+
+ const QIcon *icon = &bitmap;
+ if (QFontDatabase().isSmoothlyScalable(text)) {
+ icon = &truetype;
+ }
+ QSize actualSize = icon->actualSize(r.size());
+
+ icon->paint(painter, r, Qt::AlignLeft|Qt::AlignVCenter);
+ if (option.direction == Qt::RightToLeft)
+ r.setRight(r.right() - actualSize.width() - 4);
+ else
+ r.setLeft(r.left() + actualSize.width() + 4);
+
+ QFont old = painter->font();
+ painter->setFont(font);
+ painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
+
+ if (writingSystem != QFontDatabase::Any)
+ system = writingSystem;
+
+ if (system != QFontDatabase::Any) {
+ int w = painter->fontMetrics().width(text + QLatin1String(" "));
+ painter->setFont(font2);
+ QString sample = QFontDatabase().writingSystemSample(system);
+ if (option.direction == Qt::RightToLeft)
+ r.setRight(r.right() - w);
+ else
+ r.setLeft(r.left() + w);
+ painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, sample);
+ }
+ painter->setFont(old);
+
+ if (option.state & QStyle::State_Selected)
+ painter->restore();
+
+}
+
+QSize QFontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QString text = index.data(Qt::DisplayRole).toString();
+ QFont font(option.font);
+// font.setFamily(text);
+ font.setPointSize(QFontInfo(font).pointSize() * 3/2);
+ QFontMetrics fontMetrics(font);
+ return QSize(fontMetrics.width(text), fontMetrics.height());
+}
+
+
+class QFontComboBoxPrivate : public QComboBoxPrivate
+{
+public:
+ inline QFontComboBoxPrivate() { filters = QFontComboBox::AllFonts; }
+
+ QFontComboBox::FontFilters filters;
+ QFont currentFont;
+
+ void _q_updateModel();
+ void _q_currentChanged(const QString &);
+
+ Q_DECLARE_PUBLIC(QFontComboBox)
+};
+
+
+void QFontComboBoxPrivate::_q_updateModel()
+{
+ Q_Q(QFontComboBox);
+ const int scalableMask = (QFontComboBox::ScalableFonts | QFontComboBox::NonScalableFonts);
+ const int spacingMask = (QFontComboBox::ProportionalFonts | QFontComboBox::MonospacedFonts);
+
+ QStringListModel *m = qobject_cast<QStringListModel *>(q->model());
+ if (!m)
+ return;
+ QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(q->view()->itemDelegate());
+ QFontDatabase::WritingSystem system = delegate ? delegate->writingSystem : QFontDatabase::Any;
+
+ QFontDatabase fdb;
+ QStringList list = fdb.families(system);
+ QStringList result;
+
+ int offset = 0;
+ QFontInfo fi(currentFont);
+
+ for (int i = 0; i < list.size(); ++i) {
+ if ((filters & scalableMask) && (filters & scalableMask) != scalableMask) {
+ if (bool(filters & QFontComboBox::ScalableFonts) != fdb.isSmoothlyScalable(list.at(i)))
+ continue;
+ }
+ if ((filters & spacingMask) && (filters & spacingMask) != spacingMask) {
+ if (bool(filters & QFontComboBox::MonospacedFonts) != fdb.isFixedPitch(list.at(i)))
+ continue;
+ }
+ result += list.at(i);
+ if (list.at(i) == fi.family() || list.at(i).startsWith(fi.family() + QLatin1String(" [")))
+ offset = result.count() - 1;
+ }
+ list = result;
+
+ //we need to block the signals so that the model doesn't emit reset
+ //this prevents the current index from changing
+ //it will be updated just after this
+ ///TODO: we should finda way to avoid blocking signals and have a real update of the model
+ const bool old = m->blockSignals(true);
+ m->setStringList(list);
+ m->blockSignals(old);
+
+ if (list.isEmpty()) {
+ if (currentFont != QFont()) {
+ currentFont = QFont();
+ emit q->currentFontChanged(currentFont);
+ }
+ } else {
+ q->setCurrentIndex(offset);
+ }
+}
+
+
+void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
+{
+ Q_Q(QFontComboBox);
+ if (currentFont.family() != text) {
+ currentFont.setFamily(text);
+ emit q->currentFontChanged(currentFont);
+ }
+}
+
+/*!
+ \class QFontComboBox
+ \brief The QFontComboBox widget is a combobox that lets the user
+ select a font family.
+
+ \since 4.2
+ \ingroup basicwidgets
+
+ The combobox is populated with an alphabetized list of font
+ family names, such as Arial, Helvetica, and Times New Roman.
+ Family names are displayed using the actual font when possible.
+ For fonts such as Symbol, where the name is not representable in
+ the font itself, a sample of the font is displayed next to the
+ family name.
+
+ QFontComboBox is often used in toolbars, in conjunction with a
+ QComboBox for controlling the font size and two \l{QToolButton}s
+ for bold and italic.
+
+ When the user selects a new font, the currentFontChanged() signal
+ is emitted in addition to currentIndexChanged().
+
+ Call setWritingSystem() to tell QFontComboBox to show only fonts
+ that support a given writing system, and setFontFilters() to
+ filter out certain types of fonts as e.g. non scalable fonts or
+ monospaced fonts.
+
+ \image windowsxp-fontcombobox.png Screenshot of QFontComboBox on Windows XP
+
+ \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example}
+*/
+
+/*!
+ \fn void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
+*/
+
+/*!
+ \fn void QFontComboBox::setCurrentFont(const QFont &font);
+*/
+
+/*!
+ Constructs a font combobox with the given \a parent.
+*/
+QFontComboBox::QFontComboBox(QWidget *parent)
+ : QComboBox(*new QFontComboBoxPrivate, parent)
+{
+ Q_D(QFontComboBox);
+ d->currentFont = font();
+ setEditable(true);
+
+ QStringListModel *m = new QStringListModel(this);
+ setModel(m);
+ setItemDelegate(new QFontFamilyDelegate(this));
+ QListView *lview = qobject_cast<QListView*>(view());
+ if (lview)
+ lview->setUniformItemSizes(true);
+ setWritingSystem(QFontDatabase::Any);
+
+ connect(this, SIGNAL(currentIndexChanged(QString)),
+ this, SLOT(_q_currentChanged(QString)));
+
+ connect(qApp, SIGNAL(fontDatabaseChanged()),
+ this, SLOT(_q_updateModel()));
+}
+
+
+/*!
+ Destroys the combobox.
+*/
+QFontComboBox::~QFontComboBox()
+{
+}
+
+/*!
+ \property QFontComboBox::writingSystem
+ \brief the writing system that serves as a filter for the combobox
+
+ If \a script is QFontDatabase::Any (the default), all fonts are
+ listed.
+
+ \sa fontFilters
+*/
+
+void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
+{
+ Q_D(QFontComboBox);
+ QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
+ if (delegate)
+ delegate->writingSystem = script;
+ d->_q_updateModel();
+}
+
+QFontDatabase::WritingSystem QFontComboBox::writingSystem() const
+{
+ QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
+ if (delegate)
+ return delegate->writingSystem;
+ return QFontDatabase::Any;
+}
+
+
+/*!
+ \enum QFontComboBox::FontFilter
+
+ This enum can be used to only show certain types of fonts in the font combo box.
+
+ \value AllFonts Show all fonts
+ \value ScalableFonts Show scalable fonts
+ \value NonScalableFonts Show non scalable fonts
+ \value MonospacedFonts Show monospaced fonts
+ \value ProportionalFonts Show proportional fonts
+*/
+
+/*!
+ \property QFontComboBox::fontFilters
+ \brief the filter for the combobox
+
+ By default, all fonts are listed.
+
+ \sa writingSystem
+*/
+void QFontComboBox::setFontFilters(FontFilters filters)
+{
+ Q_D(QFontComboBox);
+ d->filters = filters;
+ d->_q_updateModel();
+}
+
+QFontComboBox::FontFilters QFontComboBox::fontFilters() const
+{
+ Q_D(const QFontComboBox);
+ return d->filters;
+}
+
+/*!
+ \property QFontComboBox::currentFont
+ \brief the currently selected font
+
+ \sa currentFontChanged(), currentIndex, currentText
+*/
+QFont QFontComboBox::currentFont() const
+{
+ Q_D(const QFontComboBox);
+ return d->currentFont;
+}
+
+void QFontComboBox::setCurrentFont(const QFont &font)
+{
+ Q_D(QFontComboBox);
+ if (font != d->currentFont) {
+ d->currentFont = font;
+ d->_q_updateModel();
+ if (d->currentFont == font) { //else the signal has already be emitted by _q_updateModel
+ emit currentFontChanged(d->currentFont);
+ }
+ }
+}
+
+/*!
+ \fn QFontComboBox::currentFontChanged(const QFont &font)
+
+ This signal is emitted whenever the current font changes, with
+ the new \a font.
+
+ \sa currentFont
+*/
+
+/*!
+ \reimp
+*/
+bool QFontComboBox::event(QEvent *e)
+{
+ if (e->type() == QEvent::Resize) {
+ QListView *lview = qobject_cast<QListView*>(view());
+ if (lview)
+ lview->window()->setFixedWidth(width() * 5 / 3);
+ }
+ return QComboBox::event(e);
+}
+
+/*!
+ \reimp
+*/
+QSize QFontComboBox::sizeHint() const
+{
+ QSize sz = QComboBox::sizeHint();
+ QFontMetrics fm(font());
+ sz.setWidth(fm.width(QLatin1Char('m'))*14);
+ return sz;
+}
+
+QT_END_NAMESPACE
+
+#include "qfontcombobox.moc"
+#include "moc_qfontcombobox.cpp"
+
+#endif // QT_NO_FONTCOMBOBOX
diff --git a/src/widgets/widgets/qfontcombobox.h b/src/widgets/widgets/qfontcombobox.h
new file mode 100644
index 0000000000..b0007207da
--- /dev/null
+++ b/src/widgets/widgets/qfontcombobox.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTCOMBOBOX_H
+#define QFONTCOMBOBOX_H
+
+#include <QtWidgets/qcombobox.h>
+#include <QtGui/qfontdatabase.h>
+
+#ifndef QT_NO_FONTCOMBOBOX
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFontComboBoxPrivate;
+
+class Q_WIDGETS_EXPORT QFontComboBox : public QComboBox
+{
+ Q_OBJECT
+ Q_FLAGS(FontFilters)
+ Q_PROPERTY(QFontDatabase::WritingSystem writingSystem READ writingSystem WRITE setWritingSystem)
+ Q_PROPERTY(FontFilters fontFilters READ fontFilters WRITE setFontFilters)
+ Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged)
+ Q_ENUMS(FontSelection)
+
+public:
+ explicit QFontComboBox(QWidget *parent = 0);
+ ~QFontComboBox();
+
+ void setWritingSystem(QFontDatabase::WritingSystem);
+ QFontDatabase::WritingSystem writingSystem() const;
+
+ enum FontFilter {
+ AllFonts = 0,
+ ScalableFonts = 0x1,
+ NonScalableFonts = 0x2,
+ MonospacedFonts = 0x4,
+ ProportionalFonts = 0x8
+ };
+ Q_DECLARE_FLAGS(FontFilters, FontFilter)
+
+ void setFontFilters(FontFilters filters);
+ FontFilters fontFilters() const;
+
+ QFont currentFont() const;
+ QSize sizeHint() const;
+
+public Q_SLOTS:
+ void setCurrentFont(const QFont &f);
+
+Q_SIGNALS:
+ void currentFontChanged(const QFont &f);
+
+protected:
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QFontComboBox)
+ Q_DECLARE_PRIVATE(QFontComboBox)
+ Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QString &))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateModel())
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFontComboBox::FontFilters)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_FONTCOMBOBOX
+#endif
diff --git a/src/widgets/widgets/qframe.cpp b/src/widgets/widgets/qframe.cpp
new file mode 100644
index 0000000000..083136f9fe
--- /dev/null
+++ b/src/widgets/widgets/qframe.cpp
@@ -0,0 +1,564 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qframe.h"
+#include "qbitmap.h"
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qapplication.h"
+
+#include "qframe_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QFramePrivate::QFramePrivate()
+ : frect(QRect(0, 0, 0, 0)),
+ frameStyle(QFrame::NoFrame | QFrame::Plain),
+ lineWidth(1),
+ midLineWidth(0),
+ frameWidth(0),
+ leftFrameWidth(0), rightFrameWidth(0),
+ topFrameWidth(0), bottomFrameWidth(0)
+{
+}
+
+inline void QFramePrivate::init()
+{
+ setLayoutItemMargins(QStyle::SE_FrameLayoutItem);
+}
+
+/*!
+ \class QFrame
+ \brief The QFrame class is the base class of widgets that can have a frame.
+
+ \ingroup abstractwidgets
+
+
+ QMenu uses this to "raise" the menu above the surrounding
+ screen. QProgressBar has a "sunken" look. QLabel has a flat look.
+ The frames of widgets like these can be changed.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qframe.cpp 0
+
+ The QFrame class can also be used directly for creating simple
+ placeholder frames without any contents.
+
+ The frame style is specified by a \l{QFrame::Shape}{frame shape} and
+ a \l{QFrame::Shadow}{shadow style} that is used to visually separate
+ the frame from surrounding widgets. These properties can be set
+ together using the setFrameStyle() function and read with frameStyle().
+
+ The frame shapes are \l NoFrame, \l Box, \l Panel, \l StyledPanel,
+ HLine and \l VLine; the shadow styles are \l Plain, \l Raised and
+ \l Sunken.
+
+ A frame widget has three attributes that describe the thickness of the
+ border: \l lineWidth, \l midLineWidth, and \l frameWidth.
+
+ \list
+ \o The line width is the width of the frame border. It can be modified
+ to customize the frame's appearance.
+
+ \o The mid-line width specifies the width of an extra line in the
+ middle of the frame, which uses a third color to obtain a special
+ 3D effect. Notice that a mid-line is only drawn for \l Box, \l
+ HLine and \l VLine frames that are raised or sunken.
+
+ \o The frame width is determined by the frame style, and the frameWidth()
+ function is used to obtain the value defined for the style used.
+ \endlist
+
+ The margin between the frame and the contents of the frame can be
+ customized with the QWidget::setContentsMargins() function.
+
+ \target picture
+ This table shows some of the combinations of styles and line widths:
+
+ \image frames.png Table of frame styles
+*/
+
+
+/*!
+ \enum QFrame::Shape
+
+ This enum type defines the shapes of frame available.
+
+ \value NoFrame QFrame draws nothing
+ \value Box QFrame draws a box around its contents
+ \value Panel QFrame draws a panel to make the contents appear
+ raised or sunken
+ \value StyledPanel draws a rectangular panel with a look that
+ depends on the current GUI style. It can be raised or sunken.
+ \value HLine QFrame draws a horizontal line that frames nothing
+ (useful as separator)
+ \value VLine QFrame draws a vertical line that frames nothing
+ (useful as separator)
+ \value WinPanel draws a rectangular panel that can be raised or
+ sunken like those in Windows 2000. Specifying this shape sets
+ the line width to 2 pixels. WinPanel is provided for compatibility.
+ For GUI style independence we recommend using StyledPanel instead.
+
+ \omitvalue GroupBoxPanel
+ \omitvalue ToolBarPanel
+ \omitvalue MenuBarPanel
+ \omitvalue PopupPanel
+ \omitvalue LineEditPanel
+ \omitvalue TabWidgetPanel
+
+ When it does not call QStyle, Shape interacts with QFrame::Shadow,
+ the lineWidth() and the midLineWidth() to create the total result.
+ See the picture of the frames in the main class documentation.
+
+ \sa QFrame::Shadow QFrame::style() QStyle::drawPrimitive()
+*/
+
+
+/*!
+ \enum QFrame::Shadow
+
+ This enum type defines the types of shadow that are used to give
+ a 3D effect to frames.
+
+ \value Plain the frame and contents appear level with the
+ surroundings; draws using the palette QPalette::WindowText color
+ (without any 3D effect)
+
+ \value Raised the frame and contents appear raised; draws a 3D
+ raised line using the light and dark colors of the current color
+ group
+ \value Sunken the frame and contents appear sunken; draws a 3D
+ sunken line using the light and dark colors of the current color
+ group
+
+ Shadow interacts with QFrame::Shape, the lineWidth() and the
+ midLineWidth(). See the picture of the frames in the main class
+ documentation.
+
+ \sa QFrame::Shape lineWidth() midLineWidth()
+*/
+
+/*!
+ \enum QFrame::StyleMask
+
+ This enum defines two constants that can be used to extract the
+ two components of frameStyle():
+
+ \value Shadow_Mask The \l Shadow part of frameStyle()
+ \value Shape_Mask The \l Shape part of frameStyle()
+
+ \omitvalue MShadow
+ \omitvalue MShape
+
+ Normally, you don't need to use these, since frameShadow() and
+ frameShape() already extract the \l Shadow and the \l Shape parts
+ of frameStyle().
+
+ \sa frameStyle(), setFrameStyle()
+*/
+
+/*!
+ Constructs a frame widget with frame style \l NoFrame and a
+ 1-pixel frame width.
+
+ The \a parent and \a f arguments are passed to the QWidget
+ constructor.
+*/
+
+QFrame::QFrame(QWidget* parent, Qt::WindowFlags f)
+ : QWidget(*new QFramePrivate, parent, f)
+{
+ Q_D(QFrame);
+ d->init();
+}
+
+/*! \internal */
+QFrame::QFrame(QFramePrivate &dd, QWidget* parent, Qt::WindowFlags f)
+ : QWidget(dd, parent, f)
+{
+ Q_D(QFrame);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QFrame::QFrame(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QWidget(*new QFramePrivate, parent, f)
+{
+ Q_D(QFrame);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+#endif
+
+/*!
+ Destroys the frame.
+ */
+QFrame::~QFrame()
+{
+}
+
+/*!
+ Returns the frame style.
+
+ The default value is QFrame::Plain.
+
+ \sa setFrameStyle(), frameShape(), frameShadow()
+*/
+int QFrame::frameStyle() const
+{
+ Q_D(const QFrame);
+ return d->frameStyle;
+}
+
+/*!
+ \property QFrame::frameShape
+ \brief the frame shape value from the frame style
+
+ \sa frameStyle(), frameShadow()
+*/
+
+QFrame::Shape QFrame::frameShape() const
+{
+ Q_D(const QFrame);
+ return (Shape) (d->frameStyle & Shape_Mask);
+}
+
+void QFrame::setFrameShape(QFrame::Shape s)
+{
+ Q_D(QFrame);
+ setFrameStyle((d->frameStyle & Shadow_Mask) | s);
+}
+
+
+/*!
+ \property QFrame::frameShadow
+ \brief the frame shadow value from the frame style
+
+ \sa frameStyle(), frameShape()
+*/
+QFrame::Shadow QFrame::frameShadow() const
+{
+ Q_D(const QFrame);
+ return (Shadow) (d->frameStyle & Shadow_Mask);
+}
+
+void QFrame::setFrameShadow(QFrame::Shadow s)
+{
+ Q_D(QFrame);
+ setFrameStyle((d->frameStyle & Shape_Mask) | s);
+}
+
+/*!
+ Sets the frame style to \a style.
+
+ The \a style is the bitwise OR between a frame shape and a frame
+ shadow style. See the picture of the frames in the main class
+ documentation.
+
+ The frame shapes are given in \l{QFrame::Shape} and the shadow
+ styles in \l{QFrame::Shadow}.
+
+ If a mid-line width greater than 0 is specified, an additional
+ line is drawn for \l Raised or \l Sunken \l Box, \l HLine, and \l
+ VLine frames. The mid-color of the current color group is used for
+ drawing middle lines.
+
+ \sa frameStyle()
+*/
+
+void QFrame::setFrameStyle(int style)
+{
+ Q_D(QFrame);
+ if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
+ QSizePolicy sp;
+
+ switch (style & Shape_Mask) {
+ case HLine:
+ sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Line);
+ break;
+ case VLine:
+ sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum, QSizePolicy::Line);
+ break;
+ default:
+ sp = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::Frame);
+ }
+ setSizePolicy(sp);
+ setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ }
+ d->frameStyle = (short)style;
+ update();
+ d->updateFrameWidth();
+}
+
+/*!
+ \property QFrame::lineWidth
+ \brief the line width
+
+ Note that the \e total line width for frames used as separators
+ (\l HLine and \l VLine) is specified by \l frameWidth.
+
+ The default value is 1.
+
+ \sa midLineWidth, frameWidth
+*/
+
+void QFrame::setLineWidth(int w)
+{
+ Q_D(QFrame);
+ if (short(w) == d->lineWidth)
+ return;
+ d->lineWidth = short(w);
+ d->updateFrameWidth();
+}
+
+int QFrame::lineWidth() const
+{
+ Q_D(const QFrame);
+ return d->lineWidth;
+}
+
+/*!
+ \property QFrame::midLineWidth
+ \brief the width of the mid-line
+
+ The default value is 0.
+
+ \sa lineWidth, frameWidth
+*/
+
+void QFrame::setMidLineWidth(int w)
+{
+ Q_D(QFrame);
+ if (short(w) == d->midLineWidth)
+ return;
+ d->midLineWidth = short(w);
+ d->updateFrameWidth();
+}
+
+int QFrame::midLineWidth() const
+{
+ Q_D(const QFrame);
+ return d->midLineWidth;
+}
+
+/*!
+ \internal
+ Updates the frame widths from the style.
+*/
+void QFramePrivate::updateStyledFrameWidths()
+{
+ Q_Q(const QFrame);
+ QStyleOptionFrameV3 opt;
+ opt.initFrom(q);
+ opt.lineWidth = lineWidth;
+ opt.midLineWidth = midLineWidth;
+ opt.frameShape = QFrame::Shape(frameStyle & QFrame::Shape_Mask);
+
+ QRect cr = q->style()->subElementRect(QStyle::SE_ShapedFrameContents, &opt, q);
+ leftFrameWidth = cr.left() - opt.rect.left();
+ topFrameWidth = cr.top() - opt.rect.top();
+ rightFrameWidth = opt.rect.right() - cr.right(),
+ bottomFrameWidth = opt.rect.bottom() - cr.bottom();
+ frameWidth = qMax(qMax(leftFrameWidth, rightFrameWidth),
+ qMax(topFrameWidth, bottomFrameWidth));
+}
+
+/*!
+ \internal
+ Updated the frameWidth parameter.
+*/
+
+void QFramePrivate::updateFrameWidth()
+{
+ Q_Q(QFrame);
+ QRect fr = q->frameRect();
+ updateStyledFrameWidths();
+ q->setFrameRect(fr);
+ setLayoutItemMargins(QStyle::SE_FrameLayoutItem);
+}
+
+/*!
+ \property QFrame::frameWidth
+ \brief the width of the frame that is drawn.
+
+ Note that the frame width depends on the \l{QFrame::setFrameStyle()}{frame style},
+ not only the line width and the mid-line width. For example, the style specified
+ by \l NoFrame always has a frame width of 0, whereas the style \l Panel has a
+ frame width equivalent to the line width.
+
+ \sa lineWidth(), midLineWidth(), frameStyle()
+*/
+int QFrame::frameWidth() const
+{
+ Q_D(const QFrame);
+ return d->frameWidth;
+}
+
+
+/*!
+ \property QFrame::frameRect
+ \brief the frame's rectangle
+
+ The frame's rectangle is the rectangle the frame is drawn in. By
+ default, this is the entire widget. Setting the rectangle does
+ does \e not cause a widget update. The frame rectangle is
+ automatically adjusted when the widget changes size.
+
+ If you set the rectangle to a null rectangle (for example,
+ QRect(0, 0, 0, 0)), then the resulting frame rectangle is
+ equivalent to the \link QWidget::rect() widget rectangle\endlink.
+*/
+
+QRect QFrame::frameRect() const
+{
+ Q_D(const QFrame);
+ QRect fr = contentsRect();
+ fr.adjust(-d->leftFrameWidth, -d->topFrameWidth, d->rightFrameWidth, d->bottomFrameWidth);
+ return fr;
+}
+
+void QFrame::setFrameRect(const QRect &r)
+{
+ Q_D(QFrame);
+ QRect cr = r.isValid() ? r : rect();
+ cr.adjust(d->leftFrameWidth, d->topFrameWidth, -d->rightFrameWidth, -d->bottomFrameWidth);
+ setContentsMargins(cr.left(), cr.top(), rect().right() - cr.right(), rect().bottom() - cr.bottom());
+}
+
+/*!\reimp
+*/
+QSize QFrame::sizeHint() const
+{
+ Q_D(const QFrame);
+ // Returns a size hint for the frame - for HLine and VLine
+ // shapes, this is stretchable one way and 3 pixels wide the
+ // other. For other shapes, QWidget::sizeHint() is used.
+ switch (d->frameStyle & Shape_Mask) {
+ case HLine:
+ return QSize(-1,3);
+ case VLine:
+ return QSize(3,-1);
+ default:
+ return QWidget::sizeHint();
+ }
+}
+
+/*!\reimp
+*/
+
+void QFrame::paintEvent(QPaintEvent *)
+{
+ QPainter paint(this);
+ drawFrame(&paint);
+}
+
+/*!
+ \internal
+
+ Mostly for the sake of Q3Frame
+ */
+void QFrame::drawFrame(QPainter *p)
+{
+ Q_D(QFrame);
+ QStyleOptionFrameV3 opt;
+ opt.init(this);
+ int frameShape = d->frameStyle & QFrame::Shape_Mask;
+ int frameShadow = d->frameStyle & QFrame::Shadow_Mask;
+ opt.frameShape = Shape(int(opt.frameShape) | frameShape);
+ opt.rect = frameRect();
+ switch (frameShape) {
+ case QFrame::Box:
+ case QFrame::HLine:
+ case QFrame::VLine:
+ case QFrame::StyledPanel:
+ case QFrame::Panel:
+ opt.lineWidth = d->lineWidth;
+ opt.midLineWidth = d->midLineWidth;
+ break;
+ default:
+ // most frame styles do not handle customized line and midline widths
+ // (see updateFrameWidth()).
+ opt.lineWidth = d->frameWidth;
+ break;
+ }
+
+ if (frameShadow == Sunken)
+ opt.state |= QStyle::State_Sunken;
+ else if (frameShadow == Raised)
+ opt.state |= QStyle::State_Raised;
+
+ style()->drawControl(QStyle::CE_ShapedFrame, &opt, p, this);
+}
+
+
+/*!\reimp
+ */
+void QFrame::changeEvent(QEvent *ev)
+{
+ Q_D(QFrame);
+ if (ev->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || ev->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->updateFrameWidth();
+ QWidget::changeEvent(ev);
+}
+
+/*! \reimp */
+bool QFrame::event(QEvent *e)
+{
+ if (e->type() == QEvent::ParentChange)
+ d_func()->updateFrameWidth();
+ bool result = QWidget::event(e);
+ //this has to be done after the widget has been polished
+ if (e->type() == QEvent::Polish)
+ d_func()->updateFrameWidth();
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qframe.h b/src/widgets/widgets/qframe.h
new file mode 100644
index 0000000000..80d41365cd
--- /dev/null
+++ b/src/widgets/widgets/qframe.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFRAME_H
+#define QFRAME_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFramePrivate;
+
+class Q_WIDGETS_EXPORT QFrame : public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(Shape Shadow)
+ Q_PROPERTY(Shape frameShape READ frameShape WRITE setFrameShape)
+ Q_PROPERTY(Shadow frameShadow READ frameShadow WRITE setFrameShadow)
+ Q_PROPERTY(int lineWidth READ lineWidth WRITE setLineWidth)
+ Q_PROPERTY(int midLineWidth READ midLineWidth WRITE setMidLineWidth)
+ Q_PROPERTY(int frameWidth READ frameWidth)
+ Q_PROPERTY(QRect frameRect READ frameRect WRITE setFrameRect DESIGNABLE false)
+
+public:
+ explicit QFrame(QWidget* parent = 0, Qt::WindowFlags f = 0);
+ ~QFrame();
+
+ int frameStyle() const;
+ void setFrameStyle(int);
+
+ int frameWidth() const;
+
+ QSize sizeHint() const;
+
+ enum Shape {
+ NoFrame = 0, // no frame
+ Box = 0x0001, // rectangular box
+ Panel = 0x0002, // rectangular panel
+ WinPanel = 0x0003, // rectangular panel (Windows)
+ HLine = 0x0004, // horizontal line
+ VLine = 0x0005, // vertical line
+ StyledPanel = 0x0006 // rectangular panel depending on the GUI style
+
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ ,PopupPanel = StyledPanel, // rectangular panel depending on the GUI style
+ MenuBarPanel = StyledPanel,
+ ToolBarPanel = StyledPanel,
+ LineEditPanel = StyledPanel,
+ TabWidgetPanel = StyledPanel,
+ GroupBoxPanel = StyledPanel
+#endif
+ };
+ enum Shadow {
+ Plain = 0x0010, // plain line
+ Raised = 0x0020, // raised shadow effect
+ Sunken = 0x0030 // sunken shadow effect
+ };
+
+ enum StyleMask {
+ Shadow_Mask = 0x00f0, // mask for the shadow
+ Shape_Mask = 0x000f // mask for the shape
+#if defined(QT3_SUPPORT)
+ ,MShadow = Shadow_Mask,
+ MShape = Shape_Mask
+#endif
+ };
+
+ Shape frameShape() const;
+ void setFrameShape(Shape);
+ Shadow frameShadow() const;
+ void setFrameShadow(Shadow);
+
+ int lineWidth() const;
+ void setLineWidth(int);
+
+ int midLineWidth() const;
+ void setMidLineWidth(int);
+
+ QRect frameRect() const;
+ void setFrameRect(const QRect &);
+
+protected:
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *);
+ void changeEvent(QEvent *);
+ void drawFrame(QPainter *);
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QFrame(QWidget* parent, const char* name, Qt::WindowFlags f = 0);
+#endif
+
+protected:
+ QFrame(QFramePrivate &dd, QWidget* parent = 0, Qt::WindowFlags f = 0);
+
+private:
+ Q_DISABLE_COPY(QFrame)
+ Q_DECLARE_PRIVATE(QFrame)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFRAME_H
diff --git a/src/widgets/widgets/qframe_p.h b/src/widgets/widgets/qframe_p.h
new file mode 100644
index 0000000000..8825abaf92
--- /dev/null
+++ b/src/widgets/widgets/qframe_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFRAME_P_H
+#define QFRAME_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/qwidget_p.h"
+#include "qframe.h"
+
+QT_BEGIN_NAMESPACE
+
+class QFramePrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QFrame)
+public:
+ QFramePrivate();
+
+ void updateFrameWidth();
+ void updateStyledFrameWidths();
+
+ QRect frect;
+ int frameStyle;
+ short lineWidth;
+ short midLineWidth;
+ short frameWidth;
+ short leftFrameWidth, rightFrameWidth;
+ short topFrameWidth, bottomFrameWidth;
+
+ inline void init();
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QFRAME_P_H
diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp
new file mode 100644
index 0000000000..56fb2dd412
--- /dev/null
+++ b/src/widgets/widgets/qgroupbox.cpp
@@ -0,0 +1,781 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgroupbox.h"
+#ifndef QT_NO_GROUPBOX
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qlayout.h"
+#include "qradiobutton.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qstylepainter.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include <private/qwidget_p.h>
+
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGroupBoxPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QGroupBox)
+
+public:
+ void skip();
+ void init();
+ void calculateFrame();
+ QString title;
+ int align;
+#ifndef QT_NO_SHORTCUT
+ int shortcutId;
+#endif
+
+ void _q_fixFocus(Qt::FocusReason reason);
+ void _q_setChildrenEnabled(bool b);
+ void click();
+ bool flat;
+ bool checkable;
+ bool checked;
+ bool hover;
+ bool overCheckBox;
+ QStyle::SubControl pressedControl;
+};
+
+/*!
+ Initialize \a option with the values from this QGroupBox. This method
+ is useful for subclasses when they need a QStyleOptionGroupBox, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QGroupBox::initStyleOption(QStyleOptionGroupBox *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QGroupBox);
+ option->initFrom(this);
+ option->text = d->title;
+ option->lineWidth = 1;
+ option->midLineWidth = 0;
+ option->textAlignment = Qt::Alignment(d->align);
+ option->activeSubControls |= d->pressedControl;
+ option->subControls = QStyle::SC_GroupBoxFrame;
+
+ if (d->hover)
+ option->state |= QStyle::State_MouseOver;
+ else
+ option->state &= ~QStyle::State_MouseOver;
+
+ if (d->flat)
+ option->features |= QStyleOptionFrameV2::Flat;
+
+ if (d->checkable) {
+ option->subControls |= QStyle::SC_GroupBoxCheckBox;
+ option->state |= (d->checked ? QStyle::State_On : QStyle::State_Off);
+ if ((d->pressedControl == QStyle::SC_GroupBoxCheckBox
+ || d->pressedControl == QStyle::SC_GroupBoxLabel) && (d->hover || d->overCheckBox))
+ option->state |= QStyle::State_Sunken;
+ }
+
+ if (!option->palette.isBrushSet(isEnabled() ? QPalette::Active :
+ QPalette::Disabled, QPalette::WindowText))
+ option->textColor = QColor(style()->styleHint(QStyle::SH_GroupBox_TextLabelColor,
+ option, this));
+
+ if (!d->title.isEmpty())
+ option->subControls |= QStyle::SC_GroupBoxLabel;
+}
+
+void QGroupBoxPrivate::click()
+{
+ Q_Q(QGroupBox);
+
+ QPointer<QGroupBox> guard(q);
+ q->setChecked(!checked);
+ if (!guard)
+ return;
+ emit q->clicked(checked);
+}
+
+/*!
+ \class QGroupBox
+ \brief The QGroupBox widget provides a group box frame with a title.
+
+ \ingroup organizers
+ \ingroup geomanagement
+
+ A group box provides a frame, a title and a keyboard shortcut, and
+ displays various other widgets inside itself. The title is on top,
+ the keyboard shortcut moves keyboard focus to one of the group
+ box's child widgets.
+
+ QGroupBox also lets you set the \l title (normally set in the
+ constructor) and the title's \l alignment. Group boxes can be
+ \l checkable; child widgets in checkable group boxes are enabled or
+ disabled depending on whether or not the group box is \l checked.
+
+ You can minimize the space consumption of a group box by enabling
+ the \l flat property. In most \l{QStyle}{styles}, enabling this
+ property results in the removal of the left, right and bottom
+ edges of the frame.
+
+ QGroupBox doesn't automatically lay out the child widgets (which
+ are often \l{QCheckBox}es or \l{QRadioButton}s but can be any
+ widgets). The following example shows how we can set up a
+ QGroupBox with a layout:
+
+ \snippet examples/widgets/groupbox/window.cpp 2
+
+ \table 100%
+ \row \o \inlineimage windowsxp-groupbox.png Screenshot of a Windows XP style group box
+ \o \inlineimage macintosh-groupbox.png Screenshot of a Macintosh style group box
+ \o \inlineimage plastique-groupbox.png Screenshot of a Plastique style group box
+ \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} group box.
+ \o A \l{Macintosh Style Widget Gallery}{Macintosh style} group box.
+ \o A \l{Plastique Style Widget Gallery}{Plastique style} group box.
+ \endtable
+
+ \sa QButtonGroup, {Group Box Example}
+*/
+
+
+
+/*!
+ Constructs a group box widget with the given \a parent but with no title.
+*/
+
+QGroupBox::QGroupBox(QWidget *parent)
+ : QWidget(*new QGroupBoxPrivate, parent, 0)
+{
+ Q_D(QGroupBox);
+ d->init();
+}
+
+/*!
+ Constructs a group box with the given \a title and \a parent.
+*/
+
+QGroupBox::QGroupBox(const QString &title, QWidget *parent)
+ : QWidget(*new QGroupBoxPrivate, parent, 0)
+{
+ Q_D(QGroupBox);
+ d->init();
+ setTitle(title);
+}
+
+
+/*!
+ Destroys the group box.
+*/
+QGroupBox::~QGroupBox()
+{
+}
+
+void QGroupBoxPrivate::init()
+{
+ Q_Q(QGroupBox);
+ align = Qt::AlignLeft;
+#ifndef QT_NO_SHORTCUT
+ shortcutId = 0;
+#endif
+ flat = false;
+ checkable = false;
+ checked = true;
+ hover = false;
+ overCheckBox = false;
+ pressedControl = QStyle::SC_None;
+ calculateFrame();
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
+ QSizePolicy::GroupBox));
+}
+
+void QGroupBox::setTitle(const QString &title)
+{
+ Q_D(QGroupBox);
+ if (d->title == title) // no change
+ return;
+ d->title = title;
+#ifndef QT_NO_SHORTCUT
+ releaseShortcut(d->shortcutId);
+ d->shortcutId = grabShortcut(QKeySequence::mnemonic(title));
+#endif
+ d->calculateFrame();
+
+ update();
+ updateGeometry();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+/*!
+ \property QGroupBox::title
+ \brief the group box title text
+
+ The group box title text will have a keyboard shortcut if the title
+ contains an ampersand ('&') followed by a letter.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qgroupbox.cpp 0
+
+ In the example above, \key Alt+U moves the keyboard focus to the
+ group box. See the \l {QShortcut#mnemonic}{QShortcut}
+ documentation for details (to display an actual ampersand, use
+ '&&').
+
+ There is no default title text.
+
+ \sa alignment
+*/
+
+QString QGroupBox::title() const
+{
+ Q_D(const QGroupBox);
+ return d->title;
+}
+
+/*!
+ \property QGroupBox::alignment
+ \brief the alignment of the group box title.
+
+ Most styles place the title at the top of the frame. The horizontal
+ alignment of the title can be specified using single values from
+ the following list:
+
+ \list
+ \i Qt::AlignLeft aligns the title text with the left-hand side of the group box.
+ \i Qt::AlignRight aligns the title text with the right-hand side of the group box.
+ \i Qt::AlignHCenter aligns the title text with the horizontal center of the group box.
+ \endlist
+
+ The default alignment is Qt::AlignLeft.
+
+ \sa Qt::Alignment
+*/
+Qt::Alignment QGroupBox::alignment() const
+{
+ Q_D(const QGroupBox);
+ return QFlag(d->align);
+}
+
+void QGroupBox::setAlignment(int alignment)
+{
+ Q_D(QGroupBox);
+ d->align = alignment;
+ updateGeometry();
+ update();
+}
+
+/*! \reimp
+*/
+void QGroupBox::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+}
+
+/*! \reimp
+*/
+
+void QGroupBox::paintEvent(QPaintEvent *)
+{
+ QStylePainter paint(this);
+ QStyleOptionGroupBox option;
+ initStyleOption(&option);
+ paint.drawComplexControl(QStyle::CC_GroupBox, option);
+}
+
+/*! \reimp */
+bool QGroupBox::event(QEvent *e)
+{
+ Q_D(QGroupBox);
+#ifndef QT_NO_SHORTCUT
+ if (e->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ if (se->shortcutId() == d->shortcutId) {
+ if (!isCheckable()) {
+ d->_q_fixFocus(Qt::ShortcutFocusReason);
+ } else {
+ d->click();
+ setFocus(Qt::ShortcutFocusReason);
+ }
+ return true;
+ }
+ }
+#endif
+ QStyleOptionGroupBox box;
+ initStyleOption(&box);
+ switch (e->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove: {
+ QStyle::SubControl control = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
+ static_cast<QHoverEvent *>(e)->pos(),
+ this);
+ bool oldHover = d->hover;
+ d->hover = d->checkable && (control == QStyle::SC_GroupBoxLabel || control == QStyle::SC_GroupBoxCheckBox);
+ if (oldHover != d->hover) {
+ QRect rect = style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this)
+ | style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxLabel, this);
+ update(rect);
+ }
+ return true;
+ }
+ case QEvent::HoverLeave:
+ d->hover = false;
+ if (d->checkable) {
+ QRect rect = style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this)
+ | style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxLabel, this);
+ update(rect);
+ }
+ return true;
+ case QEvent::KeyPress: {
+ QKeyEvent *k = static_cast<QKeyEvent*>(e);
+ if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
+ d->pressedControl = QStyle::SC_GroupBoxCheckBox;
+ update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
+ return true;
+ }
+ break;
+ }
+ case QEvent::KeyRelease: {
+ QKeyEvent *k = static_cast<QKeyEvent*>(e);
+ if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
+ bool toggle = (d->pressedControl == QStyle::SC_GroupBoxLabel
+ || d->pressedControl == QStyle::SC_GroupBoxCheckBox);
+ d->pressedControl = QStyle::SC_None;
+ if (toggle)
+ d->click();
+ return true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::event(e);
+}
+
+/*!\reimp */
+void QGroupBox::childEvent(QChildEvent *c)
+{
+ Q_D(QGroupBox);
+ if (c->type() != QEvent::ChildAdded || !c->child()->isWidgetType())
+ return;
+ QWidget *w = (QWidget*)c->child();
+ if (d->checkable) {
+ if (d->checked) {
+ if (!w->testAttribute(Qt::WA_ForceDisabled))
+ w->setEnabled(true);
+ } else {
+ if (w->isEnabled()) {
+ w->setEnabled(false);
+ w->setAttribute(Qt::WA_ForceDisabled, false);
+ }
+ }
+ }
+}
+
+
+/*!
+ \internal
+
+ This private slot finds a widget in this group box that can accept
+ focus, and gives the focus to that widget.
+*/
+
+void QGroupBoxPrivate::_q_fixFocus(Qt::FocusReason reason)
+{
+ Q_Q(QGroupBox);
+ QWidget *fw = q->focusWidget();
+ if (!fw || fw == q) {
+ QWidget * best = 0;
+ QWidget * candidate = 0;
+ QWidget * w = q;
+ while ((w = w->nextInFocusChain()) != q) {
+ if (q->isAncestorOf(w) && (w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus && w->isVisibleTo(q)) {
+ if (!best && qobject_cast<QRadioButton*>(w) && ((QRadioButton*)w)->isChecked())
+ // we prefer a checked radio button or a widget that
+ // already has focus, if there is one
+ best = w;
+ else
+ if (!candidate)
+ // but we'll accept anything that takes focus
+ candidate = w;
+ }
+ }
+ if (best)
+ fw = best;
+ else if (candidate)
+ fw = candidate;
+ }
+ if (fw)
+ fw->setFocus(reason);
+}
+
+/*
+ Sets the right frame rect depending on the title.
+*/
+void QGroupBoxPrivate::calculateFrame()
+{
+ Q_Q(QGroupBox);
+ QStyleOptionGroupBox box;
+ q->initStyleOption(&box);
+ QRect contentsRect = q->style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxContents, q);
+ q->setContentsMargins(contentsRect.left() - box.rect.left(), contentsRect.top() - box.rect.top(),
+ box.rect.right() - contentsRect.right(), box.rect.bottom() - contentsRect.bottom());
+ setLayoutItemMargins(QStyle::SE_GroupBoxLayoutItem, &box);
+}
+
+/*! \reimp
+ */
+void QGroupBox::focusInEvent(QFocusEvent *fe)
+{ // note no call to super
+ Q_D(QGroupBox);
+ if (focusPolicy() == Qt::NoFocus) {
+ d->_q_fixFocus(fe->reason());
+ } else {
+ QWidget::focusInEvent(fe);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+QSize QGroupBox::minimumSizeHint() const
+{
+ Q_D(const QGroupBox);
+ QStyleOptionGroupBox option;
+ initStyleOption(&option);
+
+ QFontMetrics metrics(fontMetrics());
+
+ int baseWidth = metrics.width(d->title) + metrics.width(QLatin1Char(' '));
+ int baseHeight = metrics.height();
+ if (d->checkable) {
+ baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth);
+ baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing);
+ baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight));
+ }
+
+ QSize size = style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), this);
+ return size.expandedTo(QWidget::minimumSizeHint());
+}
+
+/*!
+ \property QGroupBox::flat
+ \brief whether the group box is painted flat or has a frame
+
+ A group box usually consists of a surrounding frame with a title
+ at the top. If this property is enabled, only the top part of the frame is
+ drawn in most styles; otherwise the whole frame is drawn.
+
+ By default, this property is disabled; i.e. group boxes are not flat unless
+ explicitly specified.
+
+ \bold{Note:} In some styles, flat and non-flat group boxes have similar
+ representations and may not be as distinguishable as they are in other
+ styles.
+
+ \sa title
+*/
+bool QGroupBox::isFlat() const
+{
+ Q_D(const QGroupBox);
+ return d->flat;
+}
+
+void QGroupBox::setFlat(bool b)
+{
+ Q_D(QGroupBox);
+ if (d->flat == b)
+ return;
+ d->flat = b;
+ updateGeometry();
+ update();
+}
+
+
+/*!
+ \property QGroupBox::checkable
+ \brief whether the group box has a checkbox in its title
+
+ If this property is true, the group box displays its title using
+ a checkbox in place of an ordinary label. If the checkbox is checked,
+ the group box's children are enabled; otherwise they are disabled and
+ inaccessible.
+
+ By default, group boxes are not checkable.
+
+ If this property is enabled for a group box, it will also be initially
+ checked to ensure that its contents are enabled.
+
+ \sa checked
+*/
+void QGroupBox::setCheckable(bool checkable)
+{
+ Q_D(QGroupBox);
+
+ bool wasCheckable = d->checkable;
+ d->checkable = checkable;
+
+ if (checkable) {
+ setChecked(true);
+ if (!wasCheckable) {
+ setFocusPolicy(Qt::StrongFocus);
+ d->_q_setChildrenEnabled(true);
+ updateGeometry();
+ }
+ } else {
+ if (wasCheckable) {
+ setFocusPolicy(Qt::NoFocus);
+ d->_q_setChildrenEnabled(true);
+ updateGeometry();
+ }
+ d->_q_setChildrenEnabled(true);
+ }
+
+ if (wasCheckable != checkable) {
+ d->calculateFrame();
+ update();
+ }
+}
+
+bool QGroupBox::isCheckable() const
+{
+ Q_D(const QGroupBox);
+ return d->checkable;
+}
+
+
+bool QGroupBox::isChecked() const
+{
+ Q_D(const QGroupBox);
+ return d->checkable && d->checked;
+}
+
+
+/*!
+ \fn void QGroupBox::toggled(bool on)
+
+ If the group box is checkable, this signal is emitted when the check box
+ is toggled. \a on is true if the check box is checked; otherwise it is false.
+
+ \sa checkable
+*/
+
+
+/*!
+ \fn void QGroupBox::clicked(bool checked)
+ \since 4.2
+
+ This signal is emitted when the check box is activated (i.e. pressed down
+ then released while the mouse cursor is inside the button), or when the
+ shortcut key is typed, Notably, this signal is \e not emitted if you call
+ setChecked().
+
+ If the check box is checked \a checked is true; it is false if the check
+ box is unchecked.
+
+ \sa checkable, toggled(), checked
+*/
+
+/*!
+ \property QGroupBox::checked
+ \brief whether the group box is checked
+
+ If the group box is checkable, it is displayed with a check box.
+ If the check box is checked, the group box's children are enabled;
+ otherwise the children are disabled and are inaccessible to the user.
+
+ By default, checkable group boxes are also checked.
+
+ \sa checkable
+*/
+void QGroupBox::setChecked(bool b)
+{
+ Q_D(QGroupBox);
+ if (d->checkable && b != d->checked) {
+ update();
+ d->checked = b;
+ d->_q_setChildrenEnabled(b);
+ emit toggled(b);
+ }
+}
+
+/*
+ sets all children of the group box except the qt_groupbox_checkbox
+ to either disabled/enabled
+*/
+void QGroupBoxPrivate::_q_setChildrenEnabled(bool b)
+{
+ Q_Q(QGroupBox);
+ QObjectList childList = q->children();
+ for (int i = 0; i < childList.size(); ++i) {
+ QObject *o = childList.at(i);
+ if (o->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(o);
+ if (b) {
+ if (!w->testAttribute(Qt::WA_ForceDisabled))
+ w->setEnabled(true);
+ } else {
+ if (w->isEnabled()) {
+ w->setEnabled(false);
+ w->setAttribute(Qt::WA_ForceDisabled, false);
+ }
+ }
+ }
+ }
+}
+
+/*! \reimp */
+void QGroupBox::changeEvent(QEvent *ev)
+{
+ Q_D(QGroupBox);
+ if (ev->type() == QEvent::EnabledChange) {
+ if (d->checkable && isEnabled()) {
+ // we are being enabled - disable children
+ if (!d->checked)
+ d->_q_setChildrenEnabled(false);
+ }
+ } else if (ev->type() == QEvent::FontChange
+#ifdef Q_WS_MAC
+ || ev->type() == QEvent::MacSizeChange
+#endif
+ || ev->type() == QEvent::StyleChange) {
+ d->calculateFrame();
+ }
+ QWidget::changeEvent(ev);
+}
+
+/*! \reimp */
+void QGroupBox::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+
+ Q_D(QGroupBox);
+ QStyleOptionGroupBox box;
+ initStyleOption(&box);
+ d->pressedControl = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
+ event->pos(), this);
+ if (d->checkable && (d->pressedControl & (QStyle::SC_GroupBoxCheckBox | QStyle::SC_GroupBoxLabel))) {
+ d->overCheckBox = true;
+ update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
+ }
+}
+
+/*! \reimp */
+void QGroupBox::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QGroupBox);
+ QStyleOptionGroupBox box;
+ initStyleOption(&box);
+ QStyle::SubControl pressed = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
+ event->pos(), this);
+ bool oldOverCheckBox = d->overCheckBox;
+ d->overCheckBox = (pressed == QStyle::SC_GroupBoxCheckBox || pressed == QStyle::SC_GroupBoxLabel);
+ if (d->checkable && (d->pressedControl == QStyle::SC_GroupBoxCheckBox || d->pressedControl == QStyle::SC_GroupBoxLabel)
+ && (d->overCheckBox != oldOverCheckBox))
+ update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
+}
+
+/*! \reimp */
+void QGroupBox::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+
+ Q_D(QGroupBox);
+ QStyleOptionGroupBox box;
+ initStyleOption(&box);
+ QStyle::SubControl released = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
+ event->pos(), this);
+ bool toggle = d->checkable && (released == QStyle::SC_GroupBoxLabel
+ || released == QStyle::SC_GroupBoxCheckBox);
+ d->pressedControl = QStyle::SC_None;
+ d->overCheckBox = false;
+ if (toggle)
+ d->click();
+ else if (d->checkable)
+ update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QGroupBox::QGroupBox(QWidget *parent, const char *name)
+ : QWidget(*new QGroupBoxPrivate, parent, 0)
+{
+ Q_D(QGroupBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QGroupBox::QGroupBox(const QString &title, QWidget *parent, const char *name)
+ : QWidget(*new QGroupBoxPrivate, parent, 0)
+{
+ Q_D(QGroupBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+ setTitle(title);
+}
+#endif // QT3_SUPPORT
+
+QT_END_NAMESPACE
+
+#include "moc_qgroupbox.cpp"
+
+#endif //QT_NO_GROUPBOX
diff --git a/src/widgets/widgets/qgroupbox.h b/src/widgets/widgets/qgroupbox.h
new file mode 100644
index 0000000000..fba094d303
--- /dev/null
+++ b/src/widgets/widgets/qgroupbox.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGROUPBOX_H
+#define QGROUPBOX_H
+
+#include <QtWidgets/qframe.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_GROUPBOX
+
+class QGroupBoxPrivate;
+class QStyleOptionGroupBox;
+class Q_WIDGETS_EXPORT QGroupBox : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString title READ title WRITE setTitle)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled USER true)
+public:
+ explicit QGroupBox(QWidget* parent=0);
+ explicit QGroupBox(const QString &title, QWidget* parent=0);
+ ~QGroupBox();
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(int alignment);
+
+ QSize minimumSizeHint() const;
+
+ bool isFlat() const;
+ void setFlat(bool flat);
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+ bool isChecked() const;
+
+public Q_SLOTS:
+ void setChecked(bool checked);
+
+Q_SIGNALS:
+ void clicked(bool checked = false);
+ void toggled(bool);
+
+protected:
+ bool event(QEvent *event);
+ void childEvent(QChildEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void focusInEvent(QFocusEvent *event);
+ void changeEvent(QEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void initStyleOption(QStyleOptionGroupBox *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QGroupBox(QWidget* parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QGroupBox(const QString &title, QWidget* parent, const char* name);
+#endif
+
+private:
+ Q_DISABLE_COPY(QGroupBox)
+ Q_DECLARE_PRIVATE(QGroupBox)
+ Q_PRIVATE_SLOT(d_func(), void _q_setChildrenEnabled(bool b))
+};
+
+#endif // QT_NO_GROUPBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGROUPBOX_H
diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp
new file mode 100644
index 0000000000..b122632e44
--- /dev/null
+++ b/src/widgets/widgets/qlabel.cpp
@@ -0,0 +1,1734 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpainter.h"
+#include "qevent.h"
+#include "qdrawutil.h"
+#include "qapplication.h"
+#include "qabstractbutton.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include <limits.h>
+#include "qaction.h"
+#include "qclipboard.h"
+#include <qdebug.h>
+#include <qurl.h>
+#include "qlabel_p.h"
+#include "private/qstylesheetstyle_p.h"
+#include <qmath.h>
+
+#ifndef QT_NO_ACCESSIBILITY
+#include <qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QLabel
+ \brief The QLabel widget provides a text or image display.
+
+ \ingroup basicwidgets
+
+ QLabel is used for displaying text or an image. No user
+ interaction functionality is provided. The visual appearance of
+ the label can be configured in various ways, and it can be used
+ for specifying a focus mnemonic key for another widget.
+
+ A QLabel can contain any of the following content types:
+
+ \table
+ \header \o Content \o Setting
+ \row \o Plain text
+ \o Pass a QString to setText().
+ \row \o Rich text
+ \o Pass a QString that contains rich text to setText().
+ \row \o A pixmap
+ \o Pass a QPixmap to setPixmap().
+ \row \o A movie
+ \o Pass a QMovie to setMovie().
+ \row \o A number
+ \o Pass an \e int or a \e double to setNum(), which converts
+ the number to plain text.
+ \row \o Nothing
+ \o The same as an empty plain text. This is the default. Set
+ by clear().
+ \endtable
+
+ \warning When passing a QString to the constructor or calling setText(),
+ make sure to sanitize your input, as QLabel tries to guess whether it
+ displays the text as plain text or as rich text. You may want to call
+ setTextFormat() explicitly, e.g. in case you expect the text to be in
+ plain format but cannot control the text source (for instance when
+ displaying data loaded from the Web).
+
+ When the content is changed using any of these functions, any
+ previous content is cleared.
+
+ By default, labels display \l{alignment}{left-aligned, vertically-centered}
+ text and images, where any tabs in the text to be displayed are
+ \l{Qt::TextExpandTabs}{automatically expanded}. However, the look
+ of a QLabel can be adjusted and fine-tuned in several ways.
+
+ The positioning of the content within the QLabel widget area can
+ be tuned with setAlignment() and setIndent(). Text content can
+ also wrap lines along word boundaries with setWordWrap(). For
+ example, this code sets up a sunken panel with a two-line text in
+ the bottom right corner (both lines being flush with the right
+ side of the label):
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 0
+
+ The properties and functions QLabel inherits from QFrame can also
+ be used to specify the widget frame to be used for any given label.
+
+ A QLabel is often used as a label for an interactive widget. For
+ this use QLabel provides a useful mechanism for adding an
+ mnemonic (see QKeySequence) that will set the keyboard focus to
+ the other widget (called the QLabel's "buddy"). For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 1
+
+ In this example, keyboard focus is transferred to the label's
+ buddy (the QLineEdit) when the user presses Alt+P. If the buddy
+ was a button (inheriting from QAbstractButton), triggering the
+ mnemonic would emulate a button click.
+
+ \table 100%
+ \row
+ \o \inlineimage macintosh-label.png Screenshot of a Macintosh style label
+ \o A label shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row
+ \o \inlineimage plastique-label.png Screenshot of a Plastique style label
+ \o A label shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \row
+ \o \inlineimage windowsxp-label.png Screenshot of a Windows XP style label
+ \o A label shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \endtable
+
+ \sa QLineEdit, QTextEdit, QPixmap, QMovie,
+ {fowler}{GUI Design Handbook: Label}
+*/
+
+#ifndef QT_NO_PICTURE
+/*!
+ Returns the label's picture or 0 if the label doesn't have a
+ picture.
+*/
+
+const QPicture *QLabel::picture() const
+{
+ Q_D(const QLabel);
+ return d->picture;
+}
+#endif
+
+
+/*!
+ Constructs an empty label.
+
+ The \a parent and widget flag \a f, arguments are passed
+ to the QFrame constructor.
+
+ \sa setAlignment(), setFrameStyle(), setIndent()
+*/
+QLabel::QLabel(QWidget *parent, Qt::WindowFlags f)
+ : QFrame(*new QLabelPrivate(), parent, f)
+{
+ Q_D(QLabel);
+ d->init();
+}
+
+/*!
+ Constructs a label that displays the text, \a text.
+
+ The \a parent and widget flag \a f, arguments are passed
+ to the QFrame constructor.
+
+ \sa setText(), setAlignment(), setFrameStyle(), setIndent()
+*/
+QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags f)
+ : QFrame(*new QLabelPrivate(), parent, f)
+{
+ Q_D(QLabel);
+ d->init();
+ setText(text);
+}
+
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+ Constructs an empty label.
+
+ The \a parent, \a name and widget flag \a f, arguments are passed
+ to the QFrame constructor.
+
+ \sa setAlignment(), setFrameStyle(), setIndent()
+*/
+
+QLabel::QLabel(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QFrame(*new QLabelPrivate(), parent, f)
+{
+ Q_D(QLabel);
+ if (name)
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+
+/*! \obsolete
+ Constructs a label that displays the text, \a text.
+
+ The \a parent, \a name and widget flag \a f, arguments are passed
+ to the QFrame constructor.
+
+ \sa setText(), setAlignment(), setFrameStyle(), setIndent()
+*/
+
+QLabel::QLabel(const QString &text, QWidget *parent, const char *name,
+ Qt::WindowFlags f)
+ : QFrame(*new QLabelPrivate(), parent, f)
+{
+ Q_D(QLabel);
+ if (name)
+ setObjectName(QString::fromAscii(name));
+ d->init();
+ setText(text);
+}
+
+
+/*! \obsolete
+ Constructs a label that displays the text \a text. The label has a
+ buddy widget, \a buddy.
+
+ If the \a text contains an underlined letter (a letter preceded by
+ an ampersand, \&), when the user presses Alt+ the underlined letter,
+ focus is passed to the buddy widget.
+
+ The \a parent, \a name and widget flag, \a f, arguments are passed
+ to the QFrame constructor.
+
+ \sa setText(), setBuddy(), setAlignment(), setFrameStyle(),
+ setIndent()
+*/
+QLabel::QLabel(QWidget *buddy, const QString &text,
+ QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QFrame(*new QLabelPrivate(), parent, f)
+{
+ Q_D(QLabel);
+ if (name)
+ setObjectName(QString::fromAscii(name));
+ d->init();
+#ifndef QT_NO_SHORTCUT
+ setBuddy(buddy);
+#endif
+ setText(text);
+}
+#endif //QT3_SUPPORT
+
+/*!
+ Destroys the label.
+*/
+
+QLabel::~QLabel()
+{
+ Q_D(QLabel);
+ d->clearContents();
+}
+
+void QLabelPrivate::init()
+{
+ Q_Q(QLabel);
+
+ valid_hints = false;
+ margin = 0;
+#ifndef QT_NO_MOVIE
+ movie = 0;
+#endif
+#ifndef QT_NO_SHORTCUT
+ shortcutId = 0;
+#endif
+ pixmap = 0;
+ scaledpixmap = 0;
+ cachedimage = 0;
+#ifndef QT_NO_PICTURE
+ picture = 0;
+#endif
+ align = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextExpandTabs;
+ indent = -1;
+ scaledcontents = false;
+ textLayoutDirty = false;
+ textDirty = false;
+ textformat = Qt::AutoText;
+ control = 0;
+ textInteractionFlags = Qt::LinksAccessibleByMouse;
+ isRichText = false;
+ isTextLabel = false;
+
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
+ QSizePolicy::Label));
+
+#ifndef QT_NO_CURSOR
+ validCursor = false;
+ onAnchor = false;
+#endif
+
+ openExternalLinks = false;
+
+ setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
+}
+
+
+/*!
+ \property QLabel::text
+ \brief the label's text
+
+ If no text has been set this will return an empty string. Setting
+ the text clears any previous content.
+
+ The text will be interpreted either as plain text or as rich
+ text, depending on the text format setting; see setTextFormat().
+ The default setting is Qt::AutoText; i.e. QLabel will try to
+ auto-detect the format of the text set.
+
+ If a buddy has been set, the buddy mnemonic key is updated
+ from the new text.
+
+ Note that QLabel is well-suited to display small rich text
+ documents, such as small documents that get their document
+ specific settings (font, text color, link color) from the label's
+ palette and font properties. For large documents, use QTextEdit
+ in read-only mode instead. QTextEdit can also provide a scroll bar
+ when necessary.
+
+ \note This function enables mouse tracking if \a text contains rich
+ text.
+
+ \sa setTextFormat(), setBuddy(), alignment
+*/
+
+void QLabel::setText(const QString &text)
+{
+ Q_D(QLabel);
+ if (d->text == text)
+ return;
+
+ QWidgetTextControl *oldControl = d->control;
+ d->control = 0;
+
+ d->clearContents();
+ d->text = text;
+ d->isTextLabel = true;
+ d->textDirty = true;
+ d->isRichText = d->textformat == Qt::RichText
+ || (d->textformat == Qt::AutoText && Qt::mightBeRichText(d->text));
+
+ d->control = oldControl;
+
+ if (d->needTextControl()) {
+ d->ensureTextControl();
+ } else {
+ delete d->control;
+ d->control = 0;
+ }
+
+ if (d->isRichText) {
+ setMouseTracking(true);
+ } else {
+ // Note: mouse tracking not disabled intentionally
+ }
+
+#ifndef QT_NO_SHORTCUT
+ if (d->buddy)
+ d->updateShortcut();
+#endif
+
+ d->updateLabel();
+
+#ifndef QT_NO_ACCESSIBILITY
+ if (accessibleName().isEmpty())
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+QString QLabel::text() const
+{
+ Q_D(const QLabel);
+ return d->text;
+}
+
+/*!
+ Clears any label contents.
+*/
+
+void QLabel::clear()
+{
+ Q_D(QLabel);
+ d->clearContents();
+ d->updateLabel();
+}
+
+/*!
+ \property QLabel::pixmap
+ \brief the label's pixmap
+
+ If no pixmap has been set this will return 0.
+
+ Setting the pixmap clears any previous content. The buddy
+ shortcut, if any, is disabled.
+*/
+void QLabel::setPixmap(const QPixmap &pixmap)
+{
+ Q_D(QLabel);
+ if (!d->pixmap || d->pixmap->cacheKey() != pixmap.cacheKey()) {
+ d->clearContents();
+ d->pixmap = new QPixmap(pixmap);
+ }
+
+ if (d->pixmap->depth() == 1 && !d->pixmap->mask())
+ d->pixmap->setMask(*((QBitmap *)d->pixmap));
+
+ d->updateLabel();
+}
+
+const QPixmap *QLabel::pixmap() const
+{
+ Q_D(const QLabel);
+ return d->pixmap;
+}
+
+#ifndef QT_NO_PICTURE
+/*!
+ Sets the label contents to \a picture. Any previous content is
+ cleared.
+
+ The buddy shortcut, if any, is disabled.
+
+ \sa picture(), setBuddy()
+*/
+
+void QLabel::setPicture(const QPicture &picture)
+{
+ Q_D(QLabel);
+ d->clearContents();
+ d->picture = new QPicture(picture);
+
+ d->updateLabel();
+}
+#endif // QT_NO_PICTURE
+
+/*!
+ Sets the label contents to plain text containing the textual
+ representation of integer \a num. Any previous content is cleared.
+ Does nothing if the integer's string representation is the same as
+ the current contents of the label.
+
+ The buddy shortcut, if any, is disabled.
+
+ \sa setText(), QString::setNum(), setBuddy()
+*/
+
+void QLabel::setNum(int num)
+{
+ QString str;
+ str.setNum(num);
+ setText(str);
+}
+
+/*!
+ \overload
+
+ Sets the label contents to plain text containing the textual
+ representation of double \a num. Any previous content is cleared.
+ Does nothing if the double's string representation is the same as
+ the current contents of the label.
+
+ The buddy shortcut, if any, is disabled.
+
+ \sa setText(), QString::setNum(), setBuddy()
+*/
+
+void QLabel::setNum(double num)
+{
+ QString str;
+ str.setNum(num);
+ setText(str);
+}
+
+/*!
+ \property QLabel::alignment
+ \brief the alignment of the label's contents
+
+ By default, the contents of the label are left-aligned and vertically-centered.
+
+ \sa text
+*/
+
+void QLabel::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QLabel);
+ if (alignment == (d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask)))
+ return;
+ d->align = (d->align & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask))
+ | (alignment & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
+
+ d->updateLabel();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use setAlignment(Qt::Alignment) instead.
+
+ If \a alignment specifies text flags as well, use setTextFormat()
+ to set those.
+*/
+void QLabel::setAlignment(int alignment)
+{
+ Q_D(QLabel);
+ d->align = alignment & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask|Qt::TextWordWrap);
+ setAlignment(Qt::Alignment(QFlag(alignment)));
+}
+#endif
+
+Qt::Alignment QLabel::alignment() const
+{
+ Q_D(const QLabel);
+ return QFlag(d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
+}
+
+
+/*!
+ \property QLabel::wordWrap
+ \brief the label's word-wrapping policy
+
+ If this property is true then label text is wrapped where
+ necessary at word-breaks; otherwise it is not wrapped at all.
+
+ By default, word wrap is disabled.
+
+ \sa text
+*/
+void QLabel::setWordWrap(bool on)
+{
+ Q_D(QLabel);
+ if (on)
+ d->align |= Qt::TextWordWrap;
+ else
+ d->align &= ~Qt::TextWordWrap;
+
+ d->updateLabel();
+}
+
+bool QLabel::wordWrap() const
+{
+ Q_D(const QLabel);
+ return d->align & Qt::TextWordWrap;
+}
+
+/*!
+ \property QLabel::indent
+ \brief the label's text indent in pixels
+
+ If a label displays text, the indent applies to the left edge if
+ alignment() is Qt::AlignLeft, to the right edge if alignment() is
+ Qt::AlignRight, to the top edge if alignment() is Qt::AlignTop, and
+ to to the bottom edge if alignment() is Qt::AlignBottom.
+
+ If indent is negative, or if no indent has been set, the label
+ computes the effective indent as follows: If frameWidth() is 0,
+ the effective indent becomes 0. If frameWidth() is greater than 0,
+ the effective indent becomes half the width of the "x" character
+ of the widget's current font().
+
+ By default, the indent is -1, meaning that an effective indent is
+ calculating in the manner described above.
+
+ \sa alignment, margin, frameWidth(), font()
+*/
+
+void QLabel::setIndent(int indent)
+{
+ Q_D(QLabel);
+ d->indent = indent;
+ d->updateLabel();
+}
+
+int QLabel::indent() const
+{
+ Q_D(const QLabel);
+ return d->indent;
+}
+
+
+/*!
+ \property QLabel::margin
+ \brief the width of the margin
+
+ The margin is the distance between the innermost pixel of the
+ frame and the outermost pixel of contents.
+
+ The default margin is 0.
+
+ \sa indent
+*/
+int QLabel::margin() const
+{
+ Q_D(const QLabel);
+ return d->margin;
+}
+
+void QLabel::setMargin(int margin)
+{
+ Q_D(QLabel);
+ if (d->margin == margin)
+ return;
+ d->margin = margin;
+ d->updateLabel();
+}
+
+/*!
+ Returns the size that will be used if the width of the label is \a
+ w. If \a w is -1, the sizeHint() is returned. If \a w is 0 minimumSizeHint() is returned
+*/
+QSize QLabelPrivate::sizeForWidth(int w) const
+{
+ Q_Q(const QLabel);
+ if(q->minimumWidth() > 0)
+ w = qMax(w, q->minimumWidth());
+ QSize contentsMargin(leftmargin + rightmargin, topmargin + bottommargin);
+
+ QRect br;
+
+ int hextra = 2 * margin;
+ int vextra = hextra;
+ QFontMetrics fm = q->fontMetrics();
+
+ if (pixmap && !pixmap->isNull())
+ br = pixmap->rect();
+#ifndef QT_NO_PICTURE
+ else if (picture && !picture->isNull())
+ br = picture->boundingRect();
+#endif
+#ifndef QT_NO_MOVIE
+ else if (movie && !movie->currentPixmap().isNull())
+ br = movie->currentPixmap().rect();
+#endif
+ else if (isTextLabel) {
+ int align = QStyle::visualAlignment(textDirection(), QFlag(this->align));
+ // Add indentation
+ int m = indent;
+
+ if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
+ m = fm.width(QLatin1Char('x')) - margin*2;
+ if (m > 0) {
+ if ((align & Qt::AlignLeft) || (align & Qt::AlignRight))
+ hextra += m;
+ if ((align & Qt::AlignTop) || (align & Qt::AlignBottom))
+ vextra += m;
+ }
+
+ if (control) {
+ ensureTextLayouted();
+ const qreal oldTextWidth = control->textWidth();
+ // Calculate the length of document if w is the width
+ if (align & Qt::TextWordWrap) {
+ if (w >= 0) {
+ w = qMax(w-hextra-contentsMargin.width(), 0); // strip margin and indent
+ control->setTextWidth(w);
+ } else {
+ control->adjustSize();
+ }
+ } else {
+ control->setTextWidth(-1);
+ }
+
+ QSizeF controlSize = control->size();
+ br = QRect(QPoint(0, 0), QSize(qCeil(controlSize.width()), qCeil(controlSize.height())));
+
+ // restore state
+ control->setTextWidth(oldTextWidth);
+ } else {
+ // Turn off center alignment in order to avoid rounding errors for centering,
+ // since centering involves a division by 2. At the end, all we want is the size.
+ int flags = align & ~(Qt::AlignVCenter | Qt::AlignHCenter);
+ if (hasShortcut) {
+ flags |= Qt::TextShowMnemonic;
+ QStyleOption opt;
+ opt.initFrom(q);
+ if (!q->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, q))
+ flags |= Qt::TextHideMnemonic;
+ }
+
+ bool tryWidth = (w < 0) && (align & Qt::TextWordWrap);
+ if (tryWidth)
+ w = qMin(fm.averageCharWidth() * 80, q->maximumSize().width());
+ else if (w < 0)
+ w = 2000;
+ w -= (hextra + contentsMargin.width());
+ br = fm.boundingRect(0, 0, w ,2000, flags, text);
+ if (tryWidth && br.height() < 4*fm.lineSpacing() && br.width() > w/2)
+ br = fm.boundingRect(0, 0, w/2, 2000, flags, text);
+ if (tryWidth && br.height() < 2*fm.lineSpacing() && br.width() > w/4)
+ br = fm.boundingRect(0, 0, w/4, 2000, flags, text);
+ }
+ } else {
+ br = QRect(QPoint(0, 0), QSize(fm.averageCharWidth(), fm.lineSpacing()));
+ }
+
+ const QSize contentsSize(br.width() + hextra, br.height() + vextra);
+ return (contentsSize + contentsMargin).expandedTo(q->minimumSize());
+}
+
+
+/*!
+ \reimp
+*/
+
+int QLabel::heightForWidth(int w) const
+{
+ Q_D(const QLabel);
+ if (d->isTextLabel)
+ return d->sizeForWidth(w).height();
+ return QWidget::heightForWidth(w);
+}
+
+/*!
+ \property QLabel::openExternalLinks
+ \since 4.2
+
+ Specifies whether QLabel should automatically open links using
+ QDesktopServices::openUrl() instead of emitting the
+ linkActivated() signal.
+
+ \bold{Note:} The textInteractionFlags set on the label need to include
+ either LinksAccessibleByMouse or LinksAccessibleByKeyboard.
+
+ The default value is false.
+
+ \sa textInteractionFlags()
+*/
+bool QLabel::openExternalLinks() const
+{
+ Q_D(const QLabel);
+ return d->openExternalLinks;
+}
+
+void QLabel::setOpenExternalLinks(bool open)
+{
+ Q_D(QLabel);
+ d->openExternalLinks = open;
+ if (d->control)
+ d->control->setOpenExternalLinks(open);
+}
+
+/*!
+ \property QLabel::textInteractionFlags
+ \since 4.2
+
+ Specifies how the label should interact with user input if it displays text.
+
+ If the flags contain Qt::LinksAccessibleByKeyboard the focus policy is also
+ automatically set to Qt::StrongFocus. If Qt::TextSelectableByKeyboard is set
+ then the focus policy is set to Qt::ClickFocus.
+
+ The default value is Qt::LinksAccessibleByMouse.
+*/
+void QLabel::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QLabel);
+ if (d->textInteractionFlags == flags)
+ return;
+ d->textInteractionFlags = flags;
+ if (flags & Qt::LinksAccessibleByKeyboard)
+ setFocusPolicy(Qt::StrongFocus);
+ else if (flags & (Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse))
+ setFocusPolicy(Qt::ClickFocus);
+ else
+ setFocusPolicy(Qt::NoFocus);
+
+ if (d->needTextControl()) {
+ d->ensureTextControl();
+ } else {
+ delete d->control;
+ d->control = 0;
+ }
+
+ if (d->control)
+ d->control->setTextInteractionFlags(d->textInteractionFlags);
+}
+
+Qt::TextInteractionFlags QLabel::textInteractionFlags() const
+{
+ Q_D(const QLabel);
+ return d->textInteractionFlags;
+}
+
+/*!
+ Selects text from position \a start and for \a length characters.
+
+ \sa selectedText()
+
+ \bold{Note:} The textInteractionFlags set on the label need to include
+ either TextSelectableByMouse or TextSelectableByKeyboard.
+
+ \since 4.7
+*/
+void QLabel::setSelection(int start, int length)
+{
+ Q_D(QLabel);
+ if (d->control) {
+ d->ensureTextPopulated();
+ QTextCursor cursor = d->control->textCursor();
+ cursor.setPosition(start);
+ cursor.setPosition(start + length, QTextCursor::KeepAnchor);
+ d->control->setTextCursor(cursor);
+ }
+}
+
+/*!
+ \property QLabel::hasSelectedText
+ \brief whether there is any text selected
+
+ hasSelectedText() returns true if some or all of the text has been
+ selected by the user; otherwise returns false.
+
+ By default, this property is false.
+
+ \sa selectedText()
+
+ \bold{Note:} The textInteractionFlags set on the label need to include
+ either TextSelectableByMouse or TextSelectableByKeyboard.
+
+ \since 4.7
+*/
+bool QLabel::hasSelectedText() const
+{
+ Q_D(const QLabel);
+ if (d->control)
+ return d->control->textCursor().hasSelection();
+ return false;
+}
+
+/*!
+ \property QLabel::selectedText
+ \brief the selected text
+
+ If there is no selected text this property's value is
+ an empty string.
+
+ By default, this property contains an empty string.
+
+ \sa hasSelectedText()
+
+ \bold{Note:} The textInteractionFlags set on the label need to include
+ either TextSelectableByMouse or TextSelectableByKeyboard.
+
+ \since 4.7
+*/
+QString QLabel::selectedText() const
+{
+ Q_D(const QLabel);
+ if (d->control)
+ return d->control->textCursor().selectedText();
+ return QString();
+}
+
+/*!
+ selectionStart() returns the index of the first selected character in the
+ label or -1 if no text is selected.
+
+ \sa selectedText()
+
+ \bold{Note:} The textInteractionFlags set on the label need to include
+ either TextSelectableByMouse or TextSelectableByKeyboard.
+
+ \since 4.7
+*/
+int QLabel::selectionStart() const
+{
+ Q_D(const QLabel);
+ if (d->control && d->control->textCursor().hasSelection())
+ return d->control->textCursor().selectionStart();
+ return -1;
+}
+
+/*!\reimp
+*/
+QSize QLabel::sizeHint() const
+{
+ Q_D(const QLabel);
+ if (!d->valid_hints)
+ (void) QLabel::minimumSizeHint();
+ return d->sh;
+}
+
+/*!
+ \reimp
+*/
+QSize QLabel::minimumSizeHint() const
+{
+ Q_D(const QLabel);
+ if (d->valid_hints) {
+ if (d->sizePolicy == sizePolicy())
+ return d->msh;
+ }
+
+ ensurePolished();
+ d->valid_hints = true;
+ d->sh = d->sizeForWidth(-1); // wrap ? golden ratio : min doc size
+ QSize msh(-1, -1);
+
+ if (!d->isTextLabel) {
+ msh = d->sh;
+ } else {
+ msh.rheight() = d->sizeForWidth(QWIDGETSIZE_MAX).height(); // height for one line
+ msh.rwidth() = d->sizeForWidth(0).width(); // wrap ? size of biggest word : min doc size
+ if (d->sh.height() < msh.height())
+ msh.rheight() = d->sh.height();
+ }
+ d->msh = msh;
+ d->sizePolicy = sizePolicy();
+ return msh;
+}
+
+/*!\reimp
+*/
+void QLabel::mousePressEvent(QMouseEvent *ev)
+{
+ Q_D(QLabel);
+ d->sendControlEvent(ev);
+}
+
+/*!\reimp
+*/
+void QLabel::mouseMoveEvent(QMouseEvent *ev)
+{
+ Q_D(QLabel);
+ d->sendControlEvent(ev);
+}
+
+/*!\reimp
+*/
+void QLabel::mouseReleaseEvent(QMouseEvent *ev)
+{
+ Q_D(QLabel);
+ d->sendControlEvent(ev);
+}
+
+/*!\reimp
+*/
+void QLabel::contextMenuEvent(QContextMenuEvent *ev)
+{
+#ifdef QT_NO_CONTEXTMENU
+ Q_UNUSED(ev);
+#else
+ Q_D(QLabel);
+ if (!d->isTextLabel) {
+ ev->ignore();
+ return;
+ }
+ QMenu *menu = d->createStandardContextMenu(ev->pos());
+ if (!menu) {
+ ev->ignore();
+ return;
+ }
+ ev->accept();
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+ menu->popup(ev->globalPos());
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QLabel::focusInEvent(QFocusEvent *ev)
+{
+ Q_D(QLabel);
+ if (d->isTextLabel) {
+ d->ensureTextControl();
+ d->sendControlEvent(ev);
+ }
+ QFrame::focusInEvent(ev);
+}
+
+/*!
+ \reimp
+*/
+void QLabel::focusOutEvent(QFocusEvent *ev)
+{
+ Q_D(QLabel);
+ if (d->control) {
+ d->sendControlEvent(ev);
+ QTextCursor cursor = d->control->textCursor();
+ Qt::FocusReason reason = ev->reason();
+ if (reason != Qt::ActiveWindowFocusReason
+ && reason != Qt::PopupFocusReason
+ && cursor.hasSelection()) {
+ cursor.clearSelection();
+ d->control->setTextCursor(cursor);
+ }
+ }
+
+ QFrame::focusOutEvent(ev);
+}
+
+/*!\reimp
+*/
+bool QLabel::focusNextPrevChild(bool next)
+{
+ Q_D(QLabel);
+ if (d->control && d->control->setFocusToNextOrPreviousAnchor(next))
+ return true;
+ return QFrame::focusNextPrevChild(next);
+}
+
+/*!\reimp
+*/
+void QLabel::keyPressEvent(QKeyEvent *ev)
+{
+ Q_D(QLabel);
+ d->sendControlEvent(ev);
+}
+
+/*!\reimp
+*/
+bool QLabel::event(QEvent *e)
+{
+ Q_D(QLabel);
+ QEvent::Type type = e->type();
+
+#ifndef QT_NO_SHORTCUT
+ if (type == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ if (se->shortcutId() == d->shortcutId) {
+ QWidget * w = d->buddy;
+ QAbstractButton *button = qobject_cast<QAbstractButton *>(w);
+ if (w->focusPolicy() != Qt::NoFocus)
+ w->setFocus(Qt::ShortcutFocusReason);
+ if (button && !se->isAmbiguous())
+ button->animateClick();
+ else
+ window()->setAttribute(Qt::WA_KeyboardFocusChange);
+ return true;
+ }
+ } else
+#endif
+ if (type == QEvent::Resize) {
+ if (d->control)
+ d->textLayoutDirty = true;
+ } else if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ ) {
+ d->setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
+ d->updateLabel();
+ }
+
+ return QFrame::event(e);
+}
+
+/*!\reimp
+*/
+void QLabel::paintEvent(QPaintEvent *)
+{
+ Q_D(QLabel);
+ QStyle *style = QWidget::style();
+ QPainter painter(this);
+ drawFrame(&painter);
+ QRect cr = contentsRect();
+ cr.adjust(d->margin, d->margin, -d->margin, -d->margin);
+ int align = QStyle::visualAlignment(d->isTextLabel ? d->textDirection()
+ : layoutDirection(), QFlag(d->align));
+
+#ifndef QT_NO_MOVIE
+ if (d->movie) {
+ if (d->scaledcontents)
+ style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap().scaled(cr.size()));
+ else
+ style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap());
+ }
+ else
+#endif
+ if (d->isTextLabel) {
+ QRectF lr = d->layoutRect().toAlignedRect();
+ QStyleOption opt;
+ opt.initFrom(this);
+#ifndef QT_NO_STYLE_STYLESHEET
+ if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style)) {
+ cssStyle->styleSheetPalette(this, &opt, &opt.palette);
+ }
+#endif
+ if (d->control) {
+#ifndef QT_NO_SHORTCUT
+ const bool underline = (bool)style->styleHint(QStyle::SH_UnderlineShortcut, 0, this, 0);
+ if (d->shortcutId != 0
+ && underline != d->shortcutCursor.charFormat().fontUnderline()) {
+ QTextCharFormat fmt;
+ fmt.setFontUnderline(underline);
+ d->shortcutCursor.mergeCharFormat(fmt);
+ }
+#endif
+ d->ensureTextLayouted();
+
+ QAbstractTextDocumentLayout::PaintContext context;
+ if (!isEnabled() && !d->control &&
+ // We cannot support etched for rich text controls because custom
+ // colors and links will override the light palette
+ style->styleHint(QStyle::SH_EtchDisabledText, &opt, this)) {
+ context.palette = opt.palette;
+ context.palette.setColor(QPalette::Text, context.palette.light().color());
+ painter.save();
+ painter.translate(lr.x() + 1, lr.y() + 1);
+ painter.setClipRect(lr.translated(-lr.x() - 1, -lr.y() - 1));
+ QAbstractTextDocumentLayout *layout = d->control->document()->documentLayout();
+ layout->draw(&painter, context);
+ painter.restore();
+ }
+
+ // Adjust the palette
+ context.palette = opt.palette;
+
+ if (foregroundRole() != QPalette::Text && isEnabled())
+ context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole()));
+
+ painter.save();
+ painter.translate(lr.topLeft());
+ painter.setClipRect(lr.translated(-lr.x(), -lr.y()));
+ d->control->setPalette(context.palette);
+ d->control->drawContents(&painter, QRectF(), this);
+ painter.restore();
+ } else {
+ int flags = align | (d->textDirection() == Qt::LeftToRight ? Qt::TextForceLeftToRight
+ : Qt::TextForceRightToLeft);
+ if (d->hasShortcut) {
+ flags |= Qt::TextShowMnemonic;
+ if (!style->styleHint(QStyle::SH_UnderlineShortcut, &opt, this))
+ flags |= Qt::TextHideMnemonic;
+ }
+ style->drawItemText(&painter, lr.toRect(), flags, opt.palette, isEnabled(), d->text, foregroundRole());
+ }
+ } else
+#ifndef QT_NO_PICTURE
+ if (d->picture) {
+ QRect br = d->picture->boundingRect();
+ int rw = br.width();
+ int rh = br.height();
+ if (d->scaledcontents) {
+ painter.save();
+ painter.translate(cr.x(), cr.y());
+ painter.scale((double)cr.width()/rw, (double)cr.height()/rh);
+ painter.drawPicture(-br.x(), -br.y(), *d->picture);
+ painter.restore();
+ } else {
+ int xo = 0;
+ int yo = 0;
+ if (align & Qt::AlignVCenter)
+ yo = (cr.height()-rh)/2;
+ else if (align & Qt::AlignBottom)
+ yo = cr.height()-rh;
+ if (align & Qt::AlignRight)
+ xo = cr.width()-rw;
+ else if (align & Qt::AlignHCenter)
+ xo = (cr.width()-rw)/2;
+ painter.drawPicture(cr.x()+xo-br.x(), cr.y()+yo-br.y(), *d->picture);
+ }
+ } else
+#endif
+ if (d->pixmap && !d->pixmap->isNull()) {
+ QPixmap pix;
+ if (d->scaledcontents) {
+ if (!d->scaledpixmap || d->scaledpixmap->size() != cr.size()) {
+ if (!d->cachedimage)
+ d->cachedimage = new QImage(d->pixmap->toImage());
+ delete d->scaledpixmap;
+ d->scaledpixmap = new QPixmap(QPixmap::fromImage(d->cachedimage->scaled(cr.size(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)));
+ }
+ pix = *d->scaledpixmap;
+ } else
+ pix = *d->pixmap;
+ QStyleOption opt;
+ opt.initFrom(this);
+ if (!isEnabled())
+ pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt);
+ style->drawItemPixmap(&painter, cr, align, pix);
+ }
+}
+
+
+/*!
+ Updates the label, but not the frame.
+*/
+
+void QLabelPrivate::updateLabel()
+{
+ Q_Q(QLabel);
+ valid_hints = false;
+
+ if (isTextLabel) {
+ QSizePolicy policy = q->sizePolicy();
+ const bool wrap = align & Qt::TextWordWrap;
+ policy.setHeightForWidth(wrap);
+ if (policy != q->sizePolicy()) // ### should be replaced by WA_WState_OwnSizePolicy idiom
+ q->setSizePolicy(policy);
+ textLayoutDirty = true;
+ }
+ q->updateGeometry();
+ q->update(q->contentsRect());
+}
+
+#ifndef QT_NO_SHORTCUT
+/*!
+ Sets this label's buddy to \a buddy.
+
+ When the user presses the shortcut key indicated by this label,
+ the keyboard focus is transferred to the label's buddy widget.
+
+ The buddy mechanism is only available for QLabels that contain
+ text in which one character is prefixed with an ampersand, '&'.
+ This character is set as the shortcut key. See the \l
+ QKeySequence::mnemonic() documentation for details (to display an
+ actual ampersand, use '&&').
+
+ In a dialog, you might create two data entry widgets and a label
+ for each, and set up the geometry layout so each label is just to
+ the left of its data entry widget (its "buddy"), for example:
+ \snippet doc/src/snippets/code/src_gui_widgets_qlabel.cpp 2
+
+ With the code above, the focus jumps to the Name field when the
+ user presses Alt+N, and to the Phone field when the user presses
+ Alt+P.
+
+ To unset a previously set buddy, call this function with \a buddy
+ set to 0.
+
+ \sa buddy(), setText(), QShortcut, setAlignment()
+*/
+
+void QLabel::setBuddy(QWidget *buddy)
+{
+ Q_D(QLabel);
+ d->buddy = buddy;
+ if (d->isTextLabel) {
+ if (d->shortcutId)
+ releaseShortcut(d->shortcutId);
+ d->shortcutId = 0;
+ d->textDirty = true;
+ if (buddy)
+ d->updateShortcut(); // grab new shortcut
+ d->updateLabel();
+ }
+}
+
+
+/*!
+ Returns this label's buddy, or 0 if no buddy is currently set.
+
+ \sa setBuddy()
+*/
+
+QWidget * QLabel::buddy() const
+{
+ Q_D(const QLabel);
+ return d->buddy;
+}
+
+void QLabelPrivate::updateShortcut()
+{
+ Q_Q(QLabel);
+ Q_ASSERT(shortcutId == 0);
+ // Introduce an extra boolean to indicate the presence of a shortcut in the
+ // text. We cannot use the shortcutId itself because on the mac mnemonics are
+ // off by default, so QKeySequence::mnemonic always returns an empty sequence.
+ // But then we do want to hide the ampersands, so we can't use shortcutId.
+ hasShortcut = false;
+
+ if (!text.contains(QLatin1Char('&')))
+ return;
+ hasShortcut = true;
+ shortcutId = q->grabShortcut(QKeySequence::mnemonic(text));
+}
+
+#endif // QT_NO_SHORTCUT
+
+#ifndef QT_NO_MOVIE
+void QLabelPrivate::_q_movieUpdated(const QRect& rect)
+{
+ Q_Q(QLabel);
+ if (movie && movie->isValid()) {
+ QRect r;
+ if (scaledcontents) {
+ QRect cr = q->contentsRect();
+ QRect pixmapRect(cr.topLeft(), movie->currentPixmap().size());
+ if (pixmapRect.isEmpty())
+ return;
+ r.setRect(cr.left(), cr.top(),
+ (rect.width() * cr.width()) / pixmapRect.width(),
+ (rect.height() * cr.height()) / pixmapRect.height());
+ } else {
+ r = q->style()->itemPixmapRect(q->contentsRect(), align, movie->currentPixmap());
+ r.translate(rect.x(), rect.y());
+ r.setWidth(qMin(r.width(), rect.width()));
+ r.setHeight(qMin(r.height(), rect.height()));
+ }
+ q->update(r);
+ }
+}
+
+void QLabelPrivate::_q_movieResized(const QSize& size)
+{
+ Q_Q(QLabel);
+ q->update(); //we need to refresh the whole background in case the new size is smaler
+ valid_hints = false;
+ _q_movieUpdated(QRect(QPoint(0,0), size));
+ q->updateGeometry();
+}
+
+/*!
+ Sets the label contents to \a movie. Any previous content is
+ cleared. The label does NOT take ownership of the movie.
+
+ The buddy shortcut, if any, is disabled.
+
+ \sa movie(), setBuddy()
+*/
+
+void QLabel::setMovie(QMovie *movie)
+{
+ Q_D(QLabel);
+ d->clearContents();
+
+ if (!movie)
+ return;
+
+ d->movie = movie;
+ connect(movie, SIGNAL(resized(QSize)), this, SLOT(_q_movieResized(QSize)));
+ connect(movie, SIGNAL(updated(QRect)), this, SLOT(_q_movieUpdated(QRect)));
+
+ // Assume that if the movie is running,
+ // resize/update signals will come soon enough
+ if (movie->state() != QMovie::Running)
+ d->updateLabel();
+}
+
+#endif // QT_NO_MOVIE
+
+/*!
+ \internal
+
+ Clears any contents, without updating/repainting the label.
+*/
+
+void QLabelPrivate::clearContents()
+{
+ delete control;
+ control = 0;
+ isTextLabel = false;
+ hasShortcut = false;
+
+#ifndef QT_NO_PICTURE
+ delete picture;
+ picture = 0;
+#endif
+ delete scaledpixmap;
+ scaledpixmap = 0;
+ delete cachedimage;
+ cachedimage = 0;
+ delete pixmap;
+ pixmap = 0;
+
+ text.clear();
+ Q_Q(QLabel);
+#ifndef QT_NO_SHORTCUT
+ if (shortcutId)
+ q->releaseShortcut(shortcutId);
+ shortcutId = 0;
+#endif
+#ifndef QT_NO_MOVIE
+ if (movie) {
+ QObject::disconnect(movie, SIGNAL(resized(QSize)), q, SLOT(_q_movieResized(QSize)));
+ QObject::disconnect(movie, SIGNAL(updated(QRect)), q, SLOT(_q_movieUpdated(QRect)));
+ }
+ movie = 0;
+#endif
+#ifndef QT_NO_CURSOR
+ if (onAnchor) {
+ if (validCursor)
+ q->setCursor(cursor);
+ else
+ q->unsetCursor();
+ }
+ validCursor = false;
+ onAnchor = false;
+#endif
+}
+
+
+#ifndef QT_NO_MOVIE
+
+/*!
+ Returns a pointer to the label's movie, or 0 if no movie has been
+ set.
+
+ \sa setMovie()
+*/
+
+QMovie *QLabel::movie() const
+{
+ Q_D(const QLabel);
+ return d->movie;
+}
+
+#endif // QT_NO_MOVIE
+
+/*!
+ \property QLabel::textFormat
+ \brief the label's text format
+
+ See the Qt::TextFormat enum for an explanation of the possible
+ options.
+
+ The default format is Qt::AutoText.
+
+ \sa text()
+*/
+
+Qt::TextFormat QLabel::textFormat() const
+{
+ Q_D(const QLabel);
+ return d->textformat;
+}
+
+void QLabel::setTextFormat(Qt::TextFormat format)
+{
+ Q_D(QLabel);
+ if (format != d->textformat) {
+ d->textformat = format;
+ QString t = d->text;
+ if (!t.isNull()) {
+ d->text.clear();
+ setText(t);
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QLabel::changeEvent(QEvent *ev)
+{
+ Q_D(QLabel);
+ if(ev->type() == QEvent::FontChange || ev->type() == QEvent::ApplicationFontChange) {
+ if (d->isTextLabel) {
+ if (d->control)
+ d->control->document()->setDefaultFont(font());
+ d->updateLabel();
+ }
+ } else if (ev->type() == QEvent::PaletteChange && d->control) {
+ d->control->setPalette(palette());
+ } else if (ev->type() == QEvent::ContentsRectChange) {
+ d->updateLabel();
+ }
+ QFrame::changeEvent(ev);
+}
+
+/*!
+ \property QLabel::scaledContents
+ \brief whether the label will scale its contents to fill all
+ available space.
+
+ When enabled and the label shows a pixmap, it will scale the
+ pixmap to fill the available space.
+
+ This property's default is false.
+*/
+bool QLabel::hasScaledContents() const
+{
+ Q_D(const QLabel);
+ return d->scaledcontents;
+}
+
+void QLabel::setScaledContents(bool enable)
+{
+ Q_D(QLabel);
+ if ((bool)d->scaledcontents == enable)
+ return;
+ d->scaledcontents = enable;
+ if (!enable) {
+ delete d->scaledpixmap;
+ d->scaledpixmap = 0;
+ delete d->cachedimage;
+ d->cachedimage = 0;
+ }
+ update(contentsRect());
+}
+
+Qt::LayoutDirection QLabelPrivate::textDirection() const
+{
+ if (control) {
+ QTextOption opt = control->document()->defaultTextOption();
+ return opt.textDirection();
+ }
+
+ return text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
+}
+
+/*!
+ \fn void QLabel::setAlignment(Qt::AlignmentFlag flag)
+ \internal
+
+ Without this function, a call to e.g. setAlignment(Qt::AlignTop)
+ results in the \c QT3_SUPPORT function setAlignment(int) being called,
+ rather than setAlignment(Qt::Alignment).
+*/
+
+// Returns the rect that is available for us to draw the document
+QRect QLabelPrivate::documentRect() const
+{
+ Q_Q(const QLabel);
+ Q_ASSERT_X(isTextLabel, "documentRect", "document rect called for label that is not a text label!");
+ QRect cr = q->contentsRect();
+ cr.adjust(margin, margin, -margin, -margin);
+ const int align = QStyle::visualAlignment(isTextLabel ? textDirection()
+ : q->layoutDirection(), QFlag(this->align));
+ int m = indent;
+ if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
+ m = q->fontMetrics().width(QLatin1Char('x')) / 2 - margin;
+ if (m > 0) {
+ if (align & Qt::AlignLeft)
+ cr.setLeft(cr.left() + m);
+ if (align & Qt::AlignRight)
+ cr.setRight(cr.right() - m);
+ if (align & Qt::AlignTop)
+ cr.setTop(cr.top() + m);
+ if (align & Qt::AlignBottom)
+ cr.setBottom(cr.bottom() - m);
+ }
+ return cr;
+}
+
+void QLabelPrivate::ensureTextPopulated() const
+{
+ if (!textDirty)
+ return;
+ if (control) {
+ QTextDocument *doc = control->document();
+ if (textDirty) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (isRichText)
+ doc->setHtml(text);
+ else
+ doc->setPlainText(text);
+#else
+ doc->setPlainText(text);
+#endif
+ doc->setUndoRedoEnabled(false);
+
+#ifndef QT_NO_SHORTCUT
+ if (hasShortcut) {
+ // Underline the first character that follows an ampersand (and remove the others ampersands)
+ int from = 0;
+ bool found = false;
+ QTextCursor cursor;
+ while (!(cursor = control->document()->find((QLatin1String("&")), from)).isNull()) {
+ cursor.deleteChar(); // remove the ampersand
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ from = cursor.position();
+ if (!found && cursor.selectedText() != QLatin1String("&")) { //not a second &
+ found = true;
+ shortcutCursor = cursor;
+ }
+ }
+ }
+#endif
+ }
+ }
+ textDirty = false;
+}
+
+void QLabelPrivate::ensureTextLayouted() const
+{
+ if (!textLayoutDirty)
+ return;
+ ensureTextPopulated();
+ if (control) {
+ QTextDocument *doc = control->document();
+ QTextOption opt = doc->defaultTextOption();
+
+ opt.setAlignment(QFlag(this->align));
+
+ if (this->align & Qt::TextWordWrap)
+ opt.setWrapMode(QTextOption::WordWrap);
+ else
+ opt.setWrapMode(QTextOption::ManualWrap);
+
+ doc->setDefaultTextOption(opt);
+
+ QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
+ fmt.setMargin(0);
+ doc->rootFrame()->setFrameFormat(fmt);
+ doc->setTextWidth(documentRect().width());
+ }
+ textLayoutDirty = false;
+}
+
+void QLabelPrivate::ensureTextControl() const
+{
+ Q_Q(const QLabel);
+ if (!isTextLabel)
+ return;
+ if (!control) {
+ control = new QWidgetTextControl(const_cast<QLabel *>(q));
+ control->document()->setUndoRedoEnabled(false);
+ control->document()->setDefaultFont(q->font());
+ control->setTextInteractionFlags(textInteractionFlags);
+ control->setOpenExternalLinks(openExternalLinks);
+ control->setPalette(q->palette());
+ control->setFocus(q->hasFocus());
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)),
+ q, SLOT(update()));
+ QObject::connect(control, SIGNAL(linkHovered(QString)),
+ q, SLOT(_q_linkHovered(QString)));
+ QObject::connect(control, SIGNAL(linkActivated(QString)),
+ q, SIGNAL(linkActivated(QString)));
+ textLayoutDirty = true;
+ textDirty = true;
+ }
+}
+
+void QLabelPrivate::sendControlEvent(QEvent *e)
+{
+ Q_Q(QLabel);
+ if (!isTextLabel || !control || textInteractionFlags == Qt::NoTextInteraction) {
+ e->ignore();
+ return;
+ }
+ control->processEvent(e, -layoutRect().topLeft(), q);
+}
+
+void QLabelPrivate::_q_linkHovered(const QString &anchor)
+{
+ Q_Q(QLabel);
+#ifndef QT_NO_CURSOR
+ if (anchor.isEmpty()) { // restore cursor
+ if (validCursor)
+ q->setCursor(cursor);
+ else
+ q->unsetCursor();
+ onAnchor = false;
+ } else if (!onAnchor) {
+ validCursor = q->testAttribute(Qt::WA_SetCursor);
+ if (validCursor) {
+ cursor = q->cursor();
+ }
+ q->setCursor(Qt::PointingHandCursor);
+ onAnchor = true;
+ }
+#endif
+ emit q->linkHovered(anchor);
+}
+
+// Return the layout rect - this is the rect that is given to the layout painting code
+// This may be different from the document rect since vertical alignment is not
+// done by the text layout code
+QRectF QLabelPrivate::layoutRect() const
+{
+ QRectF cr = documentRect();
+ if (!control)
+ return cr;
+ ensureTextLayouted();
+ // Caculate y position manually
+ qreal rh = control->document()->documentLayout()->documentSize().height();
+ qreal yo = 0;
+ if (align & Qt::AlignVCenter)
+ yo = qMax((cr.height()-rh)/2, qreal(0));
+ else if (align & Qt::AlignBottom)
+ yo = qMax(cr.height()-rh, qreal(0));
+ return QRectF(cr.x(), yo + cr.y(), cr.width(), cr.height());
+}
+
+// Returns the point in the document rect adjusted with p
+QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
+{
+ QRect lr = layoutRect().toRect();
+ return p - lr.topLeft();
+}
+
+#ifndef QT_NO_CONTEXTMENU
+QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
+{
+ QString linkToCopy;
+ QPoint p;
+ if (control && isRichText) {
+ p = layoutPoint(pos);
+ linkToCopy = control->document()->documentLayout()->anchorAt(p);
+ }
+
+ if (linkToCopy.isEmpty() && !control)
+ return 0;
+
+ return control->createStandardContextMenu(p, q_func());
+}
+#endif
+
+/*!
+ \fn void QLabel::linkHovered(const QString &link)
+ \since 4.2
+
+ This signal is emitted when the user hovers over a link. The URL
+ referred to by the anchor is passed in \a link.
+
+ \sa linkActivated()
+*/
+
+
+/*!
+ \fn void QLabel::linkActivated(const QString &link)
+ \since 4.2
+
+ This signal is emitted when the user clicks a link. The URL
+ referred to by the anchor is passed in \a link.
+
+ \sa linkHovered()
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qlabel.cpp"
diff --git a/src/widgets/widgets/qlabel.h b/src/widgets/widgets/qlabel.h
new file mode 100644
index 0000000000..d8fc297299
--- /dev/null
+++ b/src/widgets/widgets/qlabel.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLABEL_H
+#define QLABEL_H
+
+#include <QtWidgets/qframe.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QLabelPrivate;
+
+class Q_WIDGETS_EXPORT QLabel : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText)
+ Q_PROPERTY(Qt::TextFormat textFormat READ textFormat WRITE setTextFormat)
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)
+ Q_PROPERTY(bool scaledContents READ hasScaledContents WRITE setScaledContents)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap)
+ Q_PROPERTY(int margin READ margin WRITE setMargin)
+ Q_PROPERTY(int indent READ indent WRITE setIndent)
+ Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
+ Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
+ Q_PROPERTY(bool hasSelectedText READ hasSelectedText)
+ Q_PROPERTY(QString selectedText READ selectedText)
+
+public:
+ explicit QLabel(QWidget *parent=0, Qt::WindowFlags f=0);
+ explicit QLabel(const QString &text, QWidget *parent=0, Qt::WindowFlags f=0);
+ ~QLabel();
+
+ QString text() const;
+ const QPixmap *pixmap() const;
+#ifndef QT_NO_PICTURE
+ const QPicture *picture() const;
+#endif
+#ifndef QT_NO_MOVIE
+ QMovie *movie() const;
+#endif
+
+ Qt::TextFormat textFormat() const;
+ void setTextFormat(Qt::TextFormat);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment);
+
+ void setWordWrap(bool on);
+ bool wordWrap() const;
+
+ int indent() const;
+ void setIndent(int);
+
+ int margin() const;
+ void setMargin(int);
+
+ bool hasScaledContents() const;
+ void setScaledContents(bool);
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+#ifndef QT_NO_SHORTCUT
+ void setBuddy(QWidget *);
+ QWidget *buddy() const;
+#endif
+ int heightForWidth(int) const;
+
+ bool openExternalLinks() const;
+ void setOpenExternalLinks(bool open);
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ void setSelection(int, int);
+ bool hasSelectedText() const;
+ QString selectedText() const;
+ int selectionStart() const;
+
+public Q_SLOTS:
+ void setText(const QString &);
+ void setPixmap(const QPixmap &);
+#ifndef QT_NO_PICTURE
+ void setPicture(const QPicture &);
+#endif
+#ifndef QT_NO_MOVIE
+ void setMovie(QMovie *movie);
+#endif
+ void setNum(int);
+ void setNum(double);
+ void clear();
+
+Q_SIGNALS:
+ void linkActivated(const QString& link);
+ void linkHovered(const QString& link);
+
+protected:
+ bool event(QEvent *e);
+ void keyPressEvent(QKeyEvent *ev);
+ void paintEvent(QPaintEvent *);
+ void changeEvent(QEvent *);
+ void mousePressEvent(QMouseEvent *ev);
+ void mouseMoveEvent(QMouseEvent *ev);
+ void mouseReleaseEvent(QMouseEvent *ev);
+ void contextMenuEvent(QContextMenuEvent *ev);
+ void focusInEvent(QFocusEvent *ev);
+ void focusOutEvent(QFocusEvent *ev);
+ bool focusNextPrevChild(bool next);
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QLabel(QWidget *parent, const char* name, Qt::WindowFlags f=0);
+ QT3_SUPPORT_CONSTRUCTOR QLabel(const QString &text, QWidget *parent, const char* name,
+ Qt::WindowFlags f=0);
+ QT3_SUPPORT_CONSTRUCTOR QLabel(QWidget *buddy, const QString &,
+ QWidget *parent=0, const char* name=0, Qt::WindowFlags f=0);
+ QT3_SUPPORT void setAlignment(int alignment);
+
+ // don't mark the next function with QT3_SUPPORT
+ inline void setAlignment(Qt::AlignmentFlag flag) { setAlignment((Qt::Alignment)flag); }
+#endif
+
+private:
+ Q_DISABLE_COPY(QLabel)
+ Q_DECLARE_PRIVATE(QLabel)
+#ifndef QT_NO_MOVIE
+ Q_PRIVATE_SLOT(d_func(), void _q_movieUpdated(const QRect&))
+ Q_PRIVATE_SLOT(d_func(), void _q_movieResized(const QSize&))
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_linkHovered(const QString &))
+
+ friend class QTipLabel;
+ friend class QMessageBoxPrivate;
+ friend class QBalloonTip;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLABEL_H
diff --git a/src/widgets/widgets/qlabel_p.h b/src/widgets/widgets/qlabel_p.h
new file mode 100644
index 0000000000..b6f2db6a25
--- /dev/null
+++ b/src/widgets/widgets/qlabel_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLABEL_P_H
+#define QLABEL_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 "qlabel.h"
+
+#include "private/qtextdocumentlayout_p.h"
+#include "private/qwidgettextcontrol_p.h"
+#include "qtextdocumentfragment.h"
+#include "qframe_p.h"
+#include "qtextdocument.h"
+#include "qmovie.h"
+#include "qimage.h"
+#include "qbitmap.h"
+#include "qpicture.h"
+#include "qmenu.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLabelPrivate : public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QLabel)
+public:
+ QLabelPrivate() {}
+
+ void init();
+ void clearContents();
+ void updateLabel();
+ QSize sizeForWidth(int w) const;
+
+ mutable QSize sh;
+ mutable QSize msh;
+ mutable bool valid_hints;
+ mutable QSizePolicy sizePolicy;
+ int margin;
+ QString text;
+ QPixmap *pixmap;
+ QPixmap *scaledpixmap;
+ QImage *cachedimage;
+#ifndef QT_NO_PICTURE
+ QPicture *picture;
+#endif
+#ifndef QT_NO_MOVIE
+ QPointer<QMovie> movie;
+ void _q_movieUpdated(const QRect&);
+ void _q_movieResized(const QSize&);
+#endif
+#ifndef QT_NO_SHORTCUT
+ void updateShortcut();
+#endif
+#ifndef QT_NO_SHORTCUT
+ QPointer<QWidget> buddy;
+ int shortcutId;
+#endif
+ ushort align;
+ short indent;
+ uint scaledcontents :1;
+ mutable uint textLayoutDirty : 1;
+ mutable uint textDirty : 1;
+ mutable uint isRichText : 1;
+ mutable uint isTextLabel : 1;
+ mutable uint hasShortcut : 1;
+ Qt::TextFormat textformat;
+ mutable QWidgetTextControl *control;
+ mutable QTextCursor shortcutCursor;
+ Qt::TextInteractionFlags textInteractionFlags;
+
+ inline bool needTextControl() const {
+ return isTextLabel
+ && (isRichText
+ || (!isRichText && (textInteractionFlags & (Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard))));
+ }
+
+ void ensureTextPopulated() const;
+ void ensureTextLayouted() const;
+ void ensureTextControl() const;
+ void sendControlEvent(QEvent *e);
+
+ void _q_linkHovered(const QString &link);
+
+ QRectF layoutRect() const;
+ QRect documentRect() const;
+ QPoint layoutPoint(const QPoint& p) const;
+ Qt::LayoutDirection textDirection() const;
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *createStandardContextMenu(const QPoint &pos);
+#endif
+
+ bool openExternalLinks;
+
+#ifndef QT_NO_CURSOR
+ uint validCursor : 1;
+ uint onAnchor : 1;
+ QCursor cursor;
+#endif
+
+ friend class QMessageBoxPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QLABEL_P_H
diff --git a/src/widgets/widgets/qlcdnumber.cpp b/src/widgets/widgets/qlcdnumber.cpp
new file mode 100644
index 0000000000..1e034cf3ed
--- /dev/null
+++ b/src/widgets/widgets/qlcdnumber.cpp
@@ -0,0 +1,1312 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlcdnumber.h"
+#ifndef QT_NO_LCDNUMBER
+#include "qbitarray.h"
+#include "qpainter.h"
+#include "private/qframe_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLCDNumberPrivate : public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QLCDNumber)
+public:
+ void init();
+ void internalSetString(const QString& s);
+ void drawString(const QString& s, QPainter &, QBitArray * = 0, bool = true);
+ //void drawString(const QString &, QPainter &, QBitArray * = 0) const;
+ void drawDigit(const QPoint &, QPainter &, int, char, char = ' ');
+ void drawSegment(const QPoint &, char, QPainter &, int, bool = false);
+
+ int ndigits;
+ double val;
+ uint base : 2;
+ uint smallPoint : 1;
+ uint fill : 1;
+ uint shadow : 1;
+ QString digitStr;
+ QBitArray points;
+};
+
+/*!
+ \class QLCDNumber
+
+ \brief The QLCDNumber widget displays a number with LCD-like digits.
+
+ \ingroup basicwidgets
+
+
+ It can display a number in just about any size. It can display
+ decimal, hexadecimal, octal or binary numbers. It is easy to
+ connect to data sources using the display() slot, which is
+ overloaded to take any of five argument types.
+
+ There are also slots to change the base with setMode() and the
+ decimal point with setSmallDecimalPoint().
+
+ QLCDNumber emits the overflow() signal when it is asked to display
+ something beyond its range. The range is set by setDigitCount(),
+ but setSmallDecimalPoint() also influences it. If the display is
+ set to hexadecimal, octal or binary, the integer equivalent of the
+ value is displayed.
+
+ These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
+ 6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
+ P, r, u, U, Y, colon, degree sign (which is specified as single
+ quote in the string) and space. QLCDNumber substitutes spaces for
+ illegal characters.
+
+ It is not possible to retrieve the contents of a QLCDNumber
+ object, although you can retrieve the numeric value with value().
+ If you really need the text, we recommend that you connect the
+ signals that feed the display() slot to another slot as well and
+ store the value there.
+
+ Incidentally, QLCDNumber is the very oldest part of Qt, tracing
+ its roots back to a BASIC program on the \link
+ http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
+ Sinclair Spectrum\endlink.
+
+ \table
+ \row \o \inlineimage motif-lcdnumber.png Screenshot of a Motif style LCD number widget
+ \inlineimage cde-lcdnumber.png Screenshot of a CDE style LCD number widget
+ \inlineimage windows-lcdnumber.png Screenshot of a Windows style LCD number widget
+ \inlineimage windowsxp-lcdnumber.png Screenshot of a Windows XP style LCD number widget
+ \inlineimage macintosh-lcdnumber.png Screenshot of a Macintosh style LCD number widget
+ \inlineimage plastique-lcdnumber.png Screenshot of a Plastique style LCD number widget
+ \row \o LCD number widgets shown in various widget styles (from left to right):
+ \l{Motif Style Widget Gallery}{Motif}, \l{CDE Style Widget Gallery}{CDE},
+ \l{Windows Style Widget Gallery}{Windows}, \l{Windows XP Style Widget Gallery}{Windows XP},
+ \l{Macintosh Style Widget Gallery}{Macintosh}, \l{Plastique Style Widget Gallery}{Plastique}.
+ \endtable
+
+ \sa QLabel, QFrame, {Digital Clock Example}, {Tetrix Example}
+*/
+
+/*!
+ \enum QLCDNumber::Mode
+
+ This type determines how numbers are shown.
+
+ \value Hex Hexadecimal
+ \value Dec Decimal
+ \value Oct Octal
+ \value Bin Binary
+ \omitvalue HEX
+ \omitvalue DEC
+ \omitvalue OCT
+ \omitvalue BIN
+
+ If the display is set to hexadecimal, octal or binary, the integer
+ equivalent of the value is displayed.
+*/
+
+/*!
+ \enum QLCDNumber::SegmentStyle
+
+ This type determines the visual appearance of the QLCDNumber
+ widget.
+
+ \value Outline gives raised segments filled with the background color.
+ \value Filled gives raised segments filled with the windowText color.
+ \value Flat gives flat segments filled with the windowText color.
+*/
+
+
+
+/*!
+ \fn void QLCDNumber::overflow()
+
+ This signal is emitted whenever the QLCDNumber is asked to display
+ a too-large number or a too-long string.
+
+ It is never emitted by setDigitCount().
+*/
+
+
+static QString int2string(int num, int base, int ndigits, bool *oflow)
+{
+ QString s;
+ bool negative;
+ if (num < 0) {
+ negative = true;
+ num = -num;
+ } else {
+ negative = false;
+ }
+ switch(base) {
+ case QLCDNumber::Hex:
+ s.sprintf("%*x", ndigits, num);
+ break;
+ case QLCDNumber::Dec:
+ s.sprintf("%*i", ndigits, num);
+ break;
+ case QLCDNumber::Oct:
+ s.sprintf("%*o", ndigits, num);
+ break;
+ case QLCDNumber::Bin:
+ {
+ char buf[42];
+ char *p = &buf[41];
+ uint n = num;
+ int len = 0;
+ *p = '\0';
+ do {
+ *--p = (char)((n&1)+'0');
+ n >>= 1;
+ len++;
+ } while (n != 0);
+ len = ndigits - len;
+ if (len > 0)
+ s.fill(QLatin1Char(' '), len);
+ s += QString::fromLatin1(p);
+ }
+ break;
+ }
+ if (negative) {
+ for (int i=0; i<(int)s.length(); i++) {
+ if (s[i] != QLatin1Char(' ')) {
+ if (i != 0) {
+ s[i-1] = QLatin1Char('-');
+ } else {
+ s.insert(0, QLatin1Char('-'));
+ }
+ break;
+ }
+ }
+ }
+ if (oflow)
+ *oflow = (int)s.length() > ndigits;
+ return s;
+}
+
+
+static QString double2string(double num, int base, int ndigits, bool *oflow)
+{
+ QString s;
+ if (base != QLCDNumber::Dec) {
+ bool of = num >= 2147483648.0 || num < -2147483648.0;
+ if (of) { // oops, integer overflow
+ if (oflow)
+ *oflow = true;
+ return s;
+ }
+ s = int2string((int)num, base, ndigits, 0);
+ } else { // decimal base
+ int nd = ndigits;
+ do {
+ s.sprintf("%*.*g", ndigits, nd, num);
+ int i = s.indexOf(QLatin1Char('e'));
+ if (i > 0 && s[i+1]==QLatin1Char('+')) {
+ s[i] = QLatin1Char(' ');
+ s[i+1] = QLatin1Char('e');
+ }
+ } while (nd-- && (int)s.length() > ndigits);
+ }
+ if (oflow)
+ *oflow = (int)s.length() > ndigits;
+ return s;
+}
+
+
+static const char *getSegments(char ch) // gets list of segments for ch
+{
+ static const char segments[30][8] =
+ { { 0, 1, 2, 4, 5, 6,99, 0}, // 0 0 / O
+ { 2, 5,99, 0, 0, 0, 0, 0}, // 1 1
+ { 0, 2, 3, 4, 6,99, 0, 0}, // 2 2
+ { 0, 2, 3, 5, 6,99, 0, 0}, // 3 3
+ { 1, 2, 3, 5,99, 0, 0, 0}, // 4 4
+ { 0, 1, 3, 5, 6,99, 0, 0}, // 5 5 / S
+ { 0, 1, 3, 4, 5, 6,99, 0}, // 6 6
+ { 0, 2, 5,99, 0, 0, 0, 0}, // 7 7
+ { 0, 1, 2, 3, 4, 5, 6,99}, // 8 8
+ { 0, 1, 2, 3, 5, 6,99, 0}, // 9 9 / g
+ { 3,99, 0, 0, 0, 0, 0, 0}, // 10 -
+ { 7,99, 0, 0, 0, 0, 0, 0}, // 11 .
+ { 0, 1, 2, 3, 4, 5,99, 0}, // 12 A
+ { 1, 3, 4, 5, 6,99, 0, 0}, // 13 B
+ { 0, 1, 4, 6,99, 0, 0, 0}, // 14 C
+ { 2, 3, 4, 5, 6,99, 0, 0}, // 15 D
+ { 0, 1, 3, 4, 6,99, 0, 0}, // 16 E
+ { 0, 1, 3, 4,99, 0, 0, 0}, // 17 F
+ { 1, 3, 4, 5,99, 0, 0, 0}, // 18 h
+ { 1, 2, 3, 4, 5,99, 0, 0}, // 19 H
+ { 1, 4, 6,99, 0, 0, 0, 0}, // 20 L
+ { 3, 4, 5, 6,99, 0, 0, 0}, // 21 o
+ { 0, 1, 2, 3, 4,99, 0, 0}, // 22 P
+ { 3, 4,99, 0, 0, 0, 0, 0}, // 23 r
+ { 4, 5, 6,99, 0, 0, 0, 0}, // 24 u
+ { 1, 2, 4, 5, 6,99, 0, 0}, // 25 U
+ { 1, 2, 3, 5, 6,99, 0, 0}, // 26 Y
+ { 8, 9,99, 0, 0, 0, 0, 0}, // 27 :
+ { 0, 1, 2, 3,99, 0, 0, 0}, // 28 '
+ {99, 0, 0, 0, 0, 0, 0, 0} }; // 29 empty
+
+ if (ch >= '0' && ch <= '9')
+ return segments[ch - '0'];
+ if (ch >= 'A' && ch <= 'F')
+ return segments[ch - 'A' + 12];
+ if (ch >= 'a' && ch <= 'f')
+ return segments[ch - 'a' + 12];
+
+ int n;
+ switch (ch) {
+ case '-':
+ n = 10; break;
+ case 'O':
+ n = 0; break;
+ case 'g':
+ n = 9; break;
+ case '.':
+ n = 11; break;
+ case 'h':
+ n = 18; break;
+ case 'H':
+ n = 19; break;
+ case 'l':
+ case 'L':
+ n = 20; break;
+ case 'o':
+ n = 21; break;
+ case 'p':
+ case 'P':
+ n = 22; break;
+ case 'r':
+ case 'R':
+ n = 23; break;
+ case 's':
+ case 'S':
+ n = 5; break;
+ case 'u':
+ n = 24; break;
+ case 'U':
+ n = 25; break;
+ case 'y':
+ case 'Y':
+ n = 26; break;
+ case ':':
+ n = 27; break;
+ case '\'':
+ n = 28; break;
+ default:
+ n = 29; break;
+ }
+ return segments[n];
+}
+
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+ Constructs an LCD number, sets the number of digits to 5, the base
+ to decimal, the decimal point mode to 'small' and the frame style
+ to a raised box. The segmentStyle() is set to \c Outline.
+
+ The \a parent and \a name arguments are passed to the QFrame
+ constructor.
+
+ \sa setDigitCount(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(QWidget *parent, const char *name)
+ : QFrame(*new QLCDNumberPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ Q_D(QLCDNumber);
+ d->ndigits = 5;
+ d->init();
+}
+
+
+/*! \obsolete
+ Constructs an LCD number, sets the number of digits to \a
+ numDigits, the base to decimal, the decimal point mode to 'small'
+ and the frame style to a raised box. The segmentStyle() is set to
+ \c Outline.
+
+ The \a parent and \a name arguments are passed to the QFrame
+ constructor.
+
+ \sa setDigitCount(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent, const char *name)
+ : QFrame(*new QLCDNumberPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ Q_D(QLCDNumber);
+ d->ndigits = numDigits;
+ d->init();
+}
+#endif //QT3_SUPPORT
+
+/*!
+ Constructs an LCD number, sets the number of digits to 5, the base
+ to decimal, the decimal point mode to 'small' and the frame style
+ to a raised box. The segmentStyle() is set to \c Outline.
+
+ The \a parent argument is passed to the QFrame constructor.
+
+ \sa setDigitCount(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(QWidget *parent)
+ : QFrame(*new QLCDNumberPrivate, parent)
+{
+ Q_D(QLCDNumber);
+ d->ndigits = 5;
+ d->init();
+}
+
+
+/*!
+ Constructs an LCD number, sets the number of digits to \a
+ numDigits, the base to decimal, the decimal point mode to 'small'
+ and the frame style to a raised box. The segmentStyle() is set to
+ \c Filled.
+
+ The \a parent argument is passed to the QFrame constructor.
+
+ \sa setDigitCount(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent)
+ : QFrame(*new QLCDNumberPrivate, parent)
+{
+ Q_D(QLCDNumber);
+ d->ndigits = numDigits;
+ d->init();
+}
+
+void QLCDNumberPrivate::init()
+{
+ Q_Q(QLCDNumber);
+
+ q->setFrameStyle(QFrame::Box | QFrame::Raised);
+ val = 0;
+ base = QLCDNumber::Dec;
+ smallPoint = false;
+ q->setDigitCount(ndigits);
+ q->setSegmentStyle(QLCDNumber::Filled);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
+}
+
+/*!
+ Destroys the LCD number.
+*/
+
+QLCDNumber::~QLCDNumber()
+{
+}
+
+
+/*!
+ \deprecated
+ \property QLCDNumber::numDigits
+ \brief the current number of digits displayed
+ \sa digitCount
+*/
+
+void QLCDNumber::setNumDigits(int numDigits)
+{
+ setDigitCount(numDigits);
+}
+
+/*!
+ \since 4.6
+ \property QLCDNumber::digitCount
+ \brief the current number of digits displayed
+
+ Corresponds to the current number of digits. If \l
+ QLCDNumber::smallDecimalPoint is false, the decimal point occupies
+ one digit position.
+
+ By default, this property contains a value of 5.
+
+ \sa smallDecimalPoint
+*/
+
+/*!
+ Sets the current number of digits to \a numDigits. Must
+ be in the range 0..99.
+ */
+void QLCDNumber::setDigitCount(int numDigits)
+{
+ Q_D(QLCDNumber);
+ if (numDigits > 99) {
+ qWarning("QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
+ objectName().toLocal8Bit().constData());
+ numDigits = 99;
+ }
+ if (numDigits < 0) {
+ qWarning("QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
+ objectName().toLocal8Bit().constData());
+ numDigits = 0;
+ }
+ if (d->digitStr.isNull()) { // from constructor
+ d->ndigits = numDigits;
+ d->digitStr.fill(QLatin1Char(' '), d->ndigits);
+ d->points.fill(0, d->ndigits);
+ d->digitStr[d->ndigits - 1] = QLatin1Char('0'); // "0" is the default number
+ } else {
+ bool doDisplay = d->ndigits == 0;
+ if (numDigits == d->ndigits) // no change
+ return;
+ register int i;
+ int dif;
+ if (numDigits > d->ndigits) { // expand
+ dif = numDigits - d->ndigits;
+ QString buf;
+ buf.fill(QLatin1Char(' '), dif);
+ d->digitStr.insert(0, buf);
+ d->points.resize(numDigits);
+ for (i=numDigits-1; i>=dif; i--)
+ d->points.setBit(i, d->points.testBit(i-dif));
+ for (i=0; i<dif; i++)
+ d->points.clearBit(i);
+ } else { // shrink
+ dif = d->ndigits - numDigits;
+ d->digitStr = d->digitStr.right(numDigits);
+ QBitArray tmpPoints = d->points;
+ d->points.resize(numDigits);
+ for (i=0; i<(int)numDigits; i++)
+ d->points.setBit(i, tmpPoints.testBit(i+dif));
+ }
+ d->ndigits = numDigits;
+ if (doDisplay)
+ display(value());
+ update();
+ }
+}
+
+int QLCDNumber::numDigits() const
+{
+ Q_D(const QLCDNumber);
+ return d->ndigits;
+}
+
+/*!
+ Returns the current number of digits.
+ */
+int QLCDNumber::digitCount() const
+{
+ Q_D(const QLCDNumber);
+ return d->ndigits;
+}
+
+/*!
+ \overload
+
+ Returns true if \a num is too big to be displayed in its entirety;
+ otherwise returns false.
+
+ \sa display(), digitCount(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow(int num) const
+{
+ Q_D(const QLCDNumber);
+ bool of;
+ int2string(num, d->base, d->ndigits, &of);
+ return of;
+}
+
+
+/*!
+ Returns true if \a num is too big to be displayed in its entirety;
+ otherwise returns false.
+
+ \sa display(), digitCount(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow(double num) const
+{
+ Q_D(const QLCDNumber);
+ bool of;
+ double2string(num, d->base, d->ndigits, &of);
+ return of;
+}
+
+
+/*!
+ \property QLCDNumber::mode
+ \brief the current display mode (number base)
+
+ Corresponds to the current display mode, which is one of \c Bin,
+ \c Oct, \c Dec (the default) and \c Hex. \c Dec mode can display
+ floating point values, the other modes display the integer
+ equivalent.
+
+ \sa smallDecimalPoint(), setHexMode(), setDecMode(), setOctMode(), setBinMode()
+*/
+
+QLCDNumber::Mode QLCDNumber::mode() const
+{
+ Q_D(const QLCDNumber);
+ return (QLCDNumber::Mode) d->base;
+}
+
+void QLCDNumber::setMode(Mode m)
+{
+ Q_D(QLCDNumber);
+ d->base = m;
+ display(d->val);
+}
+
+
+/*!
+ \property QLCDNumber::value
+ \brief the displayed value
+
+ This property corresponds to the current value displayed by the
+ LCDNumber.
+
+ If the displayed value is not a number, the property has a value
+ of 0.
+
+ By default, this property contains a value of 0.
+*/
+
+double QLCDNumber::value() const
+{
+ Q_D(const QLCDNumber);
+ return d->val;
+}
+
+/*!
+ \overload
+
+ Displays the number \a num.
+*/
+void QLCDNumber::display(double num)
+{
+ Q_D(QLCDNumber);
+ d->val = num;
+ bool of;
+ QString s = double2string(d->val, d->base, d->ndigits, &of);
+ if (of)
+ emit overflow();
+ else
+ d->internalSetString(s);
+}
+
+/*!
+ \property QLCDNumber::intValue
+ \brief the displayed value rounded to the nearest integer
+
+ This property corresponds to the nearest integer to the current
+ value displayed by the LCDNumber. This is the value used for
+ hexadecimal, octal and binary modes.
+
+ If the displayed value is not a number, the property has a value
+ of 0.
+
+ By default, this property contains a value of 0.
+*/
+int QLCDNumber::intValue() const
+{
+ Q_D(const QLCDNumber);
+ return qRound(d->val);
+}
+
+
+/*!
+ \overload
+
+ Displays the number \a num.
+*/
+void QLCDNumber::display(int num)
+{
+ Q_D(QLCDNumber);
+ d->val = (double)num;
+ bool of;
+ QString s = int2string(num, d->base, d->ndigits, &of);
+ if (of)
+ emit overflow();
+ else
+ d->internalSetString(s);
+}
+
+
+/*!
+ Displays the number represented by the string \a s.
+
+ This version of the function disregards mode() and
+ smallDecimalPoint().
+
+ These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
+ 6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
+ P, r, u, U, Y, colon, degree sign (which is specified as single
+ quote in the string) and space. QLCDNumber substitutes spaces for
+ illegal characters.
+*/
+
+void QLCDNumber::display(const QString &s)
+{
+ Q_D(QLCDNumber);
+ d->val = 0;
+ bool ok = false;
+ double v = s.toDouble(&ok);
+ if (ok)
+ d->val = v;
+ d->internalSetString(s);
+}
+
+/*!
+ Calls setMode(Hex). Provided for convenience (e.g. for
+ connecting buttons to it).
+
+ \sa setMode(), setDecMode(), setOctMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setHexMode()
+{
+ setMode(Hex);
+}
+
+
+/*!
+ Calls setMode(Dec). Provided for convenience (e.g. for
+ connecting buttons to it).
+
+ \sa setMode(), setHexMode(), setOctMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setDecMode()
+{
+ setMode(Dec);
+}
+
+
+/*!
+ Calls setMode(Oct). Provided for convenience (e.g. for
+ connecting buttons to it).
+
+ \sa setMode(), setHexMode(), setDecMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setOctMode()
+{
+ setMode(Oct);
+}
+
+
+/*!
+ Calls setMode(Bin). Provided for convenience (e.g. for
+ connecting buttons to it).
+
+ \sa setMode(), setHexMode(), setDecMode(), setOctMode(), mode()
+*/
+
+void QLCDNumber::setBinMode()
+{
+ setMode(Bin);
+}
+
+
+/*!
+ \property QLCDNumber::smallDecimalPoint
+ \brief the style of the decimal point
+
+ If true the decimal point is drawn between two digit positions.
+ Otherwise it occupies a digit position of its own, i.e. is drawn
+ in a digit position. The default is false.
+
+ The inter-digit space is made slightly wider when the decimal
+ point is drawn between the digits.
+
+ \sa mode
+*/
+
+void QLCDNumber::setSmallDecimalPoint(bool b)
+{
+ Q_D(QLCDNumber);
+ d->smallPoint = b;
+ update();
+}
+
+bool QLCDNumber::smallDecimalPoint() const
+{
+ Q_D(const QLCDNumber);
+ return d->smallPoint;
+}
+
+
+
+/*!\reimp
+*/
+
+
+void QLCDNumber::paintEvent(QPaintEvent *)
+{
+ Q_D(QLCDNumber);
+ QPainter p(this);
+ drawFrame(&p);
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->shadow)
+ p.translate(0.5, 0.5);
+
+ if (d->smallPoint)
+ d->drawString(d->digitStr, p, &d->points, false);
+ else
+ d->drawString(d->digitStr, p, 0, false);
+}
+
+
+void QLCDNumberPrivate::internalSetString(const QString& s)
+{
+ Q_Q(QLCDNumber);
+ QString buffer;
+ int i;
+ int len = s.length();
+ QBitArray newPoints(ndigits);
+
+ if (!smallPoint) {
+ if (len == ndigits)
+ buffer = s;
+ else
+ buffer = s.right(ndigits).rightJustified(ndigits, QLatin1Char(' '));
+ } else {
+ int index = -1;
+ bool lastWasPoint = true;
+ newPoints.clearBit(0);
+ for (i=0; i<len; i++) {
+ if (s[i] == QLatin1Char('.')) {
+ if (lastWasPoint) { // point already set for digit?
+ if (index == ndigits - 1) // no more digits
+ break;
+ index++;
+ buffer[index] = QLatin1Char(' '); // 2 points in a row, add space
+ }
+ newPoints.setBit(index); // set decimal point
+ lastWasPoint = true;
+ } else {
+ if (index == ndigits - 1)
+ break;
+ index++;
+ buffer[index] = s[i];
+ newPoints.clearBit(index); // decimal point default off
+ lastWasPoint = false;
+ }
+ }
+ if (index < ((int) ndigits) - 1) {
+ for(i=index; i>=0; i--) {
+ buffer[ndigits - 1 - index + i] = buffer[i];
+ newPoints.setBit(ndigits - 1 - index + i,
+ newPoints.testBit(i));
+ }
+ for(i=0; i<ndigits-index-1; i++) {
+ buffer[i] = QLatin1Char(' ');
+ newPoints.clearBit(i);
+ }
+ }
+ }
+
+ if (buffer == digitStr)
+ return;
+
+ digitStr = buffer;
+ if (smallPoint)
+ points = newPoints;
+ q->update();
+}
+
+/*!
+ \internal
+*/
+
+void QLCDNumberPrivate::drawString(const QString &s, QPainter &p,
+ QBitArray *newPoints, bool newString)
+{
+ Q_Q(QLCDNumber);
+ QPoint pos;
+
+ int digitSpace = smallPoint ? 2 : 1;
+ int xSegLen = q->width()*5/(ndigits*(5 + digitSpace) + digitSpace);
+ int ySegLen = q->height()*5/12;
+ int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
+ int xAdvance = segLen*(5 + digitSpace)/5;
+ int xOffset = (q->width() - ndigits*xAdvance + segLen/5)/2;
+ int yOffset = (q->height() - segLen*2)/2;
+
+ for (int i=0; i<ndigits; i++) {
+ pos = QPoint(xOffset + xAdvance*i, yOffset);
+ if (newString)
+ drawDigit(pos, p, segLen, s[i].toLatin1(), digitStr[i].toLatin1());
+ else
+ drawDigit(pos, p, segLen, s[i].toLatin1());
+ if (newPoints) {
+ char newPoint = newPoints->testBit(i) ? '.' : ' ';
+ if (newString) {
+ char oldPoint = points.testBit(i) ? '.' : ' ';
+ drawDigit(pos, p, segLen, newPoint, oldPoint);
+ } else {
+ drawDigit(pos, p, segLen, newPoint);
+ }
+ }
+ }
+ if (newString) {
+ digitStr = s;
+ digitStr.truncate(ndigits);
+ if (newPoints)
+ points = *newPoints;
+ }
+}
+
+
+/*!
+ \internal
+*/
+
+void QLCDNumberPrivate::drawDigit(const QPoint &pos, QPainter &p, int segLen,
+ char newCh, char oldCh)
+{
+// Draws and/or erases segments to change display of a single digit
+// from oldCh to newCh
+
+ char updates[18][2]; // can hold 2 times number of segments, only
+ // first 9 used if segment table is correct
+ int nErases;
+ int nUpdates;
+ const char *segs;
+ int i,j;
+
+ const char erase = 0;
+ const char draw = 1;
+ const char leaveAlone = 2;
+
+ segs = getSegments(oldCh);
+ for (nErases=0; segs[nErases] != 99; nErases++) {
+ updates[nErases][0] = erase; // get segments to erase to
+ updates[nErases][1] = segs[nErases]; // remove old char
+ }
+ nUpdates = nErases;
+ segs = getSegments(newCh);
+ for(i = 0 ; segs[i] != 99 ; i++) {
+ for (j=0; j<nErases; j++)
+ if (segs[i] == updates[j][1]) { // same segment ?
+ updates[j][0] = leaveAlone; // yes, already on screen
+ break;
+ }
+ if (j == nErases) { // if not already on screen
+ updates[nUpdates][0] = draw;
+ updates[nUpdates][1] = segs[i];
+ nUpdates++;
+ }
+ }
+ for (i=0; i<nUpdates; i++) {
+ if (updates[i][0] == draw)
+ drawSegment(pos, updates[i][1], p, segLen);
+ if (updates[i][0] == erase)
+ drawSegment(pos, updates[i][1], p, segLen, true);
+ }
+}
+
+
+static void addPoint(QPolygon &a, const QPoint &p)
+{
+ uint n = a.size();
+ a.resize(n + 1);
+ a.setPoint(n, p);
+}
+
+/*!
+ \internal
+*/
+
+void QLCDNumberPrivate::drawSegment(const QPoint &pos, char segmentNo, QPainter &p,
+ int segLen, bool erase)
+{
+ Q_Q(QLCDNumber);
+ QPoint ppt;
+ QPoint pt = pos;
+ int width = segLen/5;
+
+ const QPalette &pal = q->palette();
+ QColor lightColor,darkColor,fgColor;
+ if (erase){
+ lightColor = pal.color(q->backgroundRole());
+ darkColor = lightColor;
+ fgColor = lightColor;
+ } else {
+ lightColor = pal.light().color();
+ darkColor = pal.dark().color();
+ fgColor = pal.color(q->foregroundRole());
+ }
+
+
+#define LINETO(X,Y) addPoint(a, QPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT
+#define DARK
+
+ if (fill) {
+ QPolygon a(0);
+ //The following is an exact copy of the switch below.
+ //don't make any changes here
+ switch (segmentNo) {
+ case 0 :
+ ppt = pt;
+ LIGHT;
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(segLen - width - 1,width);
+ LINETO(width,width);
+ LINETO(0,0);
+ break;
+ case 1 :
+ pt += QPoint(0 , 1);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,width);
+ DARK;
+ LINETO(width,segLen - width/2 - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 2 :
+ pt += QPoint(segLen - 1 , 1);
+ ppt = pt;
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width/2 - 2);
+ LIGHT;
+ LINETO(-width,width);
+ LINETO(0,0);
+ break;
+ case 3 :
+ pt += QPoint(0 , segLen);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,-width/2);
+ LINETO(segLen - width - 1,-width/2);
+ LINETO(segLen - 1,0);
+ DARK;
+ if (width & 1) { // adjust for integer division error
+ LINETO(segLen - width - 3,width/2 + 1);
+ LINETO(width + 2,width/2 + 1);
+ } else {
+ LINETO(segLen - width - 1,width/2);
+ LINETO(width,width/2);
+ }
+ LINETO(0,0);
+ break;
+ case 4 :
+ pt += QPoint(0 , segLen + 1);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,width/2);
+ DARK;
+ LINETO(width,segLen - width - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 5 :
+ pt += QPoint(segLen - 1 , segLen + 1);
+ ppt = pt;
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width - 2);
+ LIGHT;
+ LINETO(-width,width/2);
+ LINETO(0,0);
+ break;
+ case 6 :
+ pt += QPoint(0 , segLen*2);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,-width);
+ LINETO(segLen - width - 1,-width);
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(0,0);
+ break;
+ case 7 :
+ if (smallPoint) // if smallpoint place'.' between other digits
+ pt += QPoint(segLen + width/2 , segLen*2);
+ else
+ pt += QPoint(segLen/2 , segLen*2);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 8 :
+ pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 9 :
+ pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ default :
+ qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
+ q->objectName().toLocal8Bit().constData(), segmentNo);
+ }
+ // End exact copy
+ p.setPen(Qt::NoPen);
+ p.setBrush(fgColor);
+ p.drawPolygon(a);
+ p.setBrush(Qt::NoBrush);
+
+ pt = pos;
+ }
+#undef LINETO
+#undef LIGHT
+#undef DARK
+
+#define LINETO(X,Y) p.drawLine(ppt.x(), ppt.y(), pt.x()+(X), pt.y()+(Y)); \
+ ppt = QPoint(pt.x()+(X), pt.y()+(Y))
+#define LIGHT p.setPen(lightColor)
+#define DARK p.setPen(darkColor)
+ if (shadow)
+ switch (segmentNo) {
+ case 0 :
+ ppt = pt;
+ LIGHT;
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(segLen - width - 1,width);
+ LINETO(width,width);
+ LINETO(0,0);
+ break;
+ case 1 :
+ pt += QPoint(0,1);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,width);
+ DARK;
+ LINETO(width,segLen - width/2 - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 2 :
+ pt += QPoint(segLen - 1 , 1);
+ ppt = pt;
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width/2 - 2);
+ LIGHT;
+ LINETO(-width,width);
+ LINETO(0,0);
+ break;
+ case 3 :
+ pt += QPoint(0 , segLen);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,-width/2);
+ LINETO(segLen - width - 1,-width/2);
+ LINETO(segLen - 1,0);
+ DARK;
+ if (width & 1) { // adjust for integer division error
+ LINETO(segLen - width - 3,width/2 + 1);
+ LINETO(width + 2,width/2 + 1);
+ } else {
+ LINETO(segLen - width - 1,width/2);
+ LINETO(width,width/2);
+ }
+ LINETO(0,0);
+ break;
+ case 4 :
+ pt += QPoint(0 , segLen + 1);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,width/2);
+ DARK;
+ LINETO(width,segLen - width - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 5 :
+ pt += QPoint(segLen - 1 , segLen + 1);
+ ppt = pt;
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width - 2);
+ LIGHT;
+ LINETO(-width,width/2);
+ LINETO(0,0);
+ break;
+ case 6 :
+ pt += QPoint(0 , segLen*2);
+ ppt = pt;
+ LIGHT;
+ LINETO(width,-width);
+ LINETO(segLen - width - 1,-width);
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(0,0);
+ break;
+ case 7 :
+ if (smallPoint) // if smallpoint place'.' between other digits
+ pt += QPoint(segLen + width/2 , segLen*2);
+ else
+ pt += QPoint(segLen/2 , segLen*2);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 8 :
+ pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 9 :
+ pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+ ppt = pt;
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ default :
+ qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
+ q->objectName().toLocal8Bit().constData(), segmentNo);
+ }
+
+#undef LINETO
+#undef LIGHT
+#undef DARK
+}
+
+
+
+/*!
+ \property QLCDNumber::segmentStyle
+ \brief the style of the LCDNumber
+
+ \table
+ \header \i Style \i Result
+ \row \i \c Outline
+ \i Produces raised segments filled with the background color
+ \row \i \c Filled
+ (this is the default).
+ \i Produces raised segments filled with the foreground color.
+ \row \i \c Flat
+ \i Produces flat segments filled with the foreground color.
+ \endtable
+
+ \c Outline and \c Filled will additionally use
+ QPalette::light() and QPalette::dark() for shadow effects.
+*/
+void QLCDNumber::setSegmentStyle(SegmentStyle s)
+{
+ Q_D(QLCDNumber);
+ d->fill = (s == Flat || s == Filled);
+ d->shadow = (s == Outline || s == Filled);
+ update();
+}
+
+QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
+{
+ Q_D(const QLCDNumber);
+ Q_ASSERT(d->fill || d->shadow);
+ if (!d->fill && d->shadow)
+ return Outline;
+ if (d->fill && d->shadow)
+ return Filled;
+ return Flat;
+}
+
+
+/*!\reimp
+*/
+QSize QLCDNumber::sizeHint() const
+{
+ return QSize(10 + 9 * (digitCount() + (smallDecimalPoint() ? 0 : 1)), 23);
+}
+
+/*! \reimp */
+bool QLCDNumber::event(QEvent *e)
+{
+ return QFrame::event(e);
+}
+
+/*!
+ \fn void QLCDNumber::setMargin(int margin)
+ Sets the width of the margin around the contents of the widget to \a margin.
+
+ Use QWidget::setContentsMargins() instead.
+ \sa margin(), QWidget::setContentsMargins()
+*/
+
+/*!
+ \fn int QLCDNumber::margin() const
+ Returns the width of the margin around the contents of the widget.
+
+ Use QWidget::getContentsMargins() instead.
+ \sa setMargin(), QWidget::getContentsMargins()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LCDNUMBER
diff --git a/src/widgets/widgets/qlcdnumber.h b/src/widgets/widgets/qlcdnumber.h
new file mode 100644
index 0000000000..7b104cbfcf
--- /dev/null
+++ b/src/widgets/widgets/qlcdnumber.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLCDNUMBER_H
+#define QLCDNUMBER_H
+
+#include <QtWidgets/qframe.h>
+#include <QtCore/qbitarray.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_LCDNUMBER
+
+class QLCDNumberPrivate;
+class Q_WIDGETS_EXPORT QLCDNumber : public QFrame // LCD number widget
+{
+ Q_OBJECT
+ Q_ENUMS(Mode SegmentStyle)
+ Q_PROPERTY(bool smallDecimalPoint READ smallDecimalPoint WRITE setSmallDecimalPoint)
+ Q_PROPERTY(int numDigits READ numDigits WRITE setNumDigits)
+ Q_PROPERTY(int digitCount READ digitCount WRITE setDigitCount)
+ Q_PROPERTY(Mode mode READ mode WRITE setMode)
+ Q_PROPERTY(SegmentStyle segmentStyle READ segmentStyle WRITE setSegmentStyle)
+ Q_PROPERTY(double value READ value WRITE display)
+ Q_PROPERTY(int intValue READ intValue WRITE display)
+
+public:
+ explicit QLCDNumber(QWidget* parent = 0);
+ explicit QLCDNumber(uint numDigits, QWidget* parent = 0);
+ ~QLCDNumber();
+
+ enum Mode {
+ Hex, Dec, Oct, Bin
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ , HEX = Hex, DEC = Dec, OCT = Oct, BIN = Bin
+#endif
+ };
+ enum SegmentStyle {
+ Outline, Filled, Flat
+ };
+
+ bool smallDecimalPoint() const;
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED int numDigits() const;
+ QT_DEPRECATED void setNumDigits(int nDigits);
+#endif
+ int digitCount() const;
+ void setDigitCount(int nDigits);
+
+ bool checkOverflow(double num) const;
+ bool checkOverflow(int num) const;
+
+ Mode mode() const;
+ void setMode(Mode);
+
+ SegmentStyle segmentStyle() const;
+ void setSegmentStyle(SegmentStyle);
+
+ double value() const;
+ int intValue() const;
+
+ QSize sizeHint() const;
+
+public Q_SLOTS:
+ void display(const QString &str);
+ void display(int num);
+ void display(double num);
+ void setHexMode();
+ void setDecMode();
+ void setOctMode();
+ void setBinMode();
+ void setSmallDecimalPoint(bool);
+
+Q_SIGNALS:
+ void overflow();
+
+protected:
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *);
+
+public:
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QLCDNumber(QWidget* parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QLCDNumber(uint numDigits, QWidget* parent, const char* name);
+
+ QT3_SUPPORT void setMargin(int margin) { setContentsMargins(margin, margin, margin, margin); }
+ QT3_SUPPORT int margin() const
+ { int margin; int dummy; getContentsMargins(&margin, &dummy, &dummy, &dummy); return margin; }
+#endif
+
+private:
+ Q_DISABLE_COPY(QLCDNumber)
+ Q_DECLARE_PRIVATE(QLCDNumber)
+};
+
+#endif // QT_NO_LCDNUMBER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLCDNUMBER_H
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
new file mode 100644
index 0000000000..aca15f30ed
--- /dev/null
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -0,0 +1,2363 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlineedit.h"
+#include "qlineedit_p.h"
+
+#ifndef QT_NO_LINEEDIT
+#include "qaction.h"
+#include "qapplication.h"
+#include "qclipboard.h"
+#include "qdrag.h"
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qfontmetrics.h"
+#include "qmenu.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qpointer.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtimer.h"
+#include "qvalidator.h"
+#include "qvariant.h"
+#include "qvector.h"
+#include "qwhatsthis.h"
+#include "qdebug.h"
+#include "qtextedit.h"
+#include <private/qtextedit_p.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#include "qlist.h"
+#endif
+#include "qabstractitemview.h"
+#include "private/qstylesheetstyle_p.h"
+
+#ifndef QT_NO_SHORTCUT
+#include "private/qapplication_p.h"
+#include "private/qshortcutmap_p.h"
+#include "qkeysequence.h"
+#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1Char('\t') + QString(QKeySequence(k)) : QString())
+#else
+#define ACCEL_KEY(k) QString()
+#endif
+
+#include <limits.h>
+#ifdef DrawText
+#undef DrawText
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_WS_MAC
+extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp
+#endif
+
+/*!
+ Initialize \a option with the values from this QLineEdit. This method
+ is useful for subclasses when they need a QStyleOptionFrame or QStyleOptionFrameV2, but don't want
+ to fill in all the information themselves. This function will check the version
+ of the QStyleOptionFrame and fill in the additional values for a
+ QStyleOptionFrameV2.
+
+ \sa QStyleOption::initFrom()
+*/
+void QLineEdit::initStyleOption(QStyleOptionFrame *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QLineEdit);
+ option->initFrom(this);
+ option->rect = contentsRect();
+ option->lineWidth = d->frame ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth, option, this)
+ : 0;
+ option->midLineWidth = 0;
+ option->state |= QStyle::State_Sunken;
+ if (d->control->isReadOnly())
+ option->state |= QStyle::State_ReadOnly;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (hasEditFocus())
+ option->state |= QStyle::State_HasEditFocus;
+#endif
+ if (QStyleOptionFrameV2 *optionV2 = qstyleoption_cast<QStyleOptionFrameV2 *>(option))
+ optionV2->features = QStyleOptionFrameV2::None;
+}
+
+/*!
+ \class QLineEdit
+ \brief The QLineEdit widget is a one-line text editor.
+
+ \ingroup basicwidgets
+
+
+ A line edit allows the user to enter and edit a single line of
+ plain text with a useful collection of editing functions,
+ including undo and redo, cut and paste, and drag and drop.
+
+ By changing the echoMode() of a line edit, it can also be used as
+ a "write-only" field, for inputs such as passwords.
+
+ The length of the text can be constrained to maxLength(). The text
+ can be arbitrarily constrained using a validator() or an
+ inputMask(), or both. When switching between a validator and an input mask
+ on the same line edit, it is best to clear the validator or input mask to
+ prevent undefined behavior.
+
+
+ A related class is QTextEdit which allows multi-line, rich text
+ editing.
+
+ You can change the text with setText() or insert(). The text is
+ retrieved with text(); the displayed text (which may be different,
+ see \l{EchoMode}) is retrieved with displayText(). Text can be
+ selected with setSelection() or selectAll(), and the selection can
+ be cut(), copy()ied and paste()d. The text can be aligned with
+ setAlignment().
+
+ When the text changes the textChanged() signal is emitted; when
+ the text changes other than by calling setText() the textEdited()
+ signal is emitted; when the cursor is moved the
+ cursorPositionChanged() signal is emitted; and when the Return or
+ Enter key is pressed the returnPressed() signal is emitted.
+
+ When editing is finished, either because the line edit lost focus
+ or Return/Enter is pressed the editingFinished() signal is
+ emitted.
+
+ Note that if there is a validator set on the line edit, the
+ returnPressed()/editingFinished() signals will only be emitted if
+ the validator returns QValidator::Acceptable.
+
+ By default, QLineEdits have a frame as specified by the Windows
+ and Motif style guides; you can turn it off by calling
+ setFrame(false).
+
+ The default key bindings are described below. The line edit also
+ provides a context menu (usually invoked by a right mouse click)
+ that presents some of these editing options.
+ \target desc
+ \table
+ \header \i Keypress \i Action
+ \row \i Left Arrow \i Moves the cursor one character to the left.
+ \row \i Shift+Left Arrow \i Moves and selects text one character to the left.
+ \row \i Right Arrow \i Moves the cursor one character to the right.
+ \row \i Shift+Right Arrow \i Moves and selects text one character to the right.
+ \row \i Home \i Moves the cursor to the beginning of the line.
+ \row \i End \i Moves the cursor to the end of the line.
+ \row \i Backspace \i Deletes the character to the left of the cursor.
+ \row \i Ctrl+Backspace \i Deletes the word to the left of the cursor.
+ \row \i Delete \i Deletes the character to the right of the cursor.
+ \row \i Ctrl+Delete \i Deletes the word to the right of the cursor.
+ \row \i Ctrl+A \i Select all.
+ \row \i Ctrl+C \i Copies the selected text to the clipboard.
+ \row \i Ctrl+Insert \i Copies the selected text to the clipboard.
+ \row \i Ctrl+K \i Deletes to the end of the line.
+ \row \i Ctrl+V \i Pastes the clipboard text into line edit.
+ \row \i Shift+Insert \i Pastes the clipboard text into line edit.
+ \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
+ \row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.
+ \row \i Ctrl+Z \i Undoes the last operation.
+ \row \i Ctrl+Y \i Redoes the last undone operation.
+ \endtable
+
+ Any other key sequence that represents a valid character, will
+ cause the character to be inserted into the line edit.
+
+ \table 100%
+ \row \o \inlineimage macintosh-lineedit.png Screenshot of a Macintosh style line edit
+ \o A line edit shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage windows-lineedit.png Screenshot of a Windows XP style line edit
+ \o A line edit shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-lineedit.png Screenshot of a Plastique style line edit
+ \o A line edit shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QTextEdit, QLabel, QComboBox, {fowler}{GUI Design Handbook: Field, Entry}, {Line Edits Example}
+*/
+
+
+/*!
+ \fn void QLineEdit::textChanged(const QString &text)
+
+ This signal is emitted whenever the text changes. The \a text
+ argument is the new text.
+
+ Unlike textEdited(), this signal is also emitted when the text is
+ changed programmatically, for example, by calling setText().
+*/
+
+/*!
+ \fn void QLineEdit::textEdited(const QString &text)
+
+ This signal is emitted whenever the text is edited. The \a text
+ argument is the next text.
+
+ Unlike textChanged(), this signal is not emitted when the text is
+ changed programmatically, for example, by calling setText().
+*/
+
+/*!
+ \fn void QLineEdit::cursorPositionChanged(int old, int new)
+
+ This signal is emitted whenever the cursor moves. The previous
+ position is given by \a old, and the new position by \a new.
+
+ \sa setCursorPosition(), cursorPosition()
+*/
+
+/*!
+ \fn void QLineEdit::selectionChanged()
+
+ This signal is emitted whenever the selection changes.
+
+ \sa hasSelectedText(), selectedText()
+*/
+
+/*!
+ Constructs a line edit with no text.
+
+ The maximum text length is set to 32767 characters.
+
+ The \a parent argument is sent to the QWidget constructor.
+
+ \sa setText(), setMaxLength()
+*/
+QLineEdit::QLineEdit(QWidget* parent)
+ : QWidget(*new QLineEditPrivate, parent,0)
+{
+ Q_D(QLineEdit);
+ d->init(QString());
+}
+
+/*!
+ Constructs a line edit containing the text \a contents.
+
+ The cursor position is set to the end of the line and the maximum
+ text length to 32767 characters.
+
+ The \a parent and argument is sent to the QWidget
+ constructor.
+
+ \sa text(), setMaxLength()
+*/
+QLineEdit::QLineEdit(const QString& contents, QWidget* parent)
+ : QWidget(*new QLineEditPrivate, parent, 0)
+{
+ Q_D(QLineEdit);
+ d->init(contents);
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Constructs a line edit with no text.
+
+ The maximum text length is set to 32767 characters.
+
+ The \a parent and \a name arguments are sent to the QWidget constructor.
+
+ \sa setText(), setMaxLength()
+*/
+QLineEdit::QLineEdit(QWidget* parent, const char* name)
+ : QWidget(*new QLineEditPrivate, parent,0)
+{
+ Q_D(QLineEdit);
+ setObjectName(QString::fromAscii(name));
+ d->init(QString());
+}
+
+/*!
+ Constructs a line edit containing the text \a contents.
+
+ The cursor position is set to the end of the line and the maximum
+ text length to 32767 characters.
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+
+ \sa text(), setMaxLength()
+*/
+
+QLineEdit::QLineEdit(const QString& contents, QWidget* parent, const char* name)
+ : QWidget(*new QLineEditPrivate, parent, 0)
+{
+ Q_D(QLineEdit);
+ setObjectName(QString::fromAscii(name));
+ d->init(contents);
+}
+
+/*!
+ Constructs a line edit with an input \a inputMask and the text \a
+ contents.
+
+ The cursor position is set to the end of the line and the maximum
+ text length is set to the length of the mask (the number of mask
+ characters and separators).
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+
+ \sa setMask() text()
+*/
+QLineEdit::QLineEdit(const QString& contents, const QString &inputMask, QWidget* parent, const char* name)
+ : QWidget(*new QLineEditPrivate, parent, 0)
+{
+ Q_D(QLineEdit);
+ setObjectName(QString::fromAscii(name));
+ d->init(contents);
+ d->control->setInputMask(inputMask);
+ d->control->moveCursor(d->control->nextMaskBlank(contents.length()));
+}
+#endif
+
+/*!
+ Destroys the line edit.
+*/
+
+QLineEdit::~QLineEdit()
+{
+}
+
+
+/*!
+ \property QLineEdit::text
+ \brief the line edit's text
+
+ Setting this property clears the selection, clears the undo/redo
+ history, moves the cursor to the end of the line and resets the
+ \l modified property to false. The text is not validated when
+ inserted with setText().
+
+ The text is truncated to maxLength() length.
+
+ By default, this property contains an empty string.
+
+ \sa insert(), clear()
+*/
+QString QLineEdit::text() const
+{
+ Q_D(const QLineEdit);
+ return d->control->text();
+}
+
+void QLineEdit::setText(const QString& text)
+{
+ Q_D(QLineEdit);
+ d->control->setText(text);
+}
+
+/*!
+ \since 4.7
+
+ \property QLineEdit::placeholderText
+ \brief the line edit's placeholder text
+
+ Setting this property makes the line edit display a grayed-out
+ placeholder text as long as the text() is empty and the widget doesn't
+ have focus.
+
+ By default, this property contains an empty string.
+
+ \sa text()
+*/
+QString QLineEdit::placeholderText() const
+{
+ Q_D(const QLineEdit);
+ return d->placeholderText;
+}
+
+void QLineEdit::setPlaceholderText(const QString& placeholderText)
+{
+ Q_D(QLineEdit);
+ if (d->placeholderText != placeholderText) {
+ d->placeholderText = placeholderText;
+ if (!hasFocus())
+ update();
+ }
+}
+
+/*!
+ \property QLineEdit::displayText
+ \brief the displayed text
+
+ If \l echoMode is \l Normal this returns the same as text(); if
+ \l EchoMode is \l Password or \l PasswordEchoOnEdit it returns a string of asterisks
+ text().length() characters long, e.g. "******"; if \l EchoMode is
+ \l NoEcho returns an empty string, "".
+
+ By default, this property contains an empty string.
+
+ \sa setEchoMode() text() EchoMode
+*/
+
+QString QLineEdit::displayText() const
+{
+ Q_D(const QLineEdit);
+ return d->control->displayText();
+}
+
+
+/*!
+ \property QLineEdit::maxLength
+ \brief the maximum permitted length of the text
+
+ If the text is too long, it is truncated at the limit.
+
+ If truncation occurs any selected text will be unselected, the
+ cursor position is set to 0 and the first part of the string is
+ shown.
+
+ If the line edit has an input mask, the mask defines the maximum
+ string length.
+
+ By default, this property contains a value of 32767.
+
+ \sa inputMask
+*/
+
+int QLineEdit::maxLength() const
+{
+ Q_D(const QLineEdit);
+ return d->control->maxLength();
+}
+
+void QLineEdit::setMaxLength(int maxLength)
+{
+ Q_D(QLineEdit);
+ d->control->setMaxLength(maxLength);
+}
+
+/*!
+ \property QLineEdit::frame
+ \brief whether the line edit draws itself with a frame
+
+ If enabled (the default) the line edit draws itself inside a
+ frame, otherwise the line edit draws itself without any frame.
+*/
+bool QLineEdit::hasFrame() const
+{
+ Q_D(const QLineEdit);
+ return d->frame;
+}
+
+
+void QLineEdit::setFrame(bool enable)
+{
+ Q_D(QLineEdit);
+ d->frame = enable;
+ update();
+ updateGeometry();
+}
+
+
+/*!
+ \enum QLineEdit::EchoMode
+
+ This enum type describes how a line edit should display its
+ contents.
+
+ \value Normal Display characters as they are entered. This is the
+ default.
+ \value NoEcho Do not display anything. This may be appropriate
+ for passwords where even the length of the
+ password should be kept secret.
+ \value Password Display asterisks instead of the characters
+ actually entered.
+ \value PasswordEchoOnEdit Display characters as they are entered
+ while editing otherwise display asterisks.
+
+ \sa setEchoMode() echoMode()
+*/
+
+
+/*!
+ \property QLineEdit::echoMode
+ \brief the line edit's echo mode
+
+ The echo mode determines how the text entered in the line edit is
+ displayed (or echoed) to the user.
+
+ The most common setting is \l Normal, in which the text entered by the
+ user is displayed verbatim, but QLineEdit also supports modes that allow
+ the entered text to be suppressed or obscured: these include \l NoEcho,
+ \l Password and \l PasswordEchoOnEdit.
+
+ The widget's display and the ability to copy or drag the text is
+ affected by this setting.
+
+ By default, this property is set to \l Normal.
+
+ \sa EchoMode displayText()
+*/
+
+QLineEdit::EchoMode QLineEdit::echoMode() const
+{
+ Q_D(const QLineEdit);
+ return (EchoMode) d->control->echoMode();
+}
+
+void QLineEdit::setEchoMode(EchoMode mode)
+{
+ Q_D(QLineEdit);
+ if (mode == (EchoMode)d->control->echoMode())
+ return;
+ Qt::InputMethodHints imHints = inputMethodHints();
+ if (mode == Password || mode == NoEcho) {
+ imHints |= Qt::ImhHiddenText;
+ } else {
+ imHints &= ~Qt::ImhHiddenText;
+ }
+ if (mode != Normal) {
+ imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ } else {
+ imHints &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ }
+ setInputMethodHints(imHints);
+ d->control->setEchoMode(mode);
+ update();
+#ifdef Q_WS_MAC
+ if (hasFocus())
+ qt_mac_secure_keyboard(mode == Password || mode == NoEcho);
+#endif
+}
+
+
+#ifndef QT_NO_VALIDATOR
+/*!
+ Returns a pointer to the current input validator, or 0 if no
+ validator has been set.
+
+ \sa setValidator()
+*/
+
+const QValidator * QLineEdit::validator() const
+{
+ Q_D(const QLineEdit);
+ return d->control->validator();
+}
+
+/*!
+ Sets this line edit to only accept input that the validator, \a v,
+ will accept. This allows you to place any arbitrary constraints on
+ the text which may be entered.
+
+ If \a v == 0, setValidator() removes the current input validator.
+ The initial setting is to have no input validator (i.e. any input
+ is accepted up to maxLength()).
+
+ \sa validator() QIntValidator QDoubleValidator QRegExpValidator
+*/
+
+void QLineEdit::setValidator(const QValidator *v)
+{
+ Q_D(QLineEdit);
+ d->control->setValidator(v);
+}
+#endif // QT_NO_VALIDATOR
+
+#ifndef QT_NO_COMPLETER
+/*!
+ \since 4.2
+
+ Sets this line edit to provide auto completions from the completer, \a c.
+ The completion mode is set using QCompleter::setCompletionMode().
+
+ To use a QCompleter with a QValidator or QLineEdit::inputMask, you need to
+ ensure that the model provided to QCompleter contains valid entries. You can
+ use the QSortFilterProxyModel to ensure that the QCompleter's model contains
+ only valid entries.
+
+ If \a c == 0, setCompleter() removes the current completer, effectively
+ disabling auto completion.
+
+ \sa QCompleter
+*/
+void QLineEdit::setCompleter(QCompleter *c)
+{
+ Q_D(QLineEdit);
+ if (c == d->control->completer())
+ return;
+ if (d->control->completer()) {
+ disconnect(d->control->completer(), 0, this, 0);
+ d->control->completer()->setWidget(0);
+ if (d->control->completer()->parent() == this)
+ delete d->control->completer();
+ }
+ d->control->setCompleter(c);
+ if (!c)
+ return;
+ if (c->widget() == 0)
+ c->setWidget(this);
+ if (hasFocus()) {
+ QObject::connect(d->control->completer(), SIGNAL(activated(QString)),
+ this, SLOT(setText(QString)));
+ QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)),
+ this, SLOT(_q_completionHighlighted(QString)));
+ }
+}
+
+/*!
+ \since 4.2
+
+ Returns the current QCompleter that provides completions.
+*/
+QCompleter *QLineEdit::completer() const
+{
+ Q_D(const QLineEdit);
+ return d->control->completer();
+}
+
+#endif // QT_NO_COMPLETER
+
+/*!
+ Returns a recommended size for the widget.
+
+ The width returned, in pixels, is usually enough for about 15 to
+ 20 characters.
+*/
+
+QSize QLineEdit::sizeHint() const
+{
+ Q_D(const QLineEdit);
+ ensurePolished();
+ QFontMetrics fm(font());
+ int h = qMax(fm.height(), 14) + 2*d->verticalMargin
+ + d->topTextMargin + d->bottomTextMargin
+ + d->topmargin + d->bottommargin;
+ int w = fm.width(QLatin1Char('x')) * 17 + 2*d->horizontalMargin
+ + d->leftTextMargin + d->rightTextMargin
+ + d->leftmargin + d->rightmargin; // "some"
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
+ expandedTo(QApplication::globalStrut()), this));
+}
+
+
+/*!
+ Returns a minimum size for the line edit.
+
+ The width returned is enough for at least one character.
+*/
+
+QSize QLineEdit::minimumSizeHint() const
+{
+ Q_D(const QLineEdit);
+ ensurePolished();
+ QFontMetrics fm = fontMetrics();
+ int h = fm.height() + qMax(2*d->verticalMargin, fm.leading())
+ + d->topmargin + d->bottommargin;
+ int w = fm.maxWidth() + d->leftmargin + d->rightmargin;
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
+ expandedTo(QApplication::globalStrut()), this));
+}
+
+
+/*!
+ \property QLineEdit::cursorPosition
+ \brief the current cursor position for this line edit
+
+ Setting the cursor position causes a repaint when appropriate.
+
+ By default, this property contains a value of 0.
+*/
+
+int QLineEdit::cursorPosition() const
+{
+ Q_D(const QLineEdit);
+ return d->control->cursorPosition();
+}
+
+void QLineEdit::setCursorPosition(int pos)
+{
+ Q_D(QLineEdit);
+ d->control->setCursorPosition(pos);
+}
+
+/*!
+ Returns the cursor position under the point \a pos.
+*/
+// ### What should this do if the point is outside of contentsRect? Currently returns 0.
+int QLineEdit::cursorPositionAt(const QPoint &pos)
+{
+ Q_D(QLineEdit);
+ return d->xToPos(pos.x());
+}
+
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+
+ Use setText(), setCursorPosition() and setSelection() instead.
+*/
+bool QLineEdit::validateAndSet(const QString &newText, int newPos,
+ int newMarkAnchor, int newMarkDrag)
+{
+ // The suggested functions above in the docs don't seem to validate,
+ // below code tries to mimic previous behaviour.
+ QString oldText = text();
+ setText(newText);
+ if(!hasAcceptableInput()){
+ setText(oldText);
+ return false;
+ }
+ int selstart = qMin(newMarkAnchor, newMarkDrag);
+ int sellength = qAbs(newMarkAnchor - newMarkDrag);
+ if (selstart == newPos) {
+ selstart = qMax(newMarkAnchor, newMarkDrag);
+ sellength = -sellength;
+ }
+ //setSelection also set the position
+ setSelection(selstart, sellength);
+ return true;
+}
+#endif //QT3_SUPPORT
+
+/*!
+ \property QLineEdit::alignment
+ \brief the alignment of the line edit
+
+ Both horizontal and vertical alignment is allowed here, Qt::AlignJustify
+ will map to Qt::AlignLeft.
+
+ By default, this property contains a combination of Qt::AlignLeft and Qt::AlignVCenter.
+
+ \sa Qt::Alignment
+*/
+
+Qt::Alignment QLineEdit::alignment() const
+{
+ Q_D(const QLineEdit);
+ return QFlag(d->alignment);
+}
+
+void QLineEdit::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QLineEdit);
+ d->alignment = alignment;
+ update();
+}
+
+
+/*!
+ Moves the cursor forward \a steps characters. If \a mark is true
+ each character moved over is added to the selection; if \a mark is
+ false the selection is cleared.
+
+ \sa cursorBackward()
+*/
+
+void QLineEdit::cursorForward(bool mark, int steps)
+{
+ Q_D(QLineEdit);
+ d->control->cursorForward(mark, steps);
+}
+
+
+/*!
+ Moves the cursor back \a steps characters. If \a mark is true each
+ character moved over is added to the selection; if \a mark is
+ false the selection is cleared.
+
+ \sa cursorForward()
+*/
+void QLineEdit::cursorBackward(bool mark, int steps)
+{
+ cursorForward(mark, -steps);
+}
+
+/*!
+ Moves the cursor one word forward. If \a mark is true, the word is
+ also selected.
+
+ \sa cursorWordBackward()
+*/
+void QLineEdit::cursorWordForward(bool mark)
+{
+ Q_D(QLineEdit);
+ d->control->cursorWordForward(mark);
+}
+
+/*!
+ Moves the cursor one word backward. If \a mark is true, the word
+ is also selected.
+
+ \sa cursorWordForward()
+*/
+
+void QLineEdit::cursorWordBackward(bool mark)
+{
+ Q_D(QLineEdit);
+ d->control->cursorWordBackward(mark);
+}
+
+
+/*!
+ If no text is selected, deletes the character to the left of the
+ text cursor and moves the cursor one position to the left. If any
+ text is selected, the cursor is moved to the beginning of the
+ selected text and the selected text is deleted.
+
+ \sa del()
+*/
+void QLineEdit::backspace()
+{
+ Q_D(QLineEdit);
+ d->control->backspace();
+}
+
+/*!
+ If no text is selected, deletes the character to the right of the
+ text cursor. If any text is selected, the cursor is moved to the
+ beginning of the selected text and the selected text is deleted.
+
+ \sa backspace()
+*/
+
+void QLineEdit::del()
+{
+ Q_D(QLineEdit);
+ d->control->del();
+}
+
+/*!
+ Moves the text cursor to the beginning of the line unless it is
+ already there. If \a mark is true, text is selected towards the
+ first position; otherwise, any selected text is unselected if the
+ cursor is moved.
+
+ \sa end()
+*/
+
+void QLineEdit::home(bool mark)
+{
+ Q_D(QLineEdit);
+ d->control->home(mark);
+}
+
+/*!
+ Moves the text cursor to the end of the line unless it is already
+ there. If \a mark is true, text is selected towards the last
+ position; otherwise, any selected text is unselected if the cursor
+ is moved.
+
+ \sa home()
+*/
+
+void QLineEdit::end(bool mark)
+{
+ Q_D(QLineEdit);
+ d->control->end(mark);
+}
+
+
+/*!
+ \property QLineEdit::modified
+ \brief whether the line edit's contents has been modified by the user
+
+ The modified flag is never read by QLineEdit; it has a default value
+ of false and is changed to true whenever the user changes the line
+ edit's contents.
+
+ This is useful for things that need to provide a default value but
+ do not start out knowing what the default should be (perhaps it
+ depends on other fields on the form). Start the line edit without
+ the best default, and when the default is known, if modified()
+ returns false (the user hasn't entered any text), insert the
+ default value.
+
+ Calling setText() resets the modified flag to false.
+*/
+
+bool QLineEdit::isModified() const
+{
+ Q_D(const QLineEdit);
+ return d->control->isModified();
+}
+
+void QLineEdit::setModified(bool modified)
+{
+ Q_D(QLineEdit);
+ d->control->setModified(modified);
+}
+
+
+/*!\fn QLineEdit::clearModified()
+
+Use setModified(false) instead.
+
+ \sa isModified()
+*/
+
+
+/*!
+ \property QLineEdit::hasSelectedText
+ \brief whether there is any text selected
+
+ hasSelectedText() returns true if some or all of the text has been
+ selected by the user; otherwise returns false.
+
+ By default, this property is false.
+
+ \sa selectedText()
+*/
+
+
+bool QLineEdit::hasSelectedText() const
+{
+ Q_D(const QLineEdit);
+ return d->control->hasSelectedText();
+}
+
+/*!
+ \property QLineEdit::selectedText
+ \brief the selected text
+
+ If there is no selected text this property's value is
+ an empty string.
+
+ By default, this property contains an empty string.
+
+ \sa hasSelectedText()
+*/
+
+QString QLineEdit::selectedText() const
+{
+ Q_D(const QLineEdit);
+ return d->control->selectedText();
+}
+
+/*!
+ selectionStart() returns the index of the first selected character in the
+ line edit or -1 if no text is selected.
+
+ \sa selectedText()
+*/
+
+int QLineEdit::selectionStart() const
+{
+ Q_D(const QLineEdit);
+ return d->control->selectionStart();
+}
+
+
+#ifdef QT3_SUPPORT
+
+/*!
+ \fn void QLineEdit::lostFocus()
+
+ This signal is emitted when the line edit has lost focus.
+
+ Use editingFinished() instead
+ \sa editingFinished(), returnPressed()
+*/
+
+/*!
+ Use isModified() instead.
+*/
+bool QLineEdit::edited() const { return isModified(); }
+/*!
+ Use setModified() or setText().
+*/
+void QLineEdit::setEdited(bool on) { setModified(on); }
+
+/*!
+ There exists no equivalent functionality in Qt 4.
+*/
+int QLineEdit::characterAt(int xpos, QChar *chr) const
+{
+ Q_D(const QLineEdit);
+ int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + d->horizontalMargin);
+ QString txt = d->control->text();
+ if (chr && pos < (int) txt.length())
+ *chr = txt.at(pos);
+ return pos;
+
+}
+
+/*!
+ Use selectedText() and selectionStart() instead.
+*/
+bool QLineEdit::getSelection(int *start, int *end)
+{
+ Q_D(QLineEdit);
+ if (d->control->hasSelectedText() && start && end) {
+ *start = selectionStart();
+ *end = *start + selectedText().length();
+ return true;
+ }
+ return false;
+}
+#endif
+
+
+/*!
+ Selects text from position \a start and for \a length characters.
+ Negative lengths are allowed.
+
+ \sa deselect() selectAll() selectedText()
+*/
+
+void QLineEdit::setSelection(int start, int length)
+{
+ Q_D(QLineEdit);
+ if (start < 0 || start > (int)d->control->text().length()) {
+ qWarning("QLineEdit::setSelection: Invalid start position (%d)", start);
+ return;
+ }
+
+ d->control->setSelection(start, length);
+
+ if (d->control->hasSelectedText()){
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ if (!style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
+ d->setCursorVisible(false);
+ }
+}
+
+
+/*!
+ \property QLineEdit::undoAvailable
+ \brief whether undo is available
+
+ Undo becomes available once the user has modified the text in the line edit.
+
+ By default, this property is false.
+*/
+
+bool QLineEdit::isUndoAvailable() const
+{
+ Q_D(const QLineEdit);
+ return d->control->isUndoAvailable();
+}
+
+/*!
+ \property QLineEdit::redoAvailable
+ \brief whether redo is available
+
+ Redo becomes available once the user has performed one or more undo operations
+ on text in the line edit.
+
+ By default, this property is false.
+*/
+
+bool QLineEdit::isRedoAvailable() const
+{
+ Q_D(const QLineEdit);
+ return d->control->isRedoAvailable();
+}
+
+/*!
+ \property QLineEdit::dragEnabled
+ \brief whether the lineedit starts a drag if the user presses and
+ moves the mouse on some selected text
+
+ Dragging is disabled by default.
+*/
+
+bool QLineEdit::dragEnabled() const
+{
+ Q_D(const QLineEdit);
+ return d->dragEnabled;
+}
+
+void QLineEdit::setDragEnabled(bool b)
+{
+ Q_D(QLineEdit);
+ d->dragEnabled = b;
+}
+
+
+/*!
+ \property QLineEdit::cursorMoveStyle
+ \brief the movement style of cursor in this line edit
+ \since 4.8
+
+ When this property is set to Qt::VisualMoveStyle, the line edit will use visual
+ movement style. Pressing the left arrow key will always cause the cursor to move
+ left, regardless of the text's writing direction. The same behavior applies to
+ right arrow key.
+
+ When the property is Qt::LogicalMoveStyle (the default), within a LTR text block,
+ increase cursor position when pressing left arrow key, decrease cursor position
+ when pressing the right arrow key. If the text block is right to left, the opposite
+ behavior applies.
+*/
+
+Qt::CursorMoveStyle QLineEdit::cursorMoveStyle() const
+{
+ Q_D(const QLineEdit);
+ return d->control->cursorMoveStyle();
+}
+
+void QLineEdit::setCursorMoveStyle(Qt::CursorMoveStyle style)
+{
+ Q_D(QLineEdit);
+ d->control->setCursorMoveStyle(style);
+}
+
+/*!
+ \property QLineEdit::acceptableInput
+ \brief whether the input satisfies the inputMask and the
+ validator.
+
+ By default, this property is true.
+
+ \sa setInputMask(), setValidator()
+*/
+bool QLineEdit::hasAcceptableInput() const
+{
+ Q_D(const QLineEdit);
+ return d->control->hasAcceptableInput();
+}
+
+/*!
+ Sets the margins around the text inside the frame to have the
+ sizes \a left, \a top, \a right, and \a bottom.
+ \since 4.5
+
+ See also getTextMargins().
+*/
+void QLineEdit::setTextMargins(int left, int top, int right, int bottom)
+{
+ Q_D(QLineEdit);
+ d->leftTextMargin = left;
+ d->topTextMargin = top;
+ d->rightTextMargin = right;
+ d->bottomTextMargin = bottom;
+ updateGeometry();
+ update();
+}
+
+/*!
+ \since 4.6
+ Sets the \a margins around the text inside the frame.
+
+ See also textMargins().
+*/
+void QLineEdit::setTextMargins(const QMargins &margins)
+{
+ setTextMargins(margins.left(), margins.top(), margins.right(), margins.bottom());
+}
+
+/*!
+ Returns the widget's text margins for \a left, \a top, \a right, and \a bottom.
+ \since 4.5
+
+ \sa setTextMargins()
+*/
+void QLineEdit::getTextMargins(int *left, int *top, int *right, int *bottom) const
+{
+ Q_D(const QLineEdit);
+ if (left)
+ *left = d->leftTextMargin;
+ if (top)
+ *top = d->topTextMargin;
+ if (right)
+ *right = d->rightTextMargin;
+ if (bottom)
+ *bottom = d->bottomTextMargin;
+}
+
+/*!
+ \since 4.6
+ Returns the widget's text margins.
+
+ \sa setTextMargins()
+*/
+QMargins QLineEdit::textMargins() const
+{
+ Q_D(const QLineEdit);
+ return QMargins(d->leftTextMargin, d->topTextMargin, d->rightTextMargin, d->bottomTextMargin);
+}
+
+/*!
+ \property QLineEdit::inputMask
+ \brief The validation input mask
+
+ If no mask is set, inputMask() returns an empty string.
+
+ Sets the QLineEdit's validation mask. Validators can be used
+ instead of, or in conjunction with masks; see setValidator().
+
+ Unset the mask and return to normal QLineEdit operation by passing
+ an empty string ("") or just calling setInputMask() with no
+ arguments.
+
+ The table below shows the characters that can be used in an input mask.
+ A space character, the default character for a blank, is needed for cases
+ where a character is \e{permitted but not required}.
+
+ \table
+ \header \i Character \i Meaning
+ \row \i \c A \i ASCII alphabetic character required. A-Z, a-z.
+ \row \i \c a \i ASCII alphabetic character permitted but not required.
+ \row \i \c N \i ASCII alphanumeric character required. A-Z, a-z, 0-9.
+ \row \i \c n \i ASCII alphanumeric character permitted but not required.
+ \row \i \c X \i Any character required.
+ \row \i \c x \i Any character permitted but not required.
+ \row \i \c 9 \i ASCII digit required. 0-9.
+ \row \i \c 0 \i ASCII digit permitted but not required.
+ \row \i \c D \i ASCII digit required. 1-9.
+ \row \i \c d \i ASCII digit permitted but not required (1-9).
+ \row \i \c # \i ASCII digit or plus/minus sign permitted but not required.
+ \row \i \c H \i Hexadecimal character required. A-F, a-f, 0-9.
+ \row \i \c h \i Hexadecimal character permitted but not required.
+ \row \i \c B \i Binary character required. 0-1.
+ \row \i \c b \i Binary character permitted but not required.
+ \row \i \c > \i All following alphabetic characters are uppercased.
+ \row \i \c < \i All following alphabetic characters are lowercased.
+ \row \i \c ! \i Switch off case conversion.
+ \row \i \tt{\\} \i Use \tt{\\} to escape the special
+ characters listed above to use them as
+ separators.
+ \endtable
+
+ The mask consists of a string of mask characters and separators,
+ optionally followed by a semicolon and the character used for
+ blanks. The blank characters are always removed from the text
+ after editing.
+
+ Examples:
+ \table
+ \header \i Mask \i Notes
+ \row \i \c 000.000.000.000;_ \i IP address; blanks are \c{_}.
+ \row \i \c HH:HH:HH:HH:HH:HH;_ \i MAC address
+ \row \i \c 0000-00-00 \i ISO Date; blanks are \c space
+ \row \i \c >AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;# \i License number;
+ blanks are \c - and all (alphabetic) characters are converted to
+ uppercase.
+ \endtable
+
+ To get range control (e.g., for an IP address) use masks together
+ with \link setValidator() validators\endlink.
+
+ \sa maxLength
+*/
+QString QLineEdit::inputMask() const
+{
+ Q_D(const QLineEdit);
+ return d->control->inputMask();
+}
+
+void QLineEdit::setInputMask(const QString &inputMask)
+{
+ Q_D(QLineEdit);
+ d->control->setInputMask(inputMask);
+}
+
+/*!
+ Selects all the text (i.e. highlights it) and moves the cursor to
+ the end. This is useful when a default value has been inserted
+ because if the user types before clicking on the widget, the
+ selected text will be deleted.
+
+ \sa setSelection() deselect()
+*/
+
+void QLineEdit::selectAll()
+{
+ Q_D(QLineEdit);
+ d->control->selectAll();
+}
+
+/*!
+ Deselects any selected text.
+
+ \sa setSelection() selectAll()
+*/
+
+void QLineEdit::deselect()
+{
+ Q_D(QLineEdit);
+ d->control->deselect();
+}
+
+
+/*!
+ Deletes any selected text, inserts \a newText, and validates the
+ result. If it is valid, it sets it as the new contents of the line
+ edit.
+
+ \sa setText(), clear()
+*/
+void QLineEdit::insert(const QString &newText)
+{
+// q->resetInputContext(); //#### FIX ME IN QT
+ Q_D(QLineEdit);
+ d->control->insert(newText);
+}
+
+/*!
+ Clears the contents of the line edit.
+
+ \sa setText(), insert()
+*/
+void QLineEdit::clear()
+{
+ Q_D(QLineEdit);
+ resetInputContext();
+ d->control->clear();
+}
+
+/*!
+ Undoes the last operation if undo is \link
+ QLineEdit::undoAvailable available\endlink. Deselects any current
+ selection, and updates the selection start to the current cursor
+ position.
+*/
+void QLineEdit::undo()
+{
+ Q_D(QLineEdit);
+ resetInputContext();
+ d->control->undo();
+}
+
+/*!
+ Redoes the last operation if redo is \link
+ QLineEdit::redoAvailable available\endlink.
+*/
+void QLineEdit::redo()
+{
+ Q_D(QLineEdit);
+ resetInputContext();
+ d->control->redo();
+}
+
+
+/*!
+ \property QLineEdit::readOnly
+ \brief whether the line edit is read only.
+
+ In read-only mode, the user can still copy the text to the
+ clipboard, or drag and drop the text (if echoMode() is \l Normal),
+ but cannot edit it.
+
+ QLineEdit does not show a cursor in read-only mode.
+
+ By default, this property is false.
+
+ \sa setEnabled()
+*/
+
+bool QLineEdit::isReadOnly() const
+{
+ Q_D(const QLineEdit);
+ return d->control->isReadOnly();
+}
+
+void QLineEdit::setReadOnly(bool enable)
+{
+ Q_D(QLineEdit);
+ if (d->control->isReadOnly() != enable) {
+ d->control->setReadOnly(enable);
+ setAttribute(Qt::WA_MacShowFocusRect, !enable);
+ setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod());
+#ifndef QT_NO_CURSOR
+ setCursor(enable ? Qt::ArrowCursor : Qt::IBeamCursor);
+#endif
+ update();
+ }
+}
+
+
+#ifndef QT_NO_CLIPBOARD
+/*!
+ Copies the selected text to the clipboard and deletes it, if there
+ is any, and if echoMode() is \l Normal.
+
+ If the current validator disallows deleting the selected text,
+ cut() will copy without deleting.
+
+ \sa copy() paste() setValidator()
+*/
+
+void QLineEdit::cut()
+{
+ if (hasSelectedText()) {
+ copy();
+ del();
+ }
+}
+
+
+/*!
+ Copies the selected text to the clipboard, if there is any, and if
+ echoMode() is \l Normal.
+
+ \sa cut() paste()
+*/
+
+void QLineEdit::copy() const
+{
+ Q_D(const QLineEdit);
+ d->control->copy();
+}
+
+/*!
+ Inserts the clipboard's text at the cursor position, deleting any
+ selected text, providing the line edit is not \link
+ QLineEdit::readOnly read-only\endlink.
+
+ If the end result would not be acceptable to the current
+ \link setValidator() validator\endlink, nothing happens.
+
+ \sa copy() cut()
+*/
+
+void QLineEdit::paste()
+{
+ Q_D(QLineEdit);
+ d->control->paste();
+}
+
+#endif // !QT_NO_CLIPBOARD
+
+/*! \reimp
+*/
+bool QLineEdit::event(QEvent * e)
+{
+ Q_D(QLineEdit);
+ if (e->type() == QEvent::Timer) {
+ // should be timerEvent, is here for binary compatibility
+ int timerId = ((QTimerEvent*)e)->timerId();
+ if (false) {
+#ifndef QT_NO_DRAGANDDROP
+ } else if (timerId == d->dndTimer.timerId()) {
+ d->drag();
+#endif
+ }
+ else if (timerId == d->tripleClickTimer.timerId())
+ d->tripleClickTimer.stop();
+ } else if (e->type() == QEvent::ContextMenu) {
+#ifndef QT_NO_IM
+ if (d->control->composeMode())
+ return true;
+#endif
+ //d->separate();
+ } else if (e->type() == QEvent::WindowActivate) {
+ QTimer::singleShot(0, this, SLOT(_q_handleWindowActivate()));
+ }else if(e->type() == QEvent::ShortcutOverride){
+ d->control->processEvent(e);
+ } else if (e->type() == QEvent::KeyRelease) {
+ d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime());
+ } else if (e->type() == QEvent::Show) {
+ //In order to get the cursor blinking if QComboBox::setEditable is called when the combobox has focus
+ if (hasFocus()) {
+ d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime());
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ if ((!hasSelectedText() && d->control->preeditAreaText().isEmpty())
+ || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
+ d->setCursorVisible(true);
+ }
+ }
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled()) {
+ if (e->type() == QEvent::EnterEditFocus) {
+ end(false);
+ d->setCursorVisible(true);
+ d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime());
+ } else if (e->type() == QEvent::LeaveEditFocus) {
+ d->setCursorVisible(false);
+ d->control->setCursorBlinkPeriod(0);
+ if (d->control->hasAcceptableInput() || d->control->fixup())
+ emit editingFinished();
+ }
+ }
+#endif
+ return QWidget::event(e);
+}
+
+/*! \reimp
+*/
+void QLineEdit::mousePressEvent(QMouseEvent* e)
+{
+ Q_D(QLineEdit);
+ if (d->sendMouseEventToInputContext(e))
+ return;
+ if (e->button() == Qt::RightButton)
+ return;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ setEditFocus(true);
+ // Get the completion list to pop up.
+ if (d->control->completer())
+ d->control->completer()->complete();
+ }
+#endif
+ if (d->tripleClickTimer.isActive() && (e->pos() - d->tripleClick).manhattanLength() <
+ QApplication::startDragDistance()) {
+ selectAll();
+ return;
+ }
+ bool mark = e->modifiers() & Qt::ShiftModifier;
+ int cursor = d->xToPos(e->pos().x());
+#ifndef QT_NO_DRAGANDDROP
+ if (!mark && d->dragEnabled && d->control->echoMode() == Normal &&
+ e->button() == Qt::LeftButton && d->control->inSelection(e->pos().x())) {
+ d->dndPos = e->pos();
+ if (!d->dndTimer.isActive())
+ d->dndTimer.start(QApplication::startDragTime(), this);
+ } else
+#endif
+ {
+ d->control->moveCursor(cursor, mark);
+ }
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseMoveEvent(QMouseEvent * e)
+{
+ Q_D(QLineEdit);
+ if (d->sendMouseEventToInputContext(e))
+ return;
+
+ if (e->buttons() & Qt::LeftButton) {
+#ifndef QT_NO_DRAGANDDROP
+ if (d->dndTimer.isActive()) {
+ if ((d->dndPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
+ d->drag();
+ } else
+#endif
+ {
+ d->control->moveCursor(d->xToPos(e->pos().x()), true);
+ }
+ }
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseReleaseEvent(QMouseEvent* e)
+{
+ Q_D(QLineEdit);
+ if (d->sendMouseEventToInputContext(e))
+ return;
+#ifndef QT_NO_DRAGANDDROP
+ if (e->button() == Qt::LeftButton) {
+ if (d->dndTimer.isActive()) {
+ d->dndTimer.stop();
+ deselect();
+ return;
+ }
+ }
+#endif
+#ifndef QT_NO_CLIPBOARD
+ if (QApplication::clipboard()->supportsSelection()) {
+ if (e->button() == Qt::LeftButton) {
+ d->control->copy(QClipboard::Selection);
+ } else if (!d->control->isReadOnly() && e->button() == Qt::MidButton) {
+ deselect();
+ insert(QApplication::clipboard()->text(QClipboard::Selection));
+ }
+ }
+#endif
+
+ if (!isReadOnly() && rect().contains(e->pos()))
+ d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
+ d->clickCausedFocus = 0;
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e)
+{
+ Q_D(QLineEdit);
+ if (d->sendMouseEventToInputContext(e))
+ return;
+ if (e->button() == Qt::LeftButton) {
+ d->control->selectWordAtPos(d->xToPos(e->pos().x()));
+ d->tripleClickTimer.start(QApplication::doubleClickInterval(), this);
+ d->tripleClick = e->pos();
+ }
+}
+
+/*!
+ \fn void QLineEdit::returnPressed()
+
+ This signal is emitted when the Return or Enter key is pressed.
+ Note that if there is a validator() or inputMask() set on the line
+ edit, the returnPressed() signal will only be emitted if the input
+ follows the inputMask() and the validator() returns
+ QValidator::Acceptable.
+*/
+
+/*!
+ \fn void QLineEdit::editingFinished()
+
+ This signal is emitted when the Return or Enter key is pressed or
+ the line edit loses focus. Note that if there is a validator() or
+ inputMask() set on the line edit and enter/return is pressed, the
+ editingFinished() signal will only be emitted if the input follows
+ the inputMask() and the validator() returns QValidator::Acceptable.
+*/
+
+/*!
+ Converts the given key press \a event into a line edit action.
+
+ If Return or Enter is pressed and the current text is valid (or
+ can be \link QValidator::fixup() made valid\endlink by the
+ validator), the signal returnPressed() is emitted.
+
+ The default key bindings are listed in the class's detailed
+ description.
+*/
+
+void QLineEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QLineEdit);
+ #ifdef QT_KEYPAD_NAVIGATION
+ bool select = false;
+ switch (event->key()) {
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (hasEditFocus()) {
+ setEditFocus(false);
+ if (d->control->completer() && d->control->completer()->popup()->isVisible())
+ d->control->completer()->popup()->hide();
+ select = true;
+ }
+ }
+ break;
+ case Qt::Key_Back:
+ case Qt::Key_No:
+ if (!QApplication::keypadNavigationEnabled() || !hasEditFocus()) {
+ event->ignore();
+ return;
+ }
+ break;
+ default:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus() && !(event->modifiers() & Qt::ControlModifier)) {
+ if (!event->text().isEmpty() && event->text().at(0).isPrint()
+ && !isReadOnly())
+ setEditFocus(true);
+ else {
+ event->ignore();
+ return;
+ }
+ }
+ }
+ }
+
+
+
+ if (QApplication::keypadNavigationEnabled() && !select && !hasEditFocus()) {
+ setEditFocus(true);
+ if (event->key() == Qt::Key_Select)
+ return; // Just start. No action.
+ }
+#endif
+ d->control->processKeyEvent(event);
+ if (event->isAccepted()) {
+ if (layoutDirection() != d->control->layoutDirection())
+ setLayoutDirection(d->control->layoutDirection());
+ d->control->setCursorBlinkPeriod(0);
+ }
+}
+
+/*!
+ \since 4.4
+
+ Returns a rectangle that includes the lineedit cursor.
+*/
+QRect QLineEdit::cursorRect() const
+{
+ Q_D(const QLineEdit);
+ return d->cursorRect();
+}
+
+/*! \reimp
+ */
+void QLineEdit::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QLineEdit);
+ if (d->control->isReadOnly()) {
+ e->ignore();
+ return;
+ }
+
+ if (echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing()) {
+ // Clear the edit and reset to normal echo mode while entering input
+ // method data; the echo mode switches back when the edit loses focus.
+ // ### changes a public property, resets current content.
+ d->updatePasswordEchoEditing(true);
+ clear();
+ }
+
+#ifdef QT_KEYPAD_NAVIGATION
+ // Focus in if currently in navigation focus on the widget
+ // Only focus in on preedits, to allow input methods to
+ // commit text as they focus out without interfering with focus
+ if (QApplication::keypadNavigationEnabled()
+ && hasFocus() && !hasEditFocus()
+ && !e->preeditString().isEmpty())
+ setEditFocus(true);
+#endif
+
+ d->control->processInputMethodEvent(e);
+
+#ifndef QT_NO_COMPLETER
+ if (!e->commitString().isEmpty())
+ d->control->complete(Qt::Key_unknown);
+#endif
+}
+
+/*!\reimp
+*/
+QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QLineEdit);
+ switch(property) {
+ case Qt::ImCursorRectangle:
+ return d->cursorRect();
+ case Qt::ImFont:
+ return font();
+ case Qt::ImCursorPosition:
+ return QVariant(d->control->cursor());
+ case Qt::ImSurroundingText:
+ return QVariant(text());
+ case Qt::ImCurrentSelection:
+ return QVariant(selectedText());
+ case Qt::ImMaximumTextLength:
+ return QVariant(maxLength());
+ case Qt::ImAnchorPosition:
+ if (d->control->selectionStart() == d->control->selectionEnd())
+ return QVariant(d->control->cursor());
+ else if (d->control->selectionStart() == d->control->cursor())
+ return QVariant(d->control->selectionEnd());
+ else
+ return QVariant(d->control->selectionStart());
+ default:
+ return QVariant();
+ }
+}
+
+/*!\reimp
+*/
+
+void QLineEdit::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QLineEdit);
+ if (e->reason() == Qt::TabFocusReason ||
+ e->reason() == Qt::BacktabFocusReason ||
+ e->reason() == Qt::ShortcutFocusReason) {
+ if (!d->control->inputMask().isEmpty())
+ d->control->moveCursor(d->control->nextMaskBlank(0));
+ else if (!d->control->hasSelectedText())
+ selectAll();
+ } else if (e->reason() == Qt::MouseFocusReason) {
+ d->clickCausedFocus = 1;
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && ( e->reason() == Qt::PopupFocusReason
+#ifdef Q_OS_SYMBIAN
+ || e->reason() == Qt::ActiveWindowFocusReason
+#endif
+ ))) {
+#endif
+ d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime());
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ if((!hasSelectedText() && d->control->preeditAreaText().isEmpty())
+ || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
+ d->setCursorVisible(true);
+#ifdef Q_WS_MAC
+ if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho)
+ qt_mac_secure_keyboard(true);
+#endif
+#ifdef QT_KEYPAD_NAVIGATION
+ d->control->setCancelText(d->control->text());
+ }
+#endif
+#ifndef QT_NO_COMPLETER
+ if (d->control->completer()) {
+ d->control->completer()->setWidget(this);
+ QObject::connect(d->control->completer(), SIGNAL(activated(QString)),
+ this, SLOT(setText(QString)));
+ QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)),
+ this, SLOT(_q_completionHighlighted(QString)));
+ }
+#endif
+ update();
+}
+
+/*!\reimp
+*/
+
+void QLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QLineEdit);
+ if (d->control->passwordEchoEditing()) {
+ // Reset the echomode back to PasswordEchoOnEdit when the widget loses
+ // focus.
+ d->updatePasswordEchoEditing(false);
+ }
+
+ Qt::FocusReason reason = e->reason();
+ if (reason != Qt::ActiveWindowFocusReason &&
+ reason != Qt::PopupFocusReason)
+ deselect();
+
+ d->setCursorVisible(false);
+ d->control->setCursorBlinkPeriod(0);
+#ifdef QT_KEYPAD_NAVIGATION
+ // editingFinished() is already emitted on LeaveEditFocus
+ if (!QApplication::keypadNavigationEnabled())
+#endif
+ if (reason != Qt::PopupFocusReason
+ || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) {
+ if (hasAcceptableInput() || d->control->fixup())
+ emit editingFinished();
+#ifdef QT3_SUPPORT
+ emit lostFocus();
+#endif
+ }
+#ifdef Q_WS_MAC
+ if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho)
+ qt_mac_secure_keyboard(false);
+#endif
+#ifdef QT_KEYPAD_NAVIGATION
+ d->control->setCancelText(QString());
+#endif
+#ifndef QT_NO_COMPLETER
+ if (d->control->completer()) {
+ QObject::disconnect(d->control->completer(), 0, this, 0);
+ }
+#endif
+ update();
+}
+
+/*!\reimp
+*/
+void QLineEdit::paintEvent(QPaintEvent *)
+{
+ Q_D(QLineEdit);
+ QPainter p(this);
+
+ QRect r = rect();
+ QPalette pal = palette();
+
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
+ r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+ r.setX(r.x() + d->leftTextMargin);
+ r.setY(r.y() + d->topTextMargin);
+ r.setRight(r.right() - d->rightTextMargin);
+ r.setBottom(r.bottom() - d->bottomTextMargin);
+ p.setClipRect(r);
+
+ QFontMetrics fm = fontMetrics();
+ Qt::Alignment va = QStyle::visualAlignment(d->control->layoutDirection(), QFlag(d->alignment));
+ switch (va & Qt::AlignVertical_Mask) {
+ case Qt::AlignBottom:
+ d->vscroll = r.y() + r.height() - fm.height() - d->verticalMargin;
+ break;
+ case Qt::AlignTop:
+ d->vscroll = r.y() + d->verticalMargin;
+ break;
+ default:
+ //center
+ d->vscroll = r.y() + (r.height() - fm.height() + 1) / 2;
+ break;
+ }
+ QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height());
+
+ int minLB = qMax(0, -fm.minLeftBearing());
+ int minRB = qMax(0, -fm.minRightBearing());
+
+ if (d->control->text().isEmpty()) {
+ if (!hasFocus() && !d->placeholderText.isEmpty()) {
+ QColor col = pal.text().color();
+ col.setAlpha(128);
+ QPen oldpen = p.pen();
+ p.setPen(col);
+ lineRect.adjust(minLB, 0, 0, 0);
+ QString elidedText = fm.elidedText(d->placeholderText, Qt::ElideRight, lineRect.width());
+ p.drawText(lineRect, va, elidedText);
+ p.setPen(oldpen);
+ return;
+ }
+ }
+
+ int cix = qRound(d->control->cursorToX());
+
+ // horizontal scrolling. d->hscroll is the left indent from the beginning
+ // of the text line to the left edge of lineRect. we update this value
+ // depending on the delta from the last paint event; in effect this means
+ // the below code handles all scrolling based on the textline (widthUsed,
+ // minLB, minRB), the line edit rect (lineRect) and the cursor position
+ // (cix).
+ int widthUsed = qRound(d->control->naturalTextWidth()) + 1 + minRB;
+ if ((minLB + widthUsed) <= lineRect.width()) {
+ // text fits in lineRect; use hscroll for alignment
+ switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+ case Qt::AlignRight:
+ d->hscroll = widthUsed - lineRect.width() + 1;
+ break;
+ case Qt::AlignHCenter:
+ d->hscroll = (widthUsed - lineRect.width()) / 2;
+ break;
+ default:
+ // Left
+ d->hscroll = 0;
+ break;
+ }
+ d->hscroll -= minLB;
+ } else if (cix - d->hscroll >= lineRect.width()) {
+ // text doesn't fit, cursor is to the right of lineRect (scroll right)
+ d->hscroll = cix - lineRect.width() + 1;
+ } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) {
+ // text doesn't fit, cursor is to the left of lineRect (scroll left)
+ d->hscroll = cix;
+ } else if (widthUsed - d->hscroll < lineRect.width()) {
+ // text doesn't fit, text document is to the left of lineRect; align
+ // right
+ d->hscroll = widthUsed - lineRect.width() + 1;
+ } else {
+ //in case the text is bigger than the lineedit, the hscroll can never be negative
+ d->hscroll = qMax(0, d->hscroll);
+ }
+
+ // the y offset is there to keep the baseline constant in case we have script changes in the text.
+ QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
+
+ // draw text, selections and cursors
+#ifndef QT_NO_STYLE_STYLESHEET
+ if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style())) {
+ cssStyle->styleSheetPalette(this, &panel, &pal);
+ }
+#endif
+ p.setPen(pal.text().color());
+
+ int flags = QWidgetLineControl::DrawText;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled() || hasEditFocus())
+#endif
+ if (d->control->hasSelectedText() || (d->cursorVisible && !d->control->inputMask().isEmpty() && !d->control->isReadOnly())){
+ flags |= QWidgetLineControl::DrawSelections;
+ // Palette only used for selections/mask and may not be in sync
+ if (d->control->palette() != pal
+ || d->control->palette().currentColorGroup() != pal.currentColorGroup())
+ d->control->setPalette(pal);
+ }
+
+ // Asian users see an IM selection text as cursor on candidate
+ // selection phase of input method, so the ordinary cursor should be
+ // invisible if we have a preedit string.
+ if (d->cursorVisible && !d->control->isReadOnly())
+ flags |= QWidgetLineControl::DrawCursor;
+
+ d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth));
+ d->control->draw(&p, topLeft, r, flags);
+
+}
+
+
+#ifndef QT_NO_DRAGANDDROP
+/*!\reimp
+*/
+void QLineEdit::dragMoveEvent(QDragMoveEvent *e)
+{
+ Q_D(QLineEdit);
+ if (!d->control->isReadOnly() && e->mimeData()->hasFormat(QLatin1String("text/plain"))) {
+ e->acceptProposedAction();
+ d->control->moveCursor(d->xToPos(e->pos().x()), false);
+ d->cursorVisible = true;
+ update();
+ }
+}
+
+/*!\reimp */
+void QLineEdit::dragEnterEvent(QDragEnterEvent * e)
+{
+ QLineEdit::dragMoveEvent(e);
+}
+
+/*!\reimp */
+void QLineEdit::dragLeaveEvent(QDragLeaveEvent *)
+{
+ Q_D(QLineEdit);
+ if (d->cursorVisible) {
+ d->cursorVisible = false;
+ update();
+ }
+}
+
+/*!\reimp */
+void QLineEdit::dropEvent(QDropEvent* e)
+{
+ Q_D(QLineEdit);
+ QString str = e->mimeData()->text();
+
+ if (!str.isNull() && !d->control->isReadOnly()) {
+ if (e->source() == this && e->dropAction() == Qt::CopyAction)
+ deselect();
+ int cursorPos = d->xToPos(e->pos().x());
+ int selStart = cursorPos;
+ int oldSelStart = d->control->selectionStart();
+ int oldSelEnd = d->control->selectionEnd();
+ d->control->moveCursor(cursorPos, false);
+ d->cursorVisible = false;
+ e->acceptProposedAction();
+ insert(str);
+ if (e->source() == this) {
+ if (e->dropAction() == Qt::MoveAction) {
+ if (selStart > oldSelStart && selStart <= oldSelEnd)
+ setSelection(oldSelStart, str.length());
+ else if (selStart > oldSelEnd)
+ setSelection(selStart - str.length(), str.length());
+ else
+ setSelection(selStart, str.length());
+ } else {
+ setSelection(selStart, str.length());
+ }
+ }
+ } else {
+ e->ignore();
+ update();
+ }
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ Shows the standard context menu created with
+ createStandardContextMenu().
+
+ If you do not want the line edit to have a context menu, you can set
+ its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
+ customize the context menu, reimplement this function. If you want
+ to extend the standard context menu, reimplement this function, call
+ createStandardContextMenu() and extend the menu returned.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qlineedit.cpp 0
+
+ The \a event parameter is used to obtain the position where
+ the mouse cursor was when the event was generated.
+
+ \sa setContextMenuPolicy()
+*/
+void QLineEdit::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (QMenu *menu = createStandardContextMenu()) {
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+ menu->popup(event->globalPos());
+ }
+}
+
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+ extern bool qt_use_rtl_extensions;
+#endif
+
+/*! This function creates the standard context menu which is shown
+ when the user clicks on the line edit with the right mouse
+ button. It is called from the default contextMenuEvent() handler.
+ The popup menu's ownership is transferred to the caller.
+*/
+
+QMenu *QLineEdit::createStandardContextMenu()
+{
+ Q_D(QLineEdit);
+ QMenu *popup = new QMenu(this);
+ popup->setObjectName(QLatin1String("qt_edit_menu"));
+ QAction *action = 0;
+
+ if (!isReadOnly()) {
+ action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo));
+ action->setEnabled(d->control->isUndoAvailable());
+ connect(action, SIGNAL(triggered()), SLOT(undo()));
+
+ action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo));
+ action->setEnabled(d->control->isRedoAvailable());
+ connect(action, SIGNAL(triggered()), SLOT(redo()));
+
+ popup->addSeparator();
+ }
+
+#ifndef QT_NO_CLIPBOARD
+ if (!isReadOnly()) {
+ action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut));
+ action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()
+ && d->control->echoMode() == QLineEdit::Normal);
+ connect(action, SIGNAL(triggered()), SLOT(cut()));
+ }
+
+ action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy));
+ action->setEnabled(d->control->hasSelectedText()
+ && d->control->echoMode() == QLineEdit::Normal);
+ connect(action, SIGNAL(triggered()), SLOT(copy()));
+
+ if (!isReadOnly()) {
+ action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste));
+ action->setEnabled(!d->control->isReadOnly() && !QApplication::clipboard()->text().isEmpty());
+ connect(action, SIGNAL(triggered()), SLOT(paste()));
+ }
+#endif
+
+ if (!isReadOnly()) {
+ action = popup->addAction(QLineEdit::tr("Delete"));
+ action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText());
+ connect(action, SIGNAL(triggered()), d->control, SLOT(_q_deleteSelected()));
+ }
+
+ if (!popup->isEmpty())
+ popup->addSeparator();
+
+ action = popup->addAction(QLineEdit::tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll));
+ action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected());
+ d->selectAllAction = action;
+ connect(action, SIGNAL(triggered()), SLOT(selectAll()));
+
+#if !defined(QT_NO_IM)
+ QInputContext *qic = inputContext();
+ if (qic) {
+ QList<QAction *> imActions = qic->actions();
+ for (int i = 0; i < imActions.size(); ++i)
+ popup->addAction(imActions.at(i));
+ }
+#endif
+
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+ if (!d->control->isReadOnly() && qt_use_rtl_extensions) {
+#else
+ if (!d->control->isReadOnly()) {
+#endif
+ popup->addSeparator();
+ QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, popup);
+ popup->addMenu(ctrlCharacterMenu);
+ }
+ return popup;
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*! \reimp */
+void QLineEdit::changeEvent(QEvent *ev)
+{
+ Q_D(QLineEdit);
+ switch(ev->type())
+ {
+ case QEvent::ActivationChange:
+ if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
+ update();
+ break;
+ case QEvent::FontChange:
+ d->control->setFont(font());
+ break;
+ case QEvent::StyleChange:
+ {
+ QStyleOptionFrameV2 opt;
+ initStyleOption(&opt);
+ d->control->setPasswordCharacter(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, this));
+ }
+ update();
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(ev);
+}
+
+/*!
+ \fn void QLineEdit::repaintArea(int a, int b)
+
+ Use update() instead.
+*/
+
+/*!
+ \fn void QLineEdit::cursorLeft(bool mark, int steps)
+
+ Use cursorForward() with a negative number of steps instead. For
+ example, cursorForward(mark, -steps).
+*/
+
+/*!
+ \fn void QLineEdit::cursorRight(bool mark, int steps)
+
+ Use cursorForward() instead.
+*/
+
+/*!
+ \fn bool QLineEdit::frame() const
+
+ Use hasFrame() instead.
+*/
+
+/*!
+ \fn void QLineEdit::clearValidator()
+
+ Use setValidator(0) instead.
+*/
+
+/*!
+ \fn bool QLineEdit::hasMarkedText() const
+
+ Use hasSelectedText() instead.
+*/
+
+/*!
+ \fn QString QLineEdit::markedText() const
+
+ Use selectedText() instead.
+*/
+
+/*!
+ \fn void QLineEdit::setFrameRect(QRect)
+ \internal
+*/
+
+/*!
+ \fn QRect QLineEdit::frameRect() const
+ \internal
+*/
+/*!
+ \enum QLineEdit::DummyFrame
+ \internal
+
+ \value Box
+ \value Sunken
+ \value Plain
+ \value Raised
+ \value MShadow
+ \value NoFrame
+ \value Panel
+ \value StyledPanel
+ \value HLine
+ \value VLine
+ \value GroupBoxPanel
+ \value WinPanel
+ \value ToolBarPanel
+ \value MenuBarPanel
+ \value PopupPanel
+ \value LineEditPanel
+ \value TabWidgetPanel
+ \value MShape
+*/
+
+/*!
+ \fn void QLineEdit::setFrameShadow(DummyFrame)
+ \internal
+*/
+
+/*!
+ \fn DummyFrame QLineEdit::frameShadow() const
+ \internal
+*/
+
+/*!
+ \fn void QLineEdit::setFrameShape(DummyFrame)
+ \internal
+*/
+
+/*!
+ \fn DummyFrame QLineEdit::frameShape() const
+ \internal
+*/
+
+/*!
+ \fn void QLineEdit::setFrameStyle(int)
+ \internal
+*/
+
+/*!
+ \fn int QLineEdit::frameStyle() const
+ \internal
+*/
+
+/*!
+ \fn int QLineEdit::frameWidth() const
+ \internal
+*/
+
+/*!
+ \fn void QLineEdit::setLineWidth(int)
+ \internal
+*/
+
+/*!
+ \fn int QLineEdit::lineWidth() const
+ \internal
+*/
+
+/*!
+ \fn void QLineEdit::setMargin(int margin)
+ Sets the width of the margin around the contents of the widget to \a margin.
+
+ Use QWidget::setContentsMargins() instead.
+ \sa margin(), QWidget::setContentsMargins()
+*/
+
+/*!
+ \fn int QLineEdit::margin() const
+ Returns the width of the margin around the contents of the widget.
+
+ Use QWidget::getContentsMargins() instead.
+ \sa setMargin(), QWidget::getContentsMargins()
+*/
+
+/*!
+ \fn void QLineEdit::setMidLineWidth(int)
+ \internal
+*/
+
+/*!
+ \fn int QLineEdit::midLineWidth() const
+ \internal
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qlineedit.cpp"
+
+#endif // QT_NO_LINEEDIT
diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h
new file mode 100644
index 0000000000..b0971db968
--- /dev/null
+++ b/src/widgets/widgets/qlineedit.h
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLINEEDIT_H
+#define QLINEEDIT_H
+
+#include <QtWidgets/qframe.h>
+#include <QtGui/qtextcursor.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmargins.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_LINEEDIT
+
+class QValidator;
+class QMenu;
+class QLineEditPrivate;
+class QCompleter;
+class QStyleOptionFrame;
+class QAbstractSpinBox;
+class QDateTimeEdit;
+
+class Q_WIDGETS_EXPORT QLineEdit : public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(EchoMode)
+ Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true)
+ Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength)
+ Q_PROPERTY(bool frame READ hasFrame WRITE setFrame)
+ Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode)
+ Q_PROPERTY(QString displayText READ displayText)
+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(bool modified READ isModified WRITE setModified DESIGNABLE false)
+ Q_PROPERTY(bool hasSelectedText READ hasSelectedText)
+ Q_PROPERTY(QString selectedText READ selectedText)
+ Q_PROPERTY(bool dragEnabled READ dragEnabled WRITE setDragEnabled)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(bool undoAvailable READ isUndoAvailable)
+ Q_PROPERTY(bool redoAvailable READ isRedoAvailable)
+ Q_PROPERTY(bool acceptableInput READ hasAcceptableInput)
+ Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText)
+ Q_PROPERTY(Qt::CursorMoveStyle cursorMoveStyle READ cursorMoveStyle WRITE setCursorMoveStyle)
+
+public:
+ explicit QLineEdit(QWidget* parent=0);
+ explicit QLineEdit(const QString &, QWidget* parent=0);
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QLineEdit(QWidget* parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QLineEdit(const QString &, QWidget* parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QLineEdit(const QString &, const QString &, QWidget* parent=0, const char* name=0);
+#endif
+ ~QLineEdit();
+
+ QString text() const;
+
+ QString displayText() const;
+
+ QString placeholderText() const;
+ void setPlaceholderText(const QString &);
+
+ int maxLength() const;
+ void setMaxLength(int);
+
+ void setFrame(bool);
+ bool hasFrame() const;
+
+ enum EchoMode { Normal, NoEcho, Password, PasswordEchoOnEdit };
+ EchoMode echoMode() const;
+ void setEchoMode(EchoMode);
+
+ bool isReadOnly() const;
+ void setReadOnly(bool);
+
+#ifndef QT_NO_VALIDATOR
+ void setValidator(const QValidator *);
+ const QValidator * validator() const;
+#endif
+
+#ifndef QT_NO_COMPLETER
+ void setCompleter(QCompleter *completer);
+ QCompleter *completer() const;
+#endif
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int cursorPosition() const;
+ void setCursorPosition(int);
+ int cursorPositionAt(const QPoint &pos);
+
+ void setAlignment(Qt::Alignment flag);
+ Qt::Alignment alignment() const;
+
+ void cursorForward(bool mark, int steps = 1);
+ void cursorBackward(bool mark, int steps = 1);
+ void cursorWordForward(bool mark);
+ void cursorWordBackward(bool mark);
+ void backspace();
+ void del();
+ void home(bool mark);
+ void end(bool mark);
+
+ bool isModified() const;
+ void setModified(bool);
+
+ void setSelection(int, int);
+ bool hasSelectedText() const;
+ QString selectedText() const;
+ int selectionStart() const;
+
+ bool isUndoAvailable() const;
+ bool isRedoAvailable() const;
+
+ void setDragEnabled(bool b);
+ bool dragEnabled() const;
+
+ void setCursorMoveStyle(Qt::CursorMoveStyle style);
+ Qt::CursorMoveStyle cursorMoveStyle() const;
+
+ QString inputMask() const;
+ void setInputMask(const QString &inputMask);
+ bool hasAcceptableInput() const;
+
+ void setTextMargins(int left, int top, int right, int bottom);
+ void setTextMargins(const QMargins &margins);
+ void getTextMargins(int *left, int *top, int *right, int *bottom) const;
+ QMargins textMargins() const;
+
+public Q_SLOTS:
+ void setText(const QString &);
+ void clear();
+ void selectAll();
+ void undo();
+ void redo();
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy() const;
+ void paste();
+#endif
+
+public:
+ void deselect();
+ void insert(const QString &);
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *createStandardContextMenu();
+#endif
+
+Q_SIGNALS:
+ void textChanged(const QString &);
+ void textEdited(const QString &);
+ void cursorPositionChanged(int, int);
+ void returnPressed();
+ void editingFinished();
+ void selectionChanged();
+
+protected:
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void focusInEvent(QFocusEvent *);
+ void focusOutEvent(QFocusEvent *);
+ void paintEvent(QPaintEvent *);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *);
+ void dragMoveEvent(QDragMoveEvent *e);
+ void dragLeaveEvent(QDragLeaveEvent *e);
+ void dropEvent(QDropEvent *);
+#endif
+ void changeEvent(QEvent *);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *);
+#endif
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT void repaintArea(int, int) { update(); }
+#endif
+
+ void inputMethodEvent(QInputMethodEvent *);
+ void initStyleOption(QStyleOptionFrame *option) const;
+public:
+ QVariant inputMethodQuery(Qt::InputMethodQuery) const;
+ bool event(QEvent *);
+protected:
+ QRect cursorRect() const;
+
+public:
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT void clearModified() { setModified(false); }
+ inline QT3_SUPPORT void cursorLeft(bool mark, int steps = 1) { cursorForward(mark, -steps); }
+ inline QT3_SUPPORT void cursorRight(bool mark, int steps = 1) { cursorForward(mark, steps); }
+ QT3_SUPPORT bool validateAndSet(const QString &, int, int, int);
+ inline QT3_SUPPORT bool frame() const { return hasFrame(); }
+#ifndef QT_NO_VALIDATOR
+ inline QT3_SUPPORT void clearValidator() { setValidator(0); }
+#endif
+ inline QT3_SUPPORT bool hasMarkedText() const { return hasSelectedText(); }
+ inline QT3_SUPPORT QString markedText() const { return selectedText(); }
+ QT3_SUPPORT bool edited() const;
+ QT3_SUPPORT void setEdited(bool);
+ QT3_SUPPORT int characterAt(int, QChar*) const;
+ QT3_SUPPORT bool getSelection(int *, int *);
+
+ QT3_SUPPORT void setFrameRect(QRect) {}
+ QT3_SUPPORT QRect frameRect() const { return QRect(); }
+ enum DummyFrame { Box, Sunken, Plain, Raised, MShadow, NoFrame, Panel, StyledPanel,
+ HLine, VLine, GroupBoxPanel, WinPanel, ToolBarPanel, MenuBarPanel,
+ PopupPanel, LineEditPanel, TabWidgetPanel, MShape };
+ QT3_SUPPORT void setFrameShadow(DummyFrame) {}
+ QT3_SUPPORT DummyFrame frameShadow() const { return Plain; }
+ QT3_SUPPORT void setFrameShape(DummyFrame) {}
+ QT3_SUPPORT DummyFrame frameShape() const { return NoFrame; }
+ QT3_SUPPORT void setFrameStyle(int) {}
+ QT3_SUPPORT int frameStyle() const { return 0; }
+ QT3_SUPPORT int frameWidth() const { return 0; }
+ QT3_SUPPORT void setLineWidth(int) {}
+ QT3_SUPPORT int lineWidth() const { return 0; }
+ QT3_SUPPORT void setMargin(int margin) { setContentsMargins(margin, margin, margin, margin); }
+ QT3_SUPPORT int margin() const
+ { int margin; int dummy; getContentsMargins(&margin, &dummy, &dummy, &dummy); return margin; }
+ QT3_SUPPORT void setMidLineWidth(int) {}
+ QT3_SUPPORT int midLineWidth() const { return 0; }
+
+Q_SIGNALS:
+ QT_MOC_COMPAT void lostFocus();
+#endif
+
+private:
+ friend class QAbstractSpinBox;
+#ifdef QT_KEYPAD_NAVIGATION
+ friend class QDateTimeEdit;
+#endif
+ Q_DISABLE_COPY(QLineEdit)
+ Q_DECLARE_PRIVATE(QLineEdit)
+ Q_PRIVATE_SLOT(d_func(), void _q_handleWindowActivate())
+ Q_PRIVATE_SLOT(d_func(), void _q_textEdited(const QString &))
+ Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged(int, int))
+#ifndef QT_NO_COMPLETER
+ Q_PRIVATE_SLOT(d_func(), void _q_completionHighlighted(QString))
+#endif
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_PRIVATE_SLOT(d_func(), void _q_editFocusChange(bool))
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateNeeded(const QRect &))
+};
+
+#endif // QT_NO_LINEEDIT
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLINEEDIT_H
diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp
new file mode 100644
index 0000000000..8511d0c9e5
--- /dev/null
+++ b/src/widgets/widgets/qlineedit_p.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlineedit.h"
+#include "qlineedit_p.h"
+
+#ifndef QT_NO_LINEEDIT
+
+#include "qabstractitemview.h"
+#include "qdrag.h"
+#include "qclipboard.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#include "qlist.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+const int QLineEditPrivate::verticalMargin(1);
+const int QLineEditPrivate::horizontalMargin(2);
+
+QRect QLineEditPrivate::adjustedControlRect(const QRect &rect) const
+{
+ QRect cr = adjustedContentsRect();
+ int cix = cr.x() - hscroll + horizontalMargin;
+ return rect.translated(QPoint(cix, vscroll));
+}
+
+int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
+{
+ QRect cr = adjustedContentsRect();
+ x-= cr.x() - hscroll + horizontalMargin;
+ return control->xToPos(x, betweenOrOn);
+}
+
+QRect QLineEditPrivate::cursorRect() const
+{
+ return adjustedControlRect(control->cursorRect());
+}
+
+#ifndef QT_NO_COMPLETER
+
+void QLineEditPrivate::_q_completionHighlighted(QString newText)
+{
+ Q_Q(QLineEdit);
+ if (control->completer()->completionMode() != QCompleter::InlineCompletion) {
+ q->setText(newText);
+ } else {
+ int c = control->cursor();
+ QString text = control->text();
+ q->setText(text.left(c) + newText.mid(c));
+ control->moveCursor(control->end(), false);
+ control->moveCursor(c, true);
+ }
+}
+
+#endif // QT_NO_COMPLETER
+
+void QLineEditPrivate::_q_handleWindowActivate()
+{
+ Q_Q(QLineEdit);
+ if (!q->hasFocus() && control->hasSelectedText())
+ control->deselect();
+}
+
+void QLineEditPrivate::_q_textEdited(const QString &text)
+{
+ Q_Q(QLineEdit);
+ emit q->textEdited(text);
+#ifndef QT_NO_COMPLETER
+ if (control->completer()
+ && control->completer()->completionMode() != QCompleter::InlineCompletion)
+ control->complete(-1); // update the popup on cut/paste/del
+#endif
+}
+
+void QLineEditPrivate::_q_cursorPositionChanged(int from, int to)
+{
+ Q_Q(QLineEdit);
+ q->update();
+ emit q->cursorPositionChanged(from, to);
+}
+
+#ifdef QT_KEYPAD_NAVIGATION
+void QLineEditPrivate::_q_editFocusChange(bool e)
+{
+ Q_Q(QLineEdit);
+ q->setEditFocus(e);
+}
+#endif
+
+void QLineEditPrivate::_q_selectionChanged()
+{
+ Q_Q(QLineEdit);
+ if (!control->text().isEmpty() && control->preeditAreaText().isEmpty()) {
+ QStyleOptionFrameV2 opt;
+ q->initStyleOption(&opt);
+ bool showCursor = control->hasSelectedText() ?
+ q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q):
+ q->hasFocus();
+ setCursorVisible(showCursor);
+ }
+
+ emit q->selectionChanged();
+}
+
+void QLineEditPrivate::_q_updateNeeded(const QRect &rect)
+{
+ q_func()->update(adjustedControlRect(rect));
+}
+
+void QLineEditPrivate::init(const QString& txt)
+{
+ Q_Q(QLineEdit);
+ control = new QWidgetLineControl(txt);
+ control->setParent(q);
+ control->setFont(q->font());
+ QObject::connect(control, SIGNAL(textChanged(QString)),
+ q, SIGNAL(textChanged(QString)));
+ QObject::connect(control, SIGNAL(textEdited(QString)),
+ q, SLOT(_q_textEdited(QString)));
+ QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(_q_cursorPositionChanged(int,int)));
+ QObject::connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(_q_selectionChanged()));
+ QObject::connect(control, SIGNAL(accepted()),
+ q, SIGNAL(returnPressed()));
+ QObject::connect(control, SIGNAL(editingFinished()),
+ q, SIGNAL(editingFinished()));
+#ifdef QT_KEYPAD_NAVIGATION
+ QObject::connect(control, SIGNAL(editFocusChange(bool)),
+ q, SLOT(_q_editFocusChange(bool)));
+#endif
+ QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(updateMicroFocus()));
+
+ QObject::connect(control, SIGNAL(textChanged(const QString &)),
+ q, SLOT(updateMicroFocus()));
+
+ // for now, going completely overboard with updates.
+ QObject::connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(update()));
+
+ QObject::connect(control, SIGNAL(displayTextChanged(QString)),
+ q, SLOT(update()));
+
+ QObject::connect(control, SIGNAL(updateNeeded(QRect)),
+ q, SLOT(_q_updateNeeded(QRect)));
+
+ QStyleOptionFrameV2 opt;
+ q->initStyleOption(&opt);
+ control->setPasswordCharacter(q->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, q));
+#ifndef QT_NO_CURSOR
+ q->setCursor(Qt::IBeamCursor);
+#endif
+ q->setFocusPolicy(Qt::StrongFocus);
+ q->setAttribute(Qt::WA_InputMethodEnabled);
+ // Specifies that this widget can use more, but is able to survive on
+ // less, horizontal space; and is fixed vertically.
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit));
+ q->setBackgroundRole(QPalette::Base);
+ q->setAttribute(Qt::WA_KeyCompression);
+ q->setMouseTracking(true);
+ q->setAcceptDrops(true);
+
+ q->setAttribute(Qt::WA_MacShowFocusRect);
+}
+
+QRect QLineEditPrivate::adjustedContentsRect() const
+{
+ Q_Q(const QLineEdit);
+ QStyleOptionFrameV2 opt;
+ q->initStyleOption(&opt);
+ QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q);
+ r.setX(r.x() + leftTextMargin);
+ r.setY(r.y() + topTextMargin);
+ r.setRight(r.right() - rightTextMargin);
+ r.setBottom(r.bottom() - bottomTextMargin);
+ return r;
+}
+
+void QLineEditPrivate::setCursorVisible(bool visible)
+{
+ Q_Q(QLineEdit);
+ if ((bool)cursorVisible == visible)
+ return;
+ cursorVisible = visible;
+ if (control->inputMask().isEmpty())
+ q->update(cursorRect());
+ else
+ q->update();
+}
+
+void QLineEditPrivate::updatePasswordEchoEditing(bool editing)
+{
+ Q_Q(QLineEdit);
+ control->updatePasswordEchoEditing(editing);
+ q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod());
+}
+
+/*!
+ This function is not intended as polymorphic usage. Just a shared code
+ fragment that calls QInputContext::mouseHandler for this
+ class.
+*/
+bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e )
+{
+#if !defined QT_NO_IM
+ Q_Q(QLineEdit);
+ if ( control->composeMode() ) {
+ int tmp_cursor = xToPos(e->pos().x());
+ int mousePos = tmp_cursor - control->cursor();
+ if ( mousePos < 0 || mousePos > control->preeditAreaText().length() ) {
+ mousePos = -1;
+ // don't send move events outside the preedit area
+ if ( e->type() == QEvent::MouseMove )
+ return true;
+ }
+
+ QInputContext *qic = q->inputContext();
+ if ( qic )
+ // may be causing reset() in some input methods
+ qic->mouseHandler(mousePos, e);
+ if (!control->preeditAreaText().isEmpty())
+ return true;
+ }
+#else
+ Q_UNUSED(e);
+#endif
+
+ return false;
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QLineEditPrivate::drag()
+{
+ Q_Q(QLineEdit);
+ dndTimer.stop();
+ QMimeData *data = new QMimeData;
+ data->setText(control->selectedText());
+ QDrag *drag = new QDrag(q);
+ drag->setMimeData(data);
+ Qt::DropAction action = drag->start();
+ if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q)
+ control->removeSelection();
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h
new file mode 100644
index 0000000000..74717fd2fa
--- /dev/null
+++ b/src/widgets/widgets/qlineedit_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLINEEDIT_P_H
+#define QLINEEDIT_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 "QtCore/qglobal.h"
+
+#ifndef QT_NO_LINEEDIT
+#include "private/qwidget_p.h"
+#include "QtWidgets/qlineedit.h"
+#include "QtGui/qtextlayout.h"
+#include "QtWidgets/qstyleoption.h"
+#include "QtCore/qbasictimer.h"
+#include "QtWidgets/qcompleter.h"
+#include "QtCore/qpointer.h"
+#include "QtWidgets/qlineedit.h"
+
+#include "private/qwidgetlinecontrol_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLineEditPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QLineEdit)
+public:
+
+ QLineEditPrivate()
+ : control(0), frame(1), contextMenuEnabled(1), cursorVisible(0),
+ dragEnabled(0), clickCausedFocus(0), hscroll(0), vscroll(0),
+ alignment(Qt::AlignLeading | Qt::AlignVCenter),
+ leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0)
+ {
+ }
+
+ ~QLineEditPrivate()
+ {
+ }
+
+ QWidgetLineControl *control;
+
+#ifndef QT_NO_CONTEXTMENU
+ QPointer<QAction> selectAllAction;
+#endif
+ void init(const QString&);
+
+ QRect adjustedControlRect(const QRect &) const;
+
+ int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const;
+ QRect cursorRect() const;
+ void setCursorVisible(bool visible);
+
+ void updatePasswordEchoEditing(bool);
+
+ inline bool shouldEnableInputMethod() const
+ {
+ return !control->isReadOnly();
+ }
+
+ QPoint tripleClick;
+ QBasicTimer tripleClickTimer;
+ uint frame : 1;
+ uint contextMenuEnabled : 1;
+ uint cursorVisible : 1;
+ uint dragEnabled : 1;
+ uint clickCausedFocus : 1;
+ int hscroll;
+ int vscroll;
+ uint alignment;
+ static const int verticalMargin;
+ static const int horizontalMargin;
+
+ bool sendMouseEventToInputContext(QMouseEvent *e);
+
+ QRect adjustedContentsRect() const;
+
+ void _q_handleWindowActivate();
+ void _q_textEdited(const QString &);
+ void _q_cursorPositionChanged(int, int);
+#ifdef QT_KEYPAD_NAVIGATION
+ void _q_editFocusChange(bool);
+#endif
+ void _q_selectionChanged();
+ void _q_updateNeeded(const QRect &);
+#ifndef QT_NO_COMPLETER
+ void _q_completionHighlighted(QString);
+#endif
+#ifndef QT_NO_DRAGANDDROP
+ QPoint dndPos;
+ QBasicTimer dndTimer;
+ void drag();
+#endif
+
+ int leftTextMargin;
+ int topTextMargin;
+ int rightTextMargin;
+ int bottomTextMargin;
+
+ QString placeholderText;
+};
+
+#endif // QT_NO_LINEEDIT
+
+QT_END_NAMESPACE
+
+#endif // QLINEEDIT_P_H
diff --git a/src/widgets/widgets/qmaccocoaviewcontainer_mac.h b/src/widgets/widgets/qmaccocoaviewcontainer_mac.h
new file mode 100644
index 0000000000..48eac4f490
--- /dev/null
+++ b/src/widgets/widgets/qmaccocoaviewcontainer_mac.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOCOAVIEWCONTAINER_H
+#define QCOCOAVIEWCONTAINER_H
+
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QMacCocoaViewContainerPrivate;
+
+class Q_WIDGETS_EXPORT QMacCocoaViewContainer : public QWidget
+{
+ Q_OBJECT
+public:
+ QMacCocoaViewContainer(void *cocoaViewToWrap, QWidget *parent = 0);
+ virtual ~QMacCocoaViewContainer();
+
+ void setCocoaView(void *cocoaViewToWrap);
+ void *cocoaView() const;
+
+private:
+ Q_DECLARE_PRIVATE(QMacCocoaViewContainer)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOCOAVIEWCONTAINER_H
diff --git a/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm
new file mode 100644
index 0000000000..5bb7a3bbf2
--- /dev/null
+++ b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#include <private/qwidget_p.h>
+#include "qmaccocoaviewcontainer_mac.h"
+#include <private/qt_mac_p.h>
+
+/*!
+ \class QMacCocoaViewContainer
+ \since 4.5
+
+ \brief The QMacCocoaViewContainer class provides a widget for Mac OS X that can be used to wrap arbitrary
+ Cocoa views (i.e., NSView subclasses) and insert them into Qt hierarchies.
+
+ \ingroup advanced
+
+ While Qt offers a lot of classes for writing your application, Apple's
+ Cocoa framework offers lots of functionality that is not currently in Qt or
+ may never end up in Qt. Using QMacCocoaViewContainer, it is possible to put an
+ arbitrary NSView-derived class from Cocoa and put it in a Qt hierarchy.
+ Depending on how comfortable you are with using objective-C, you can use
+ QMacCocoaViewContainer directly, or subclass it to wrap further functionality
+ of the underlying NSView.
+
+ QMacCocoaViewContainer works regardless if Qt is built against Carbon or
+ Cocoa. However, QCocoaContainerView requires Mac OS X 10.5 or better to be
+ used with Carbon.
+
+ It should be also noted that at the low level on Mac OS X, there is a
+ difference between windows (top-levels) and view (widgets that are inside a
+ window). For this reason, make sure that the NSView that you are wrapping
+ doesn't end up as a top-level. The best way to ensure this is to make sure
+ you always have a parent and not set the parent to 0.
+
+ If you are using QMacCocoaViewContainer as a sub-class and are mixing and
+ matching objective-C with C++ (a.k.a. objective-C++). It is probably
+ simpler to have your file end with \tt{.mm} than \tt{.cpp}. Most Apple tools will
+ correctly identify the source as objective-C++.
+
+ QMacCocoaViewContainer requires knowledge of how Cocoa works, especially in
+ regard to its reference counting (retain/release) nature. It is noted in
+ the functions below if there is any change in the reference count. Cocoa
+ views often generate temporary objects that are released by an autorelease
+ pool. If this is done outside of a running event loop, it is up to the
+ developer to provide the autorelease pool.
+
+ The following is a snippet of subclassing QMacCocoaViewContainer to wrap a NSSearchField.
+ \snippet examples/mainwindows/macmainwindow/macmainwindow.mm 0
+
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QMacCocoaViewContainerPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QMacCocoaViewContainer)
+public:
+ NSView *nsview;
+#ifndef QT_MAC_USE_COCOA
+ HIViewRef wrapperView;
+#endif
+ QMacCocoaViewContainerPrivate();
+ ~QMacCocoaViewContainerPrivate();
+};
+
+QMacCocoaViewContainerPrivate::QMacCocoaViewContainerPrivate()
+ : nsview(0)
+#ifndef QT_MAC_USE_COCOA
+ , wrapperView(0)
+#endif
+{
+}
+
+QMacCocoaViewContainerPrivate::~QMacCocoaViewContainerPrivate()
+{
+ [nsview release];
+#ifndef QT_MAC_USE_COCOA
+ if (wrapperView)
+ CFRelease(wrapperView);
+#endif
+}
+
+/*!
+ \fn QMacCocoaViewContainer::QMacCocoaViewContainer(void *cocoaViewToWrap, QWidget *parent)
+
+ Create a new QMacCocoaViewContainer using the NSView pointer in \a
+ cocoaViewToWrap with parent, \a parent. QMacCocoaViewContainer will
+ retain \a cocoaViewToWrap.
+
+ \a cocoaViewToWrap is a void pointer that allows the header to be included
+ with C++ source.
+*/
+QMacCocoaViewContainer::QMacCocoaViewContainer(void *cocoaViewToWrap, QWidget *parent)
+ : QWidget(*new QMacCocoaViewContainerPrivate, parent, 0)
+{
+ if (cocoaViewToWrap)
+ setCocoaView(cocoaViewToWrap);
+}
+
+/*!
+ Destroy the QMacCocoaViewContainer and release the wrapped view.
+*/
+QMacCocoaViewContainer::~QMacCocoaViewContainer()
+{
+}
+
+/*!
+ Returns the NSView that has been set on this container. The returned view
+ has been autoreleased, so you will need to retain it if you want to make
+ use of it.
+*/
+void *QMacCocoaViewContainer::cocoaView() const
+{
+ Q_D(const QMacCocoaViewContainer);
+ return [[d->nsview retain] autorelease];
+}
+
+/*!
+ Sets the NSView to contain to be \a cocoaViewToWrap and retains it. If this
+ container already had a view set, it will release the previously set view.
+*/
+void QMacCocoaViewContainer::setCocoaView(void *cocoaViewToWrap)
+{
+ Q_D(QMacCocoaViewContainer);
+ QMacCocoaAutoReleasePool pool;
+ NSView *view = static_cast<NSView *>(cocoaViewToWrap);
+ NSView *oldView = d->nsview;
+ destroy(true, true);
+ [view retain];
+ d->nsview = view;
+#ifndef QT_MAC_USE_COCOA
+ if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5) {
+ qWarning("QMacCocoaViewContainer::setCocoaView: You cannot use this class with Carbon on versions of Mac OS X less than 10.5.");
+ return;
+ }
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (d->wrapperView)
+ CFRelease(d->wrapperView);
+ HICocoaViewCreate(d->nsview, 0, &d->wrapperView);
+ create(WId(d->wrapperView), false, true);
+#endif
+#else
+ create(WId(d->nsview), false, true);
+#endif
+ [oldView release];
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qmacnativewidget_mac.h b/src/widgets/widgets/qmacnativewidget_mac.h
new file mode 100644
index 0000000000..935feac58e
--- /dev/null
+++ b/src/widgets/widgets/qmacnativewidget_mac.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMACNATIVEWIDGET_H
+#define QMACNATIVEWIDGET_H
+
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QMacNativeWidgetPrivate;
+class Q_WIDGETS_EXPORT QMacNativeWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QMacNativeWidget(void *parentRef = 0);
+ ~QMacNativeWidget();
+
+ QSize sizeHint() const;
+
+protected:
+ bool event(QEvent *ev);
+
+private:
+ Q_DECLARE_PRIVATE(QMacNativeWidget)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMACNATIVEWIDGET_H
diff --git a/src/widgets/widgets/qmacnativewidget_mac.mm b/src/widgets/widgets/qmacnativewidget_mac.mm
new file mode 100644
index 0000000000..b3c00d3cc6
--- /dev/null
+++ b/src/widgets/widgets/qmacnativewidget_mac.mm
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#import <private/qcocoaview_mac_p.h>
+#include "qmacnativewidget_mac.h"
+#include <private/qwidget_p.h>
+
+/*!
+ \class QMacNativeWidget
+ \since 4.5
+ \brief The QMacNativeWidget class provides a widget for Mac OS X that provides a way to put Qt widgets into Carbon
+ or Cocoa hierarchies depending on how Qt was configured.
+
+ \ingroup advanced
+
+ On Mac OS X, there is a difference between a window and view;
+ normally expressed as widgets in Qt. Qt makes assumptions about its
+ parent-child hierarchy that make it complex to put an arbitrary Qt widget
+ into a hierarchy of "normal" views from Apple frameworks. QMacNativeWidget
+ bridges the gap between views and windows and makes it possible to put a
+ hierarchy of Qt widgets into a non-Qt window or view.
+
+ QMacNativeWidget pretends it is a window (i.e. isWindow() will return true),
+ but it cannot be shown on its own. It needs to be put into a window
+ when it is created or later through a native call.
+
+ QMacNativeWidget works for either Carbon or Cocoa depending on how Qt was configured. If Qt is
+ using Carbon, QMacNativeWidget will embed into Carbon hierarchies. If Qt is
+ using Cocoa, QMacNativeWidget embeds into Cocoa hierarchies.
+
+ Here is an example of putting a QPushButton into a NSWindow:
+
+ \snippet doc/src/snippets/qmacnativewidget/main.mm 0
+
+ On Carbon, this would do the equivalent:
+
+ \snippet doc/src/snippets/qmacnativewidget/main.mm 1
+
+ Note that QMacNativeWidget requires knowledge of Carbon or Cocoa. All it
+ does is get the Qt hierarchy into a window not owned by Qt. It is then up
+ to the programmer to ensure it is placed correctly in the window and
+ responds correctly to events.
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QMacNativeWidgetPrivate : public QWidgetPrivate
+{
+};
+
+extern OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent);
+
+
+/*!
+ Create a QMacNativeWidget with \a parentView as its "superview" (i.e.,
+ parent). The \a parentView is either an HIViewRef if Qt is using Carbon or
+ a NSView pointer if Qt is using Cocoa.
+*/
+QMacNativeWidget::QMacNativeWidget(void *parentView)
+ : QWidget(*new QMacNativeWidgetPrivate, 0, Qt::Window)
+{
+ Q_D(QMacNativeWidget);
+ OSViewRef myView = qt_mac_create_widget(this, d, OSViewRef(parentView));
+
+ d->topData()->embedded = true;
+ create(WId(myView), false, false);
+ setPalette(QPalette(Qt::transparent));
+ setAttribute(Qt::WA_SetPalette, false);
+ setAttribute(Qt::WA_LayoutUsesWidgetRect);
+}
+
+/*!
+ Destroy the QMacNativeWidget.
+*/
+QMacNativeWidget::~QMacNativeWidget()
+{
+}
+
+/*!
+ \reimp
+*/
+QSize QMacNativeWidget::sizeHint() const
+{
+ return QSize(200, 200);
+}
+/*!
+ \reimp
+*/
+bool QMacNativeWidget::event(QEvent *ev)
+{
+ return QWidget::event(ev);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp
new file mode 100644
index 0000000000..b3bd972497
--- /dev/null
+++ b/src/widgets/widgets/qmainwindow.cpp
@@ -0,0 +1,1686 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QT_EXPERIMENTAL_CLIENT_DECORATIONS
+
+#include "qmainwindow.h"
+#include "qmainwindowlayout_p.h"
+
+#ifndef QT_NO_MAINWINDOW
+
+#include "qdockwidget.h"
+#include "qtoolbar.h"
+
+#include <qapplication.h>
+#include <qmenubar.h>
+#include <qstatusbar.h>
+#include <qevent.h>
+#include <qstyle.h>
+#include <qdebug.h>
+#include <qpainter.h>
+
+#include <private/qwidget_p.h>
+#include "qtoolbar_p.h"
+#include "qwidgetanimator_p.h"
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+QT_BEGIN_NAMESPACE
+extern OSWindowRef qt_mac_window_for(const QWidget *); // qwidget_mac.cpp
+QT_END_NAMESPACE
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMainWindowPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QMainWindow)
+public:
+ inline QMainWindowPrivate()
+ : layout(0), explicitIconSize(false), toolButtonStyle(Qt::ToolButtonIconOnly)
+#ifdef Q_WS_MAC
+ , useHIToolBar(false)
+ , activateUnifiedToolbarAfterFullScreen(false)
+#endif
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+ , hasOldCursor(false) , cursorAdjusted(false)
+#endif
+ { }
+ QMainWindowLayout *layout;
+ QSize iconSize;
+ bool explicitIconSize;
+ Qt::ToolButtonStyle toolButtonStyle;
+#ifdef Q_WS_MAC
+ bool useHIToolBar;
+ bool activateUnifiedToolbarAfterFullScreen;
+#endif
+ void init();
+ QList<int> hoverSeparator;
+ QPoint hoverPos;
+
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+ QCursor separatorCursor(const QList<int> &path) const;
+ void adjustCursor(const QPoint &pos);
+ QCursor oldCursor;
+ uint hasOldCursor : 1;
+ uint cursorAdjusted : 1;
+#endif
+
+ static inline QMainWindowLayout *mainWindowLayout(const QMainWindow *mainWindow)
+ {
+ return mainWindow ? mainWindow->d_func()->layout : static_cast<QMainWindowLayout *>(0);
+ }
+};
+
+QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow)
+{
+ return QMainWindowPrivate::mainWindowLayout(mainWindow);
+}
+
+#ifdef QT_EXPERIMENTAL_CLIENT_DECORATIONS
+Q_WIDGETS_EXPORT void qt_setMainWindowTitleWidget(QMainWindow *mainWindow, Qt::DockWidgetArea area, QWidget *widget)
+{
+ QGridLayout *topLayout = qobject_cast<QGridLayout *>(mainWindow->layout());
+ Q_ASSERT(topLayout);
+
+ int row = 0;
+ int column = 0;
+
+ switch (area) {
+ case Qt::LeftDockWidgetArea:
+ row = 1;
+ column = 0;
+ break;
+ case Qt::TopDockWidgetArea:
+ row = 0;
+ column = 1;
+ break;
+ case Qt::BottomDockWidgetArea:
+ row = 2;
+ column = 1;
+ break;
+ case Qt::RightDockWidgetArea:
+ row = 1;
+ column = 2;
+ break;
+ default:
+ Q_ASSERT_X(false, "qt_setMainWindowTitleWidget", "Unknown area");
+ return;
+ }
+
+ if (QLayoutItem *oldItem = topLayout->itemAtPosition(row, column))
+ delete oldItem->widget();
+ topLayout->addWidget(widget, row, column);
+}
+#endif
+
+void QMainWindowPrivate::init()
+{
+ Q_Q(QMainWindow);
+
+#ifdef QT_EXPERIMENTAL_CLIENT_DECORATIONS
+ QGridLayout *topLayout = new QGridLayout(q);
+ topLayout->setContentsMargins(0, 0, 0, 0);
+
+ layout = new QMainWindowLayout(q, topLayout);
+
+ topLayout->addItem(layout, 1, 1);
+#else
+ layout = new QMainWindowLayout(q, 0);
+#endif
+
+ const int metric = q->style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, q);
+ iconSize = QSize(metric, metric);
+ q->setAttribute(Qt::WA_Hover);
+}
+
+/*
+ The Main Window:
+
+ +----------------------------------------------------------+
+ | Menu Bar |
+ +----------------------------------------------------------+
+ | Tool Bar Area |
+ | +--------------------------------------------------+ |
+ | | Dock Window Area | |
+ | | +------------------------------------------+ | |
+ | | | | | |
+ | | | Central Widget | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | +------------------------------------------+ | |
+ | | | |
+ | +--------------------------------------------------+ |
+ | |
+ +----------------------------------------------------------+
+ | Status Bar |
+ +----------------------------------------------------------+
+
+*/
+
+/*!
+ \class QMainWindow
+ \brief The QMainWindow class provides a main application
+ window.
+ \ingroup mainwindow-classes
+
+
+ \tableofcontents
+
+ \section1 Qt Main Window Framework
+
+ A main window provides a framework for building an
+ application's user interface. Qt has QMainWindow and its \l{Main
+ Window and Related Classes}{related classes} for main window
+ management. QMainWindow has its own layout to which you can add
+ \l{QToolBar}s, \l{QDockWidget}s, a
+ QMenuBar, and a QStatusBar. The layout has a center area that can
+ be occupied by any kind of widget. You can see an image of the
+ layout below.
+
+ \image mainwindowlayout.png
+
+ \note Creating a main window without a central widget is not supported.
+ You must have a central widget even if it is just a placeholder.
+
+ \section1 Creating Main Window Components
+
+ A central widget will typically be a standard Qt widget such
+ as a QTextEdit or a QGraphicsView. Custom widgets can also be
+ used for advanced applications. You set the central widget with \c
+ setCentralWidget().
+
+ Main windows have either a single (SDI) or multiple (MDI)
+ document interface. You create MDI applications in Qt by using a
+ QMdiArea as the central widget.
+
+ We will now examine each of the other widgets that can be
+ added to a main window. We give examples on how to create and add
+ them.
+
+ \section2 Creating Menus
+
+ Qt implements menus in QMenu and QMainWindow keeps them in a
+ QMenuBar. \l{QAction}{QAction}s are added to the menus, which
+ display them as menu items.
+
+ You can add new menus to the main window's menu bar by calling
+ \c menuBar(), which returns the QMenuBar for the window, and then
+ add a menu with QMenuBar::addMenu().
+
+ QMainWindow comes with a default menu bar, but you can also
+ set one yourself with \c setMenuBar(). If you wish to implement a
+ custom menu bar (i.e., not use the QMenuBar widget), you can set it
+ with \c setMenuWidget().
+
+ An example of how to create menus follows:
+
+ \snippet examples/mainwindows/application/mainwindow.cpp 26
+
+ The \c createPopupMenu() function creates popup menus when the
+ main window receives context menu events. The default
+ implementation generates a menu with the checkable actions from
+ the dock widgets and toolbars. You can reimplement \c
+ createPopupMenu() for a custom menu.
+
+ \section2 Creating Toolbars
+
+ Toolbars are implemented in the QToolBar class. You add a
+ toolbar to a main window with \c addToolBar().
+
+ You control the initial position of toolbars by assigning them
+ to a specific Qt::ToolBarArea. You can split an area by inserting
+ a toolbar break - think of this as a line break in text editing -
+ with \c addToolBarBreak() or \c insertToolBarBreak(). You can also
+ restrict placement by the user with QToolBar::setAllowedAreas()
+ and QToolBar::setMovable().
+
+ The size of toolbar icons can be retrieved with \c iconSize().
+ The sizes are platform dependent; you can set a fixed size with \c
+ setIconSize(). You can alter the appearance of all tool buttons in
+ the toolbars with \c setToolButtonStyle().
+
+ An example of toolbar creation follows:
+
+ \snippet examples/mainwindows/application/mainwindow.cpp 29
+
+ \section2 Creating Dock Widgets
+
+ Dock widgets are implemented in the QDockWidget class. A dock
+ widget is a window that can be docked into the main window. You
+ add dock widgets to a main window with \c addDockWidget().
+
+ There are four dock widget areas as given by the
+ Qt::DockWidgetArea enum: left, right, top, and bottom. You can
+ specify which dock widget area that should occupy the corners
+ where the areas overlap with \c setCorner(). By default
+ each area can only contain one row (vertical or horizontal) of
+ dock widgets, but if you enable nesting with \c
+ setDockNestingEnabled(), dock widgets can be added in either
+ direction.
+
+ Two dock widgets may also be stacked on top of each other. A
+ QTabBar is then used to select which of the widgets that should be
+ displayed.
+
+ We give an example of how to create and add dock widgets to a
+ main window:
+
+ \snippet doc/src/snippets/mainwindowsnippet.cpp 0
+
+ \section2 The Status Bar
+
+ You can set a status bar with \c setStatusBar(), but one is
+ created the first time \c statusBar() (which returns the main
+ window's status bar) is called. See QStatusBar for information on
+ how to use it.
+
+ \section1 Storing State
+
+ QMainWindow can store the state of its layout with \c
+ saveState(); it can later be retrieved with \c restoreState(). It
+ is the position and size (relative to the size of the main window)
+ of the toolbars and dock widgets that are stored.
+
+ \sa QMenuBar, QToolBar, QStatusBar, QDockWidget, {Application
+ Example}, {Dock Widgets Example}, {MDI Example}, {SDI Example},
+ {Menus Example}
+*/
+
+/*!
+ \fn void QMainWindow::iconSizeChanged(const QSize &iconSize)
+
+ This signal is emitted when the size of the icons used in the
+ window is changed. The new icon size is passed in \a iconSize.
+
+ You can connect this signal to other components to help maintain
+ a consistent appearance for your application.
+
+ \sa setIconSize()
+*/
+
+/*!
+ \fn void QMainWindow::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
+
+ This signal is emitted when the style used for tool buttons in the
+ window is changed. The new style is passed in \a toolButtonStyle.
+
+ You can connect this signal to other components to help maintain
+ a consistent appearance for your application.
+
+ \sa setToolButtonStyle()
+*/
+
+/*!
+ Constructs a QMainWindow with the given \a parent and the specified
+ widget \a flags.
+
+ QMainWindow sets the Qt::Window flag itself, and will hence
+ always be created as a top-level widget.
+ */
+QMainWindow::QMainWindow(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*(new QMainWindowPrivate()), parent, flags | Qt::Window)
+{
+ d_func()->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \obsolete
+ Constructs a QMainWindow with the given \a parent, \a name, and
+ with the specified widget \a flags.
+ */
+QMainWindow::QMainWindow(QWidget *parent, const char *name, Qt::WindowFlags flags)
+ : QWidget(*(new QMainWindowPrivate()), parent, flags | Qt::WType_TopLevel)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->init();
+}
+#endif
+
+/*!
+ Destroys the main window.
+ */
+QMainWindow::~QMainWindow()
+{ }
+
+/*! \property QMainWindow::iconSize
+ \brief size of toolbar icons in this mainwindow.
+
+ The default is the default tool bar icon size of the GUI style.
+ Note that the icons used must be at least of this size as the
+ icons are only scaled down.
+*/
+
+/*!
+ \property QMainWindow::dockOptions
+ \brief the docking behavior of QMainWindow
+ \since 4.3
+
+ The default value is AnimatedDocks | AllowTabbedDocks.
+*/
+
+/*!
+ \enum QMainWindow::DockOption
+ \since 4.3
+
+ This enum contains flags that specify the docking behavior of QMainWindow.
+
+ \value AnimatedDocks Identical to the \l animated property.
+
+ \value AllowNestedDocks Identical to the \l dockNestingEnabled property.
+
+ \value AllowTabbedDocks The user can drop one dock widget "on top" of
+ another. The two widgets are stacked and a tab
+ bar appears for selecting which one is visible.
+
+ \value ForceTabbedDocks Each dock area contains a single stack of tabbed
+ dock widgets. In other words, dock widgets cannot
+ be placed next to each other in a dock area. If
+ this option is set, AllowNestedDocks has no effect.
+
+ \value VerticalTabs The two vertical dock areas on the sides of the
+ main window show their tabs vertically. If this
+ option is not set, all dock areas show their tabs
+ at the bottom. Implies AllowTabbedDocks. See also
+ \l setTabPosition().
+
+ These options only control how dock widgets may be dropped in a QMainWindow.
+ They do not re-arrange the dock widgets to conform with the specified
+ options. For this reason they should be set before any dock widgets
+ are added to the main window. Exceptions to this are the AnimatedDocks and
+ VerticalTabs options, which may be set at any time.
+*/
+
+void QMainWindow::setDockOptions(DockOptions opt)
+{
+ Q_D(QMainWindow);
+ d->layout->setDockOptions(opt);
+}
+
+QMainWindow::DockOptions QMainWindow::dockOptions() const
+{
+ Q_D(const QMainWindow);
+ return d->layout->dockOptions;
+}
+
+QSize QMainWindow::iconSize() const
+{ return d_func()->iconSize; }
+
+void QMainWindow::setIconSize(const QSize &iconSize)
+{
+ Q_D(QMainWindow);
+ QSize sz = iconSize;
+ if (!sz.isValid()) {
+ const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this);
+ sz = QSize(metric, metric);
+ }
+ if (d->iconSize != sz) {
+ d->iconSize = sz;
+ emit iconSizeChanged(d->iconSize);
+ }
+ d->explicitIconSize = iconSize.isValid();
+}
+
+/*! \property QMainWindow::toolButtonStyle
+ \brief style of toolbar buttons in this mainwindow.
+
+ The default is Qt::ToolButtonIconOnly.
+*/
+
+Qt::ToolButtonStyle QMainWindow::toolButtonStyle() const
+{ return d_func()->toolButtonStyle; }
+
+void QMainWindow::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
+{
+ Q_D(QMainWindow);
+ if (d->toolButtonStyle == toolButtonStyle)
+ return;
+ d->toolButtonStyle = toolButtonStyle;
+ emit toolButtonStyleChanged(d->toolButtonStyle);
+}
+
+#ifndef QT_NO_MENUBAR
+/*!
+ Returns the menu bar for the main window. This function creates
+ and returns an empty menu bar if the menu bar does not exist.
+
+ If you want all windows in a Mac application to share one menu
+ bar, don't use this function to create it, because the menu bar
+ created here will have this QMainWindow as its parent. Instead,
+ you must create a menu bar that does not have a parent, which you
+ can then share among all the Mac windows. Create a parent-less
+ menu bar this way:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenubar.cpp 1
+
+ \sa setMenuBar()
+*/
+QMenuBar *QMainWindow::menuBar() const
+{
+ QMenuBar *menuBar = qobject_cast<QMenuBar *>(layout()->menuBar());
+ if (!menuBar) {
+ QMainWindow *self = const_cast<QMainWindow *>(this);
+ menuBar = new QMenuBar(self);
+ self->setMenuBar(menuBar);
+ }
+ return menuBar;
+}
+
+/*!
+ Sets the menu bar for the main window to \a menuBar.
+
+ Note: QMainWindow takes ownership of the \a menuBar pointer and
+ deletes it at the appropriate time.
+
+ \sa menuBar()
+*/
+void QMainWindow::setMenuBar(QMenuBar *menuBar)
+{
+ QLayout *topLayout = layout();
+
+ if (topLayout->menuBar() && topLayout->menuBar() != menuBar) {
+ // Reparent corner widgets before we delete the old menu bar.
+ QMenuBar *oldMenuBar = qobject_cast<QMenuBar *>(topLayout->menuBar());
+ if (menuBar) {
+ // TopLeftCorner widget.
+ QWidget *cornerWidget = oldMenuBar->cornerWidget(Qt::TopLeftCorner);
+ if (cornerWidget)
+ menuBar->setCornerWidget(cornerWidget, Qt::TopLeftCorner);
+ // TopRightCorner widget.
+ cornerWidget = oldMenuBar->cornerWidget(Qt::TopRightCorner);
+ if (cornerWidget)
+ menuBar->setCornerWidget(cornerWidget, Qt::TopRightCorner);
+ }
+ oldMenuBar->hide();
+ oldMenuBar->deleteLater();
+ }
+ topLayout->setMenuBar(menuBar);
+}
+
+/*!
+ \since 4.2
+
+ Returns the menu bar for the main window. This function returns
+ null if a menu bar hasn't been constructed yet.
+*/
+QWidget *QMainWindow::menuWidget() const
+{
+ QWidget *menuBar = d_func()->layout->menuBar();
+ return menuBar;
+}
+
+/*!
+ \since 4.2
+
+ Sets the menu bar for the main window to \a menuBar.
+
+ QMainWindow takes ownership of the \a menuBar pointer and
+ deletes it at the appropriate time.
+*/
+void QMainWindow::setMenuWidget(QWidget *menuBar)
+{
+ Q_D(QMainWindow);
+ if (d->layout->menuBar() && d->layout->menuBar() != menuBar) {
+ d->layout->menuBar()->hide();
+ d->layout->menuBar()->deleteLater();
+ }
+ d->layout->setMenuBar(menuBar);
+}
+#endif // QT_NO_MENUBAR
+
+#ifndef QT_NO_STATUSBAR
+/*!
+ Returns the status bar for the main window. This function creates
+ and returns an empty status bar if the status bar does not exist.
+
+ \sa setStatusBar()
+*/
+QStatusBar *QMainWindow::statusBar() const
+{
+ QStatusBar *statusbar = d_func()->layout->statusBar();
+ if (!statusbar) {
+ QMainWindow *self = const_cast<QMainWindow *>(this);
+ statusbar = new QStatusBar(self);
+ statusbar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+ self->setStatusBar(statusbar);
+ }
+ return statusbar;
+}
+
+/*!
+ Sets the status bar for the main window to \a statusbar.
+
+ Setting the status bar to 0 will remove it from the main window.
+ Note that QMainWindow takes ownership of the \a statusbar pointer
+ and deletes it at the appropriate time.
+
+ \sa statusBar()
+*/
+void QMainWindow::setStatusBar(QStatusBar *statusbar)
+{
+ Q_D(QMainWindow);
+ if (d->layout->statusBar() && d->layout->statusBar() != statusbar) {
+ d->layout->statusBar()->hide();
+ d->layout->statusBar()->deleteLater();
+ }
+ d->layout->setStatusBar(statusbar);
+}
+#endif // QT_NO_STATUSBAR
+
+/*!
+ Returns the central widget for the main window. This function
+ returns zero if the central widget has not been set.
+
+ \sa setCentralWidget()
+*/
+QWidget *QMainWindow::centralWidget() const
+{ return d_func()->layout->centralWidget(); }
+
+/*!
+ Sets the given \a widget to be the main window's central widget.
+
+ Note: QMainWindow takes ownership of the \a widget pointer and
+ deletes it at the appropriate time.
+
+ \sa centralWidget()
+*/
+void QMainWindow::setCentralWidget(QWidget *widget)
+{
+ Q_D(QMainWindow);
+ if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
+ d->layout->centralWidget()->hide();
+ d->layout->centralWidget()->deleteLater();
+ }
+ d->layout->setCentralWidget(widget);
+}
+
+#ifndef QT_NO_DOCKWIDGET
+/*!
+ Sets the given dock widget \a area to occupy the specified \a
+ corner.
+
+ \sa corner()
+*/
+void QMainWindow::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
+{
+ bool valid = false;
+ switch (corner) {
+ case Qt::TopLeftCorner:
+ valid = (area == Qt::TopDockWidgetArea || area == Qt::LeftDockWidgetArea);
+ break;
+ case Qt::TopRightCorner:
+ valid = (area == Qt::TopDockWidgetArea || area == Qt::RightDockWidgetArea);
+ break;
+ case Qt::BottomLeftCorner:
+ valid = (area == Qt::BottomDockWidgetArea || area == Qt::LeftDockWidgetArea);
+ break;
+ case Qt::BottomRightCorner:
+ valid = (area == Qt::BottomDockWidgetArea || area == Qt::RightDockWidgetArea);
+ break;
+ }
+ if (!valid)
+ qWarning("QMainWindow::setCorner(): 'area' is not valid for 'corner'");
+ else
+ d_func()->layout->setCorner(corner, area);
+}
+
+/*!
+ Returns the dock widget area that occupies the specified \a
+ corner.
+
+ \sa setCorner()
+*/
+Qt::DockWidgetArea QMainWindow::corner(Qt::Corner corner) const
+{ return d_func()->layout->corner(corner); }
+#endif
+
+#ifndef QT_NO_TOOLBAR
+
+static bool checkToolBarArea(Qt::ToolBarArea area, const char *where)
+{
+ switch (area) {
+ case Qt::LeftToolBarArea:
+ case Qt::RightToolBarArea:
+ case Qt::TopToolBarArea:
+ case Qt::BottomToolBarArea:
+ return true;
+ default:
+ break;
+ }
+ qWarning("%s: invalid 'area' argument", where);
+ return false;
+}
+
+/*!
+ Adds a toolbar break to the given \a area after all the other
+ objects that are present.
+*/
+void QMainWindow::addToolBarBreak(Qt::ToolBarArea area)
+{
+ if (!checkToolBarArea(area, "QMainWindow::addToolBarBreak"))
+ return;
+ d_func()->layout->addToolBarBreak(area);
+}
+
+/*!
+ Inserts a toolbar break before the toolbar specified by \a before.
+*/
+void QMainWindow::insertToolBarBreak(QToolBar *before)
+{ d_func()->layout->insertToolBarBreak(before); }
+
+/*!
+ Removes a toolbar break previously inserted before the toolbar specified by \a before.
+*/
+
+void QMainWindow::removeToolBarBreak(QToolBar *before)
+{
+ Q_D(QMainWindow);
+ d->layout->removeToolBarBreak(before);
+}
+
+/*!
+ Adds the \a toolbar into the specified \a area in this main
+ window. The \a toolbar is placed at the end of the current tool
+ bar block (i.e. line). If the main window already manages \a toolbar
+ then it will only move the toolbar to \a area.
+
+ \sa insertToolBar() addToolBarBreak() insertToolBarBreak()
+*/
+void QMainWindow::addToolBar(Qt::ToolBarArea area, QToolBar *toolbar)
+{
+ if (!checkToolBarArea(area, "QMainWindow::addToolBar"))
+ return;
+
+ Q_D(QMainWindow);
+
+ disconnect(this, SIGNAL(iconSizeChanged(QSize)),
+ toolbar, SLOT(_q_updateIconSize(QSize)));
+ disconnect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
+ toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
+
+ if(toolbar->d_func()->state && toolbar->d_func()->state->dragging) {
+ //removing a toolbar which is dragging will cause crash
+#ifndef QT_NO_DOCKWIDGET
+ bool animated = isAnimated();
+ setAnimated(false);
+#endif
+ toolbar->d_func()->endDrag();
+#ifndef QT_NO_DOCKWIDGET
+ setAnimated(animated);
+#endif
+ }
+
+ if (!d->layout->usesHIToolBar(toolbar)) {
+ d->layout->removeWidget(toolbar);
+ } else {
+ d->layout->removeToolBar(toolbar);
+ }
+
+ toolbar->d_func()->_q_updateIconSize(d->iconSize);
+ toolbar->d_func()->_q_updateToolButtonStyle(d->toolButtonStyle);
+ connect(this, SIGNAL(iconSizeChanged(QSize)),
+ toolbar, SLOT(_q_updateIconSize(QSize)));
+ connect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
+ toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
+
+ d->layout->addToolBar(area, toolbar);
+}
+
+/*! \overload
+ Equivalent of calling addToolBar(Qt::TopToolBarArea, \a toolbar)
+*/
+void QMainWindow::addToolBar(QToolBar *toolbar)
+{ addToolBar(Qt::TopToolBarArea, toolbar); }
+
+/*!
+ \overload
+
+ Creates a QToolBar object, setting its window title to \a title,
+ and inserts it into the top toolbar area.
+
+ \sa setWindowTitle()
+*/
+QToolBar *QMainWindow::addToolBar(const QString &title)
+{
+ QToolBar *toolBar = new QToolBar(this);
+ toolBar->setWindowTitle(title);
+ addToolBar(toolBar);
+ return toolBar;
+}
+
+/*!
+ Inserts the \a toolbar into the area occupied by the \a before toolbar
+ so that it appears before it. For example, in normal left-to-right
+ layout operation, this means that \a toolbar will appear to the left
+ of the toolbar specified by \a before in a horizontal toolbar area.
+
+ \sa insertToolBarBreak() addToolBar() addToolBarBreak()
+*/
+void QMainWindow::insertToolBar(QToolBar *before, QToolBar *toolbar)
+{
+ Q_D(QMainWindow);
+
+ d->layout->removeToolBar(toolbar);
+
+ toolbar->d_func()->_q_updateIconSize(d->iconSize);
+ toolbar->d_func()->_q_updateToolButtonStyle(d->toolButtonStyle);
+ connect(this, SIGNAL(iconSizeChanged(QSize)),
+ toolbar, SLOT(_q_updateIconSize(QSize)));
+ connect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
+ toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
+
+ d->layout->insertToolBar(before, toolbar);
+}
+
+/*!
+ Removes the \a toolbar from the main window layout and hides
+ it. Note that the \a toolbar is \e not deleted.
+*/
+void QMainWindow::removeToolBar(QToolBar *toolbar)
+{
+ if (toolbar) {
+ d_func()->layout->removeToolBar(toolbar);
+ toolbar->hide();
+ }
+}
+
+/*!
+ Returns the Qt::ToolBarArea for \a toolbar. If \a toolbar has not
+ been added to the main window, this function returns \c
+ Qt::NoToolBarArea.
+
+ \sa addToolBar() addToolBarBreak() Qt::ToolBarArea
+*/
+Qt::ToolBarArea QMainWindow::toolBarArea(QToolBar *toolbar) const
+{ return d_func()->layout->toolBarArea(toolbar); }
+
+/*!
+
+ Returns whether there is a toolbar
+ break before the \a toolbar.
+
+ \sa addToolBarBreak(), insertToolBarBreak()
+*/
+bool QMainWindow::toolBarBreak(QToolBar *toolbar) const
+{
+ return d_func()->layout->toolBarBreak(toolbar);
+}
+
+#endif // QT_NO_TOOLBAR
+
+#ifndef QT_NO_DOCKWIDGET
+
+/*! \property QMainWindow::animated
+ \brief whether manipulating dock widgets and tool bars is animated
+ \since 4.2
+
+ When a dock widget or tool bar is dragged over the
+ main window, the main window adjusts its contents
+ to indicate where the dock widget or tool bar will
+ be docked if it is dropped. Setting this property
+ causes QMainWindow to move its contents in a smooth
+ animation. Clearing this property causes the contents
+ to snap into their new positions.
+
+ By default, this property is set. It may be cleared if
+ the main window contains widgets which are slow at resizing
+ or repainting themselves.
+
+ Setting this property is identical to setting the AnimatedDocks
+ option using setDockOptions().
+*/
+
+bool QMainWindow::isAnimated() const
+{
+ Q_D(const QMainWindow);
+ return d->layout->dockOptions & AnimatedDocks;
+}
+
+void QMainWindow::setAnimated(bool enabled)
+{
+ Q_D(QMainWindow);
+
+ DockOptions opts = d->layout->dockOptions;
+ if (enabled)
+ opts |= AnimatedDocks;
+ else
+ opts &= ~AnimatedDocks;
+
+ d->layout->setDockOptions(opts);
+}
+
+/*! \property QMainWindow::dockNestingEnabled
+ \brief whether docks can be nested
+ \since 4.2
+
+ If this property is false, dock areas can only contain a single row
+ (horizontal or vertical) of dock widgets. If this property is true,
+ the area occupied by a dock widget can be split in either direction to contain
+ more dock widgets.
+
+ Dock nesting is only necessary in applications that contain a lot of
+ dock widgets. It gives the user greater freedom in organizing their
+ main window. However, dock nesting leads to more complex
+ (and less intuitive) behavior when a dock widget is dragged over the
+ main window, since there are more ways in which a dropped dock widget
+ may be placed in the dock area.
+
+ Setting this property is identical to setting the AllowNestedDocks option
+ using setDockOptions().
+*/
+
+bool QMainWindow::isDockNestingEnabled() const
+{
+ Q_D(const QMainWindow);
+ return d->layout->dockOptions & AllowNestedDocks;
+}
+
+void QMainWindow::setDockNestingEnabled(bool enabled)
+{
+ Q_D(QMainWindow);
+
+ DockOptions opts = d->layout->dockOptions;
+ if (enabled)
+ opts |= AllowNestedDocks;
+ else
+ opts &= ~AllowNestedDocks;
+
+ d->layout->setDockOptions(opts);
+}
+
+#if 0
+/*! \property QMainWindow::verticalTabsEnabled
+ \brief whether left and right dock areas use vertical tabs
+ \since 4.2
+
+ If this property is set to false, dock areas containing tabbed dock widgets
+ display horizontal tabs, simmilar to Visual Studio.
+
+ If this property is set to true, then the right and left dock areas display vertical
+ tabs, simmilar to KDevelop.
+
+ This property should be set before any dock widgets are added to the main window.
+*/
+
+bool QMainWindow::verticalTabsEnabled() const
+{
+ return d_func()->layout->verticalTabsEnabled();
+}
+
+void QMainWindow::setVerticalTabsEnabled(bool enabled)
+{
+ d_func()->layout->setVerticalTabsEnabled(enabled);
+}
+#endif
+
+static bool checkDockWidgetArea(Qt::DockWidgetArea area, const char *where)
+{
+ switch (area) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ return true;
+ default:
+ break;
+ }
+ qWarning("%s: invalid 'area' argument", where);
+ return false;
+}
+
+#ifndef QT_NO_TABBAR
+/*!
+ \property QMainWindow::documentMode
+ \brief whether the tab bar for tabbed dockwidgets is set to document mode.
+ \since 4.5
+
+ The default is false.
+
+ \sa QTabBar::documentMode
+*/
+bool QMainWindow::documentMode() const
+{
+ return d_func()->layout->documentMode();
+}
+
+void QMainWindow::setDocumentMode(bool enabled)
+{
+ d_func()->layout->setDocumentMode(enabled);
+}
+#endif // QT_NO_TABBAR
+
+#ifndef QT_NO_TABWIDGET
+/*!
+ \property QMainWindow::tabShape
+ \brief the tab shape used for tabbed dock widgets.
+ \since 4.5
+
+ The default is \l QTabWidget::Rounded.
+
+ \sa setTabPosition()
+*/
+QTabWidget::TabShape QMainWindow::tabShape() const
+{
+ return d_func()->layout->tabShape();
+}
+
+void QMainWindow::setTabShape(QTabWidget::TabShape tabShape)
+{
+ d_func()->layout->setTabShape(tabShape);
+}
+
+/*!
+ \since 4.5
+
+ Returns the tab position for \a area.
+
+ \note The \l VerticalTabs dock option overrides the tab positions returned
+ by this function.
+
+ \sa setTabPosition(), tabShape()
+*/
+QTabWidget::TabPosition QMainWindow::tabPosition(Qt::DockWidgetArea area) const
+{
+ if (!checkDockWidgetArea(area, "QMainWindow::tabPosition"))
+ return QTabWidget::South;
+ return d_func()->layout->tabPosition(area);
+}
+
+/*!
+ \since 4.5
+
+ Sets the tab position for the given dock widget \a areas to the specified
+ \a tabPosition. By default, all dock areas show their tabs at the bottom.
+
+ \note The \l VerticalTabs dock option overrides the tab positions set by
+ this method.
+
+ \sa tabPosition(), setTabShape()
+*/
+void QMainWindow::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
+{
+ d_func()->layout->setTabPosition(areas, tabPosition);
+}
+#endif // QT_NO_TABWIDGET
+
+/*!
+ Adds the given \a dockwidget to the specified \a area.
+*/
+void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget)
+{
+ if (!checkDockWidgetArea(area, "QMainWindow::addDockWidget"))
+ return;
+
+ Qt::Orientation orientation = Qt::Vertical;
+ switch (area) {
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ orientation = Qt::Horizontal;
+ break;
+ default:
+ break;
+ }
+ d_func()->layout->removeWidget(dockwidget); // in case it was already in here
+ addDockWidget(area, dockwidget, orientation);
+
+#ifdef Q_WS_MAC //drawer support
+ QMacCocoaAutoReleasePool pool;
+ extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
+ if (qt_mac_is_macdrawer(dockwidget)) {
+ extern bool qt_mac_set_drawer_preferred_edge(QWidget *, Qt::DockWidgetArea); //qwidget_mac.cpp
+ window()->createWinId();
+ dockwidget->window()->createWinId();
+ qt_mac_set_drawer_preferred_edge(dockwidget, area);
+ if (dockwidget->isVisible()) {
+ dockwidget->hide();
+ dockwidget->show();
+ }
+ }
+#endif
+}
+
+/*!
+ Restores the state of \a dockwidget if it is created after the call
+ to restoreState(). Returns true if the state was restored; otherwise
+ returns false.
+
+ \sa restoreState(), saveState()
+*/
+
+bool QMainWindow::restoreDockWidget(QDockWidget *dockwidget)
+{
+ return d_func()->layout->restoreDockWidget(dockwidget);
+}
+
+/*!
+ Adds \a dockwidget into the given \a area in the direction
+ specified by the \a orientation.
+*/
+void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget,
+ Qt::Orientation orientation)
+{
+ if (!checkDockWidgetArea(area, "QMainWindow::addDockWidget"))
+ return;
+
+ // add a window to an area, placing done relative to the previous
+ d_func()->layout->addDockWidget(area, dockwidget, orientation);
+}
+
+/*!
+ \fn void QMainWindow::splitDockWidget(QDockWidget *first, QDockWidget *second, Qt::Orientation orientation)
+
+ Splits the space covered by the \a first dock widget into two parts,
+ moves the \a first dock widget into the first part, and moves the
+ \a second dock widget into the second part.
+
+ The \a orientation specifies how the space is divided: A Qt::Horizontal
+ split places the second dock widget to the right of the first; a
+ Qt::Vertical split places the second dock widget below the first.
+
+ \e Note: if \a first is currently in a tabbed docked area, \a second will
+ be added as a new tab, not as a neighbor of \a first. This is because a
+ single tab can contain only one dock widget.
+
+ \e Note: The Qt::LayoutDirection influences the order of the dock widgets
+ in the two parts of the divided area. When right-to-left layout direction
+ is enabled, the placing of the dock widgets will be reversed.
+
+ \sa tabifyDockWidget(), addDockWidget(), removeDockWidget()
+*/
+void QMainWindow::splitDockWidget(QDockWidget *after, QDockWidget *dockwidget,
+ Qt::Orientation orientation)
+{
+ d_func()->layout->splitDockWidget(after, dockwidget, orientation);
+}
+
+/*!
+ \fn void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
+
+ Moves \a second dock widget on top of \a first dock widget, creating a tabbed
+ docked area in the main window.
+
+ \sa tabifiedDockWidgets()
+*/
+void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
+{
+ d_func()->layout->tabifyDockWidget(first, second);
+}
+
+
+/*!
+ \fn QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
+
+ Returns the dock widgets that are tabified together with \a dockwidget.
+
+ \since 4.5
+ \sa tabifyDockWidget()
+*/
+
+QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
+{
+ QList<QDockWidget*> ret;
+#if defined(QT_NO_TABBAR)
+ Q_UNUSED(dockwidget);
+#else
+ const QDockAreaLayoutInfo *info = d_func()->layout->layoutState.dockAreaLayout.info(dockwidget);
+ if (info && info->tabbed && info->tabBar) {
+ for(int i = 0; i < info->item_list.count(); ++i) {
+ const QDockAreaLayoutItem &item = info->item_list.at(i);
+ if (item.widgetItem) {
+ if (QDockWidget *dock = qobject_cast<QDockWidget*>(item.widgetItem->widget())) {
+ if (dock != dockwidget) {
+ ret += dock;
+ }
+ }
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+
+/*!
+ Removes the \a dockwidget from the main window layout and hides
+ it. Note that the \a dockwidget is \e not deleted.
+*/
+void QMainWindow::removeDockWidget(QDockWidget *dockwidget)
+{
+ if (dockwidget) {
+ d_func()->layout->removeWidget(dockwidget);
+ dockwidget->hide();
+ }
+}
+
+/*!
+ Returns the Qt::DockWidgetArea for \a dockwidget. If \a dockwidget
+ has not been added to the main window, this function returns \c
+ Qt::NoDockWidgetArea.
+
+ \sa addDockWidget() splitDockWidget() Qt::DockWidgetArea
+*/
+Qt::DockWidgetArea QMainWindow::dockWidgetArea(QDockWidget *dockwidget) const
+{ return d_func()->layout->dockWidgetArea(dockwidget); }
+
+#endif // QT_NO_DOCKWIDGET
+
+/*!
+ Saves the current state of this mainwindow's toolbars and
+ dockwidgets. The \a version number is stored as part of the data.
+
+ The \link QObject::objectName objectName\endlink property is used
+ to identify each QToolBar and QDockWidget. You should make sure
+ that this property is unique for each QToolBar and QDockWidget you
+ add to the QMainWindow
+
+ To restore the saved state, pass the return value and \a version
+ number to restoreState().
+
+ To save the geometry when the window closes, you can
+ implement a close event like this:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qmainwindow.cpp 0
+
+ \sa restoreState(), QWidget::saveGeometry(), QWidget::restoreGeometry()
+*/
+QByteArray QMainWindow::saveState(int version) const
+{
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ stream << QMainWindowLayout::VersionMarker;
+ stream << version;
+ d_func()->layout->saveState(stream);
+ return data;
+}
+
+/*!
+ Restores the \a state of this mainwindow's toolbars and
+ dockwidgets. The \a version number is compared with that stored
+ in \a state. If they do not match, the mainwindow's state is left
+ unchanged, and this function returns \c false; otherwise, the state
+ is restored, and this function returns \c true.
+
+ To restore geometry saved using QSettings, you can use code like
+ this:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qmainwindow.cpp 1
+
+ \sa saveState(), QWidget::saveGeometry(),
+ QWidget::restoreGeometry(), restoreDockWidget()
+*/
+bool QMainWindow::restoreState(const QByteArray &state, int version)
+{
+ if (state.isEmpty())
+ return false;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ int marker, v;
+ stream >> marker;
+ stream >> v;
+ if (stream.status() != QDataStream::Ok || marker != QMainWindowLayout::VersionMarker || v != version)
+ return false;
+ bool restored = d_func()->layout->restoreState(stream);
+ return restored;
+}
+
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+QCursor QMainWindowPrivate::separatorCursor(const QList<int> &path) const
+{
+ QDockAreaLayoutInfo *info = layout->layoutState.dockAreaLayout.info(path);
+ Q_ASSERT(info != 0);
+ if (path.size() == 1) { // is this the "top-level" separator which separates a dock area
+ // from the central widget?
+ switch (path.first()) {
+ case QInternal::LeftDock:
+ case QInternal::RightDock:
+ return Qt::SplitHCursor;
+ case QInternal::TopDock:
+ case QInternal::BottomDock:
+ return Qt::SplitVCursor;
+ default:
+ break;
+ }
+ }
+
+ // no, it's a splitter inside a dock area, separating two dock widgets
+
+ return info->o == Qt::Horizontal
+ ? Qt::SplitHCursor : Qt::SplitVCursor;
+}
+
+void QMainWindowPrivate::adjustCursor(const QPoint &pos)
+{
+ Q_Q(QMainWindow);
+
+ hoverPos = pos;
+
+ if (pos == QPoint(0, 0)) {
+ if (!hoverSeparator.isEmpty())
+ q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
+ hoverSeparator.clear();
+
+ if (cursorAdjusted) {
+ cursorAdjusted = false;
+ if (hasOldCursor)
+ q->setCursor(oldCursor);
+ else
+ q->unsetCursor();
+ }
+ } else {
+ QList<int> pathToSeparator
+ = layout->layoutState.dockAreaLayout.findSeparator(pos);
+
+ if (pathToSeparator != hoverSeparator) {
+ if (!hoverSeparator.isEmpty())
+ q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
+
+ hoverSeparator = pathToSeparator;
+
+ if (hoverSeparator.isEmpty()) {
+ if (cursorAdjusted) {
+ cursorAdjusted = false;
+ if (hasOldCursor)
+ q->setCursor(oldCursor);
+ else
+ q->unsetCursor();
+ }
+ } else {
+ q->update(layout->layoutState.dockAreaLayout.separatorRect(hoverSeparator));
+ if (!cursorAdjusted) {
+ oldCursor = q->cursor();
+ hasOldCursor = q->testAttribute(Qt::WA_SetCursor);
+ }
+ QCursor cursor = separatorCursor(hoverSeparator);
+ cursorAdjusted = false; //to not reset the oldCursor in event(CursorChange)
+ q->setCursor(cursor);
+ cursorAdjusted = true;
+ }
+ }
+ }
+}
+#endif
+
+/*! \reimp */
+bool QMainWindow::event(QEvent *event)
+{
+ Q_D(QMainWindow);
+ switch (event->type()) {
+
+#ifndef QT_NO_DOCKWIDGET
+ case QEvent::Paint: {
+ QPainter p(this);
+ QRegion r = static_cast<QPaintEvent*>(event)->region();
+ d->layout->layoutState.dockAreaLayout.paintSeparators(&p, this, r, d->hoverPos);
+ break;
+ }
+
+#ifndef QT_NO_CURSOR
+ case QEvent::HoverMove: {
+ d->adjustCursor(static_cast<QHoverEvent*>(event)->pos());
+ break;
+ }
+
+ // We don't want QWidget to call update() on the entire QMainWindow
+ // on HoverEnter and HoverLeave, hence accept the event (return true).
+ case QEvent::HoverEnter:
+ return true;
+ case QEvent::HoverLeave:
+ d->adjustCursor(QPoint(0, 0));
+ return true;
+ case QEvent::ShortcutOverride: // when a menu pops up
+ d->adjustCursor(QPoint(0, 0));
+ break;
+#endif // QT_NO_CURSOR
+
+ case QEvent::MouseButtonPress: {
+ QMouseEvent *e = static_cast<QMouseEvent*>(event);
+ if (e->button() == Qt::LeftButton && d->layout->startSeparatorMove(e->pos())) {
+ // The click was on a separator, eat this event
+ e->accept();
+ return true;
+ }
+ break;
+ }
+
+ case QEvent::MouseMove: {
+ QMouseEvent *e = static_cast<QMouseEvent*>(event);
+
+#ifndef QT_NO_CURSOR
+ d->adjustCursor(e->pos());
+#endif
+ if (e->buttons() & Qt::LeftButton) {
+ if (d->layout->separatorMove(e->pos())) {
+ // We're moving a separator, eat this event
+ e->accept();
+ return true;
+ }
+ }
+
+ break;
+ }
+
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *e = static_cast<QMouseEvent*>(event);
+ if (d->layout->endSeparatorMove(e->pos())) {
+ // We've released a separator, eat this event
+ e->accept();
+ return true;
+ }
+ break;
+ }
+
+#endif
+
+#ifndef QT_NO_TOOLBAR
+ case QEvent::ToolBarChange: {
+ d->layout->toggleToolBarsVisible();
+ return true;
+ }
+#endif
+
+#ifndef QT_NO_STATUSTIP
+ case QEvent::StatusTip:
+#ifndef QT_NO_STATUSBAR
+ if (QStatusBar *sb = d->layout->statusBar())
+ sb->showMessage(static_cast<QStatusTipEvent*>(event)->tip());
+ else
+#endif
+ static_cast<QStatusTipEvent*>(event)->ignore();
+ return true;
+#endif // QT_NO_STATUSTIP
+
+ case QEvent::StyleChange:
+#ifndef QT_NO_DOCKWIDGET
+ d->layout->layoutState.dockAreaLayout.styleChangedEvent();
+#endif
+ if (!d->explicitIconSize)
+ setIconSize(QSize());
+ break;
+#ifdef Q_WS_MAC
+ case QEvent::Show:
+ if (unifiedTitleAndToolBarOnMac())
+ d->layout->syncUnifiedToolbarVisibility();
+ d->layout->blockVisiblityCheck = false;
+ break;
+ case QEvent::WindowStateChange:
+ {
+ if (isHidden()) {
+ // We are coming out of a minimize, leave things as is.
+ d->layout->blockVisiblityCheck = true;
+ }
+# ifdef QT_MAC_USE_COCOA
+ // We need to update the HIToolbar status when we go out of or into fullscreen.
+ QWindowStateChangeEvent *wce = static_cast<QWindowStateChangeEvent *>(event);
+ if ((windowState() & Qt::WindowFullScreen) || (wce->oldState() & Qt::WindowFullScreen)) {
+ d->layout->updateHIToolBarStatus();
+ }
+# endif // Cocoa
+ }
+ break;
+#endif // Q_WS_MAC
+#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
+ case QEvent::CursorChange:
+ if (d->cursorAdjusted) {
+ d->oldCursor = cursor();
+ d->hasOldCursor = testAttribute(Qt::WA_SetCursor);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return QWidget::event(event);
+}
+
+#ifndef QT_NO_TOOLBAR
+
+/*!
+ \property QMainWindow::unifiedTitleAndToolBarOnMac
+ \brief whether the window uses the unified title and toolbar look on Mac OS X
+ \since 4.3
+
+ This property is false by default and only has any effect on Mac OS X 10.4 or higher.
+
+ If set to true, then the top toolbar area is replaced with a Carbon HIToolbar
+ or a Cocoa NSToolbar (depending on whether Qt was built with Carbon or Cocoa).
+ All toolbars in the top toolbar area and any toolbars added afterwards are
+ moved to that. This means a couple of things.
+
+ \list
+ \i QToolBars in this toolbar area are not movable and you cannot drag other
+ toolbars to it
+ \i Toolbar breaks are not respected or preserved
+ \i Any custom widgets in the toolbar will not be shown if the toolbar
+ becomes too small (only actions will be shown)
+ \i Before Qt 4.5, if you called showFullScreen() on the main window, the QToolbar would
+ disappear since it is considered to be part of the title bar. Qt 4.5 and up will now work around this by pulling
+ the toolbars out and back into the regular toolbar and vice versa when you swap out.
+ \endlist
+
+ Setting this back to false will remove these restrictions.
+
+ The Qt::WA_MacBrushedMetal attribute takes precedence over this property.
+*/
+void QMainWindow::setUnifiedTitleAndToolBarOnMac(bool set)
+{
+#ifdef Q_WS_MAC
+ Q_D(QMainWindow);
+ if (!isWindow() || d->useHIToolBar == set || QSysInfo::MacintoshVersion < QSysInfo::MV_10_3)
+ return;
+
+ d->useHIToolBar = set;
+ createWinId(); // We need the hiview for down below.
+
+#ifdef QT_MAC_USE_COCOA
+ // Activate the unified toolbar with the raster engine.
+ if (windowSurface() && set) {
+ d->layout->unifiedSurface = new QUnifiedToolbarSurface(this);
+ }
+#endif // QT_MAC_USE_COCOA
+
+ d->layout->updateHIToolBarStatus();
+
+#ifdef QT_MAC_USE_COCOA
+ // Deactivate the unified toolbar with the raster engine.
+ if (windowSurface() && !set) {
+ if (d->layout->unifiedSurface) {
+ delete d->layout->unifiedSurface;
+ d->layout->unifiedSurface = 0;
+ }
+ }
+#endif // QT_MAC_USE_COCOA
+
+ // Enabling the unified toolbar clears the opaque size grip setting, update it.
+ d->macUpdateOpaqueSizeGrip();
+#else
+ Q_UNUSED(set)
+#endif
+}
+
+bool QMainWindow::unifiedTitleAndToolBarOnMac() const
+{
+#ifdef Q_WS_MAC
+ return d_func()->useHIToolBar && !testAttribute(Qt::WA_MacBrushedMetal) && !(windowFlags() & Qt::FramelessWindowHint);
+#endif
+ return false;
+}
+
+#endif // QT_NO_TOOLBAR
+
+/*!
+ \internal
+*/
+bool QMainWindow::isSeparator(const QPoint &pos) const
+{
+#ifndef QT_NO_DOCKWIDGET
+ Q_D(const QMainWindow);
+ return !d->layout->layoutState.dockAreaLayout.findSeparator(pos).isEmpty();
+#else
+ Q_UNUSED(pos);
+ return false;
+#endif
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \reimp
+*/
+void QMainWindow::contextMenuEvent(QContextMenuEvent *event)
+{
+ event->ignore();
+ // only show the context menu for direct QDockWidget and QToolBar
+ // children and for the menu bar as well
+ QWidget *child = childAt(event->pos());
+ while (child && child != this) {
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar *>(child)) {
+ if (mb->parentWidget() != this)
+ return;
+ break;
+ }
+#endif
+#ifndef QT_NO_DOCKWIDGET
+ if (QDockWidget *dw = qobject_cast<QDockWidget *>(child)) {
+ if (dw->parentWidget() != this)
+ return;
+ if (dw->widget()
+ && dw->widget()->geometry().contains(child->mapFrom(this, event->pos()))) {
+ // ignore the event if the mouse is over the QDockWidget contents
+ return;
+ }
+ break;
+ }
+#endif // QT_NO_DOCKWIDGET
+#ifndef QT_NO_TOOLBAR
+ if (QToolBar *tb = qobject_cast<QToolBar *>(child)) {
+ if (tb->parentWidget() != this)
+ return;
+ break;
+ }
+#endif
+ child = child->parentWidget();
+ }
+ if (child == this)
+ return;
+
+#ifndef QT_NO_MENU
+ QMenu *popup = createPopupMenu();
+ if (popup) {
+ if (!popup->isEmpty()) {
+ popup->setAttribute(Qt::WA_DeleteOnClose);
+ popup->popup(event->globalPos());
+ event->accept();
+ } else {
+ delete popup;
+ }
+ }
+#endif
+}
+#endif // QT_NO_CONTEXTMENU
+
+#ifndef QT_NO_MENU
+/*!
+ Returns a popup menu containing checkable entries for the toolbars and
+ dock widgets present in the main window. If there are no toolbars and
+ dock widgets present, this function returns a null pointer.
+
+ By default, this function is called by the main window when the user
+ activates a context menu, typically by right-clicking on a toolbar or a dock
+ widget.
+
+ If you want to create a custom popup menu, reimplement this function and
+ return a newly-created popup menu. Ownership of the popup menu is transferred
+ to the caller.
+
+ \sa addDockWidget(), addToolBar(), menuBar()
+*/
+QMenu *QMainWindow::createPopupMenu()
+{
+ Q_D(QMainWindow);
+ QMenu *menu = 0;
+#ifndef QT_NO_DOCKWIDGET
+ QList<QDockWidget *> dockwidgets = findChildren<QDockWidget *>();
+ if (dockwidgets.size()) {
+ menu = new QMenu(this);
+ for (int i = 0; i < dockwidgets.size(); ++i) {
+ QDockWidget *dockWidget = dockwidgets.at(i);
+ if (dockWidget->parentWidget() == this
+ && !d->layout->layoutState.dockAreaLayout.indexOf(dockWidget).isEmpty()) {
+ menu->addAction(dockwidgets.at(i)->toggleViewAction());
+ }
+ }
+ menu->addSeparator();
+ }
+#endif // QT_NO_DOCKWIDGET
+#ifndef QT_NO_TOOLBAR
+ QList<QToolBar *> toolbars = findChildren<QToolBar *>();
+ if (toolbars.size()) {
+ if (!menu)
+ menu = new QMenu(this);
+ for (int i = 0; i < toolbars.size(); ++i) {
+ QToolBar *toolBar = toolbars.at(i);
+ if (toolBar->parentWidget() == this
+ && (!d->layout->layoutState.toolBarAreaLayout.indexOf(toolBar).isEmpty()
+ || (unifiedTitleAndToolBarOnMac()
+ && toolBarArea(toolBar) == Qt::TopToolBarArea))) {
+ menu->addAction(toolbars.at(i)->toggleViewAction());
+ }
+ }
+ }
+#endif
+ Q_UNUSED(d);
+ return menu;
+}
+#endif // QT_NO_MENU
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MAINWINDOW
diff --git a/src/widgets/widgets/qmainwindow.h b/src/widgets/widgets/qmainwindow.h
new file mode 100644
index 0000000000..f060d3f460
--- /dev/null
+++ b/src/widgets/widgets/qmainwindow.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICMAINWINDOW_H
+#define QDYNAMICMAINWINDOW_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qtabwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MAINWINDOW
+
+class QDockWidget;
+class QMainWindowPrivate;
+class QMenuBar;
+class QStatusBar;
+class QToolBar;
+class QMenu;
+
+class Q_WIDGETS_EXPORT QMainWindow : public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(DockOption)
+ Q_FLAGS(DockOptions)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+ Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle)
+#ifndef QT_NO_DOCKWIDGET
+ Q_PROPERTY(bool animated READ isAnimated WRITE setAnimated)
+#ifndef QT_NO_TABBAR
+ Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
+#endif // QT_NO_TABBAR
+#ifndef QT_NO_TABWIDGET
+ Q_PROPERTY(QTabWidget::TabShape tabShape READ tabShape WRITE setTabShape)
+#endif // QT_NO_TABWIDGET
+ Q_PROPERTY(bool dockNestingEnabled READ isDockNestingEnabled WRITE setDockNestingEnabled)
+#endif // QT_NO_DOCKWIDGET
+ Q_PROPERTY(DockOptions dockOptions READ dockOptions WRITE setDockOptions)
+#ifndef QT_NO_TOOLBAR
+ Q_PROPERTY(bool unifiedTitleAndToolBarOnMac READ unifiedTitleAndToolBarOnMac WRITE setUnifiedTitleAndToolBarOnMac)
+#endif
+
+public:
+ enum DockOption {
+ AnimatedDocks = 0x01,
+ AllowNestedDocks = 0x02,
+ AllowTabbedDocks = 0x04,
+ ForceTabbedDocks = 0x08, // implies AllowTabbedDocks, !AllowNestedDocks
+ VerticalTabs = 0x10 // implies AllowTabbedDocks
+ };
+ Q_DECLARE_FLAGS(DockOptions, DockOption)
+
+ explicit QMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QMainWindow();
+
+ QSize iconSize() const;
+ void setIconSize(const QSize &iconSize);
+
+ Qt::ToolButtonStyle toolButtonStyle() const;
+ void setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle);
+
+#ifndef QT_NO_DOCKWIDGET
+ bool isAnimated() const;
+ bool isDockNestingEnabled() const;
+#endif
+
+#ifndef QT_NO_TABBAR
+ bool documentMode() const;
+ void setDocumentMode(bool enabled);
+#endif
+
+#ifndef QT_NO_TABWIDGET
+ QTabWidget::TabShape tabShape() const;
+ void setTabShape(QTabWidget::TabShape tabShape);
+ QTabWidget::TabPosition tabPosition(Qt::DockWidgetArea area) const;
+ void setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition);
+#endif // QT_NO_TABWIDGET
+
+ void setDockOptions(DockOptions options);
+ DockOptions dockOptions() const;
+
+ bool isSeparator(const QPoint &pos) const;
+
+#ifndef QT_NO_MENUBAR
+ QMenuBar *menuBar() const;
+ void setMenuBar(QMenuBar *menubar);
+
+ QWidget *menuWidget() const;
+ void setMenuWidget(QWidget *menubar);
+#endif
+
+#ifndef QT_NO_STATUSBAR
+ QStatusBar *statusBar() const;
+ void setStatusBar(QStatusBar *statusbar);
+#endif
+
+ QWidget *centralWidget() const;
+ void setCentralWidget(QWidget *widget);
+
+#ifndef QT_NO_DOCKWIDGET
+ void setCorner(Qt::Corner corner, Qt::DockWidgetArea area);
+ Qt::DockWidgetArea corner(Qt::Corner corner) const;
+#endif
+
+#ifndef QT_NO_TOOLBAR
+ void addToolBarBreak(Qt::ToolBarArea area = Qt::TopToolBarArea);
+ void insertToolBarBreak(QToolBar *before);
+
+ void addToolBar(Qt::ToolBarArea area, QToolBar *toolbar);
+ void addToolBar(QToolBar *toolbar);
+ QToolBar *addToolBar(const QString &title);
+ void insertToolBar(QToolBar *before, QToolBar *toolbar);
+ void removeToolBar(QToolBar *toolbar);
+ void removeToolBarBreak(QToolBar *before);
+
+ void setUnifiedTitleAndToolBarOnMac(bool set);
+ bool unifiedTitleAndToolBarOnMac() const;
+
+ Qt::ToolBarArea toolBarArea(QToolBar *toolbar) const;
+ bool toolBarBreak(QToolBar *toolbar) const;
+#endif
+#ifndef QT_NO_DOCKWIDGET
+ void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget);
+ void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget,
+ Qt::Orientation orientation);
+ void splitDockWidget(QDockWidget *after, QDockWidget *dockwidget,
+ Qt::Orientation orientation);
+ void tabifyDockWidget(QDockWidget *first, QDockWidget *second);
+ QList<QDockWidget*> tabifiedDockWidgets(QDockWidget *dockwidget) const;
+ void removeDockWidget(QDockWidget *dockwidget);
+ bool restoreDockWidget(QDockWidget *dockwidget);
+
+ Qt::DockWidgetArea dockWidgetArea(QDockWidget *dockwidget) const;
+#endif // QT_NO_DOCKWIDGET
+
+ QByteArray saveState(int version = 0) const;
+ bool restoreState(const QByteArray &state, int version = 0);
+
+#ifndef QT_NO_MENU
+ virtual QMenu *createPopupMenu();
+#endif
+
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QMainWindow(QWidget *parent, const char *name, Qt::WindowFlags flags = 0);
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+public Q_SLOTS:
+ void setAnimated(bool enabled);
+ void setDockNestingEnabled(bool enabled);
+#endif
+
+Q_SIGNALS:
+ void iconSizeChanged(const QSize &iconSize);
+ void toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle);
+
+protected:
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *event);
+#endif
+ bool event(QEvent *event);
+
+private:
+ Q_DECLARE_PRIVATE(QMainWindow)
+ Q_DISABLE_COPY(QMainWindow)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMainWindow::DockOptions)
+
+#endif // QT_NO_MAINWINDOW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDYNAMICMAINWINDOW_H
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
new file mode 100644
index 0000000000..ebabf2d93c
--- /dev/null
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -0,0 +1,2017 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmainwindowlayout_p.h"
+#include "qdockarealayout_p.h"
+
+#ifndef QT_NO_MAINWINDOW
+#include "qdockwidget.h"
+#include "qdockwidget_p.h"
+#include "qtoolbar_p.h"
+#include "qmainwindow.h"
+#include "qmainwindowlayout_p.h"
+#include "qtoolbar.h"
+#include "qtoolbarlayout_p.h"
+#include "qwidgetanimator_p.h"
+#include "qrubberband.h"
+#include "qdockwidget_p.h"
+#include "qtabbar_p.h"
+
+#include <qapplication.h>
+#include <qstatusbar.h>
+#include <qstring.h>
+#include <qstyle.h>
+#include <qvarlengtharray.h>
+#include <qstack.h>
+#include <qmap.h>
+#include <qtimer.h>
+
+#include <qdebug.h>
+
+#include <private/qapplication_p.h>
+#include <private/qlayoutengine_p.h>
+#ifdef Q_WS_MAC
+# include <private/qcore_mac_p.h>
+# include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#ifdef QT_NO_DOCKWIDGET
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+#endif
+
+#ifdef Q_DEBUG_MAINWINDOW_LAYOUT
+# include <QTextStream>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/******************************************************************************
+** debug
+*/
+
+#if defined(Q_DEBUG_MAINWINDOW_LAYOUT) && !defined(QT_NO_DOCKWIDGET)
+
+static QTextStream qout(stderr, QIODevice::WriteOnly);
+
+static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent);
+
+static void dumpLayout(QTextStream &qout, const QDockAreaLayoutItem &item, QString indent)
+{
+ qout << indent << "QDockAreaLayoutItem: "
+ << "pos: " << item.pos << " size:" << item.size
+ << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
+ << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize) << '\n';
+ indent += QLatin1String(" ");
+ if (item.widgetItem != 0) {
+ qout << indent << "widget: "
+ << item.widgetItem->widget()->metaObject()->className()
+ << ' ' << item.widgetItem->widget()->windowTitle() << '\n';
+ } else if (item.subinfo != 0) {
+ qout << indent << "subinfo:\n";
+ dumpLayout(qout, *item.subinfo, indent + QLatin1String(" "));
+ } else if (item.placeHolderItem != 0) {
+ QRect r = item.placeHolderItem->topLevelRect;
+ qout << indent << "placeHolder: "
+ << "pos: " << item.pos << " size:" << item.size
+ << " gap:" << (item.flags & QDockAreaLayoutItem::GapItem)
+ << " keepSize:" << (item.flags & QDockAreaLayoutItem::KeepSize)
+ << " objectName:" << item.placeHolderItem->objectName
+ << " hidden:" << item.placeHolderItem->hidden
+ << " window:" << item.placeHolderItem->window
+ << " rect:" << r.x() << ',' << r.y() << ' '
+ << r.width() << 'x' << r.height() << '\n';
+ }
+ qout.flush();
+}
+
+static void dumpLayout(QTextStream &qout, const QDockAreaLayoutInfo &layout, QString indent)
+{
+ qout << indent << "QDockAreaLayoutInfo: "
+ << layout.rect.left() << ','
+ << layout.rect.top() << ' '
+ << layout.rect.width() << 'x'
+ << layout.rect.height()
+ << " orient:" << layout.o
+ << " tabbed:" << layout.tabbed
+ << " tbshape:" << layout.tabBarShape << '\n';
+
+ indent += QLatin1String(" ");
+
+ for (int i = 0; i < layout.item_list.count(); ++i) {
+ qout << indent << "Item: " << i << '\n';
+ dumpLayout(qout, layout.item_list.at(i), indent + QLatin1String(" "));
+ }
+ qout.flush();
+};
+
+static void dumpLayout(QTextStream &qout, const QDockAreaLayout &layout, QString indent)
+{
+ qout << indent << "QDockAreaLayout: "
+ << layout.rect.left() << ','
+ << layout.rect.top() << ' '
+ << layout.rect.width() << 'x'
+ << layout.rect.height() << '\n';
+
+ qout << indent << "TopDockArea:\n";
+ dumpLayout(qout, layout.docks[QInternal::TopDock], indent + QLatin1String(" "));
+ qout << indent << "LeftDockArea:\n";
+ dumpLayout(qout, layout.docks[QInternal::LeftDock], indent + QLatin1String(" "));
+ qout << indent << "RightDockArea:\n";
+ dumpLayout(qout, layout.docks[QInternal::RightDock], indent + QLatin1String(" "));
+ qout << indent << "BottomDockArea:\n";
+ dumpLayout(qout, layout.docks[QInternal::BottomDock], indent + QLatin1String(" "));
+
+ qout.flush();
+};
+
+void qt_dumpLayout(QTextStream &qout, QMainWindow *window)
+{
+ QMainWindowLayout *layout = qt_mainwindow_layout(window);
+ dumpLayout(qout, layout->layoutState.dockAreaLayout, QString());
+}
+
+#endif // Q_DEBUG_MAINWINDOW_LAYOUT && !QT_NO_DOCKWIDGET
+
+/******************************************************************************
+** QMainWindowLayoutState
+*/
+
+// we deal with all the #ifndefferry here so QMainWindowLayout code is clean
+
+QMainWindowLayoutState::QMainWindowLayoutState(QMainWindow *win)
+ :
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout(win),
+#endif
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout(win)
+#else
+ centralWidgetItem(0)
+#endif
+
+{
+ mainWindow = win;
+}
+
+QSize QMainWindowLayoutState::sizeHint() const
+{
+
+ QSize result(0, 0);
+
+#ifndef QT_NO_DOCKWIDGET
+ result = dockAreaLayout.sizeHint();
+#else
+ if (centralWidgetItem != 0)
+ result = centralWidgetItem->sizeHint();
+#endif
+
+#ifndef QT_NO_TOOLBAR
+ result = toolBarAreaLayout.sizeHint(result);
+#endif // QT_NO_TOOLBAR
+
+ return result;
+}
+
+QSize QMainWindowLayoutState::minimumSize() const
+{
+ QSize result(0, 0);
+
+#ifndef QT_NO_DOCKWIDGET
+ result = dockAreaLayout.minimumSize();
+#else
+ if (centralWidgetItem != 0)
+ result = centralWidgetItem->minimumSize();
+#endif
+
+#ifndef QT_NO_TOOLBAR
+ result = toolBarAreaLayout.minimumSize(result);
+#endif // QT_NO_TOOLBAR
+
+ return result;
+}
+
+void QMainWindowLayoutState::apply(bool animated)
+{
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout.apply(animated);
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+// dumpLayout(dockAreaLayout, QString());
+ dockAreaLayout.apply(animated);
+#else
+ if (centralWidgetItem != 0) {
+ QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT(layout != 0);
+ layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated);
+ }
+#endif
+}
+
+void QMainWindowLayoutState::fitLayout()
+{
+ QRect r;
+#ifdef QT_NO_TOOLBAR
+ r = rect;
+#else
+ toolBarAreaLayout.rect = rect;
+ r = toolBarAreaLayout.fitLayout();
+#endif // QT_NO_TOOLBAR
+
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout.rect = r;
+ dockAreaLayout.fitLayout();
+#else
+ centralWidgetRect = r;
+#endif
+}
+
+void QMainWindowLayoutState::deleteAllLayoutItems()
+{
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout.deleteAllLayoutItems();
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout.deleteAllLayoutItems();
+#endif
+}
+
+void QMainWindowLayoutState::deleteCentralWidgetItem()
+{
+#ifndef QT_NO_DOCKWIDGET
+ delete dockAreaLayout.centralWidgetItem;
+ dockAreaLayout.centralWidgetItem = 0;
+#else
+ delete centralWidgetItem;
+ centralWidgetItem = 0;
+#endif
+}
+
+QLayoutItem *QMainWindowLayoutState::itemAt(int index, int *x) const
+{
+#ifndef QT_NO_TOOLBAR
+ if (QLayoutItem *ret = toolBarAreaLayout.itemAt(x, index))
+ return ret;
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (QLayoutItem *ret = dockAreaLayout.itemAt(x, index))
+ return ret;
+#else
+ if (centralWidgetItem != 0 && (*x)++ == index)
+ return centralWidgetItem;
+#endif
+
+ return 0;
+}
+
+QLayoutItem *QMainWindowLayoutState::takeAt(int index, int *x)
+{
+#ifndef QT_NO_TOOLBAR
+ if (QLayoutItem *ret = toolBarAreaLayout.takeAt(x, index))
+ return ret;
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (QLayoutItem *ret = dockAreaLayout.takeAt(x, index))
+ return ret;
+#else
+ if (centralWidgetItem != 0 && (*x)++ == index) {
+ QLayoutItem *ret = centralWidgetItem;
+ centralWidgetItem = 0;
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+QList<int> QMainWindowLayoutState::indexOf(QWidget *widget) const
+{
+ QList<int> result;
+
+#ifndef QT_NO_TOOLBAR
+ // is it a toolbar?
+ if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
+ result = toolBarAreaLayout.indexOf(toolBar);
+ if (!result.isEmpty())
+ result.prepend(0);
+ return result;
+ }
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ // is it a dock widget?
+ if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget)) {
+ result = dockAreaLayout.indexOf(dockWidget);
+ if (!result.isEmpty())
+ result.prepend(1);
+ return result;
+ }
+#endif //QT_NO_DOCKWIDGET
+
+ return result;
+}
+
+bool QMainWindowLayoutState::contains(QWidget *widget) const
+{
+#ifndef QT_NO_DOCKWIDGET
+ if (dockAreaLayout.centralWidgetItem != 0 && dockAreaLayout.centralWidgetItem->widget() == widget)
+ return true;
+ if (!dockAreaLayout.indexOf(widget).isEmpty())
+ return true;
+#else
+ if (centralWidgetItem != 0 && centralWidgetItem->widget() == widget)
+ return true;
+#endif
+
+#ifndef QT_NO_TOOLBAR
+ if (!toolBarAreaLayout.indexOf(widget).isEmpty())
+ return true;
+#endif
+ return false;
+}
+
+void QMainWindowLayoutState::setCentralWidget(QWidget *widget)
+{
+ QLayoutItem *item = 0;
+ //make sure we remove the widget
+ deleteCentralWidgetItem();
+
+ if (widget != 0)
+ item = new QWidgetItemV2(widget);
+
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout.centralWidgetItem = item;
+#else
+ centralWidgetItem = item;
+#endif
+}
+
+QWidget *QMainWindowLayoutState::centralWidget() const
+{
+ QLayoutItem *item = 0;
+
+#ifndef QT_NO_DOCKWIDGET
+ item = dockAreaLayout.centralWidgetItem;
+#else
+ item = centralWidgetItem;
+#endif
+
+ if (item != 0)
+ return item->widget();
+ return 0;
+}
+
+QList<int> QMainWindowLayoutState::gapIndex(QWidget *widget,
+ const QPoint &pos) const
+{
+ QList<int> result;
+
+#ifndef QT_NO_TOOLBAR
+ // is it a toolbar?
+ if (qobject_cast<QToolBar*>(widget) != 0) {
+ result = toolBarAreaLayout.gapIndex(pos);
+ if (!result.isEmpty())
+ result.prepend(0);
+ return result;
+ }
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ // is it a dock widget?
+ if (qobject_cast<QDockWidget *>(widget) != 0) {
+ result = dockAreaLayout.gapIndex(pos);
+ if (!result.isEmpty())
+ result.prepend(1);
+ return result;
+ }
+#endif //QT_NO_DOCKWIDGET
+
+ return result;
+}
+
+bool QMainWindowLayoutState::insertGap(const QList<int> &path, QLayoutItem *item)
+{
+ if (path.isEmpty())
+ return false;
+
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0) {
+ Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0);
+ return toolBarAreaLayout.insertGap(path.mid(1), item);
+ }
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1) {
+ Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) != 0);
+ return dockAreaLayout.insertGap(path.mid(1), item);
+ }
+#endif //QT_NO_DOCKWIDGET
+
+ return false;
+}
+
+void QMainWindowLayoutState::remove(const QList<int> &path)
+{
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0)
+ toolBarAreaLayout.remove(path.mid(1));
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ dockAreaLayout.remove(path.mid(1));
+#endif //QT_NO_DOCKWIDGET
+}
+
+void QMainWindowLayoutState::remove(QLayoutItem *item)
+{
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout.remove(item);
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ // is it a dock widget?
+ if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(item->widget())) {
+ QList<int> path = dockAreaLayout.indexOf(dockWidget);
+ if (!path.isEmpty())
+ dockAreaLayout.remove(path);
+ }
+#endif //QT_NO_DOCKWIDGET
+}
+
+void QMainWindowLayoutState::clear()
+{
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout.clear();
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout.clear();
+#else
+ centralWidgetRect = QRect();
+#endif
+
+ rect = QRect();
+}
+
+bool QMainWindowLayoutState::isValid() const
+{
+ return rect.isValid();
+}
+
+QLayoutItem *QMainWindowLayoutState::item(const QList<int> &path)
+{
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0)
+ return toolBarAreaLayout.item(path.mid(1)).widgetItem;
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ return dockAreaLayout.item(path.mid(1)).widgetItem;
+#endif //QT_NO_DOCKWIDGET
+
+ return 0;
+}
+
+QRect QMainWindowLayoutState::itemRect(const QList<int> &path) const
+{
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0)
+ return toolBarAreaLayout.itemRect(path.mid(1));
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ return dockAreaLayout.itemRect(path.mid(1));
+#endif //QT_NO_DOCKWIDGET
+
+ return QRect();
+}
+
+QRect QMainWindowLayoutState::gapRect(const QList<int> &path) const
+{
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0)
+ return toolBarAreaLayout.itemRect(path.mid(1));
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ return dockAreaLayout.gapRect(path.mid(1));
+#endif //QT_NO_DOCKWIDGET
+
+ return QRect();
+}
+
+QLayoutItem *QMainWindowLayoutState::plug(const QList<int> &path)
+{
+ int i = path.first();
+
+#ifndef QT_NO_TOOLBAR
+ if (i == 0)
+ return toolBarAreaLayout.plug(path.mid(1));
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ return dockAreaLayout.plug(path.mid(1));
+#endif //QT_NO_DOCKWIDGET
+
+ return 0;
+}
+
+QLayoutItem *QMainWindowLayoutState::unplug(const QList<int> &path, QMainWindowLayoutState *other)
+{
+ int i = path.first();
+
+#ifdef QT_NO_TOOLBAR
+ Q_UNUSED(other);
+#else
+ if (i == 0)
+ return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout : 0);
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ if (i == 1)
+ return dockAreaLayout.unplug(path.mid(1));
+#endif //QT_NO_DOCKWIDGET
+
+ return 0;
+}
+
+void QMainWindowLayoutState::saveState(QDataStream &stream) const
+{
+#ifndef QT_NO_DOCKWIDGET
+ dockAreaLayout.saveState(stream);
+#endif
+#ifndef QT_NO_TOOLBAR
+ toolBarAreaLayout.saveState(stream);
+#endif
+}
+
+template <typename T>
+static QList<T> findChildrenHelper(const QObject *o)
+{
+ const QObjectList &list = o->children();
+ QList<T> result;
+
+ for (int i=0; i < list.size(); ++i) {
+ if (T t = qobject_cast<T>(list[i])) {
+ result.append(t);
+ }
+ }
+
+ return result;
+}
+
+//pre4.3 tests the format that was used before 4.3
+bool QMainWindowLayoutState::checkFormat(QDataStream &stream, bool pre43)
+{
+#ifdef QT_NO_TOOLBAR
+ Q_UNUSED(pre43);
+#endif
+ while (!stream.atEnd()) {
+ uchar marker;
+ stream >> marker;
+ switch(marker)
+ {
+#ifndef QT_NO_TOOLBAR
+ case QToolBarAreaLayout::ToolBarStateMarker:
+ case QToolBarAreaLayout::ToolBarStateMarkerEx:
+ {
+ QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
+ if (!toolBarAreaLayout.restoreState(stream, toolBars, marker,
+ pre43 /*testing 4.3 format*/, true /*testing*/)) {
+ return false;
+ }
+ }
+ break;
+#endif // QT_NO_TOOLBAR
+
+#ifndef QT_NO_DOCKWIDGET
+ case QDockAreaLayout::DockWidgetStateMarker:
+ {
+ QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow);
+ if (!dockAreaLayout.restoreState(stream, dockWidgets, true /*testing*/)) {
+ return false;
+ }
+ }
+ break;
+#endif
+ default:
+ //there was an error during the parsing
+ return false;
+ }// switch
+ } //while
+
+ //everything went fine: it must be a pre-4.3 saved state
+ return true;
+}
+
+bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
+ const QMainWindowLayoutState &oldState)
+{
+ //make a copy of the data so that we can read it more than once
+ QByteArray copy;
+ while(!_stream.atEnd()) {
+ int length = 1024;
+ QByteArray ba(length, '\0');
+ length = _stream.readRawData(ba.data(), ba.size());
+ ba.resize(length);
+ copy += ba;
+ }
+
+ QDataStream ds(copy);
+ const bool oldFormat = !checkFormat(ds, false);
+ if (oldFormat) {
+ //we should try with the old format
+ QDataStream ds2(copy);
+ if (!checkFormat(ds2, true)) {
+ return false; //format unknown
+ }
+ }
+
+ QDataStream stream(copy);
+
+ while (!stream.atEnd()) {
+ uchar marker;
+ stream >> marker;
+ switch(marker)
+ {
+#ifndef QT_NO_DOCKWIDGET
+ case QDockAreaLayout::DockWidgetStateMarker:
+ {
+ QList<QDockWidget *> dockWidgets = findChildrenHelper<QDockWidget*>(mainWindow);
+ if (!dockAreaLayout.restoreState(stream, dockWidgets))
+ return false;
+
+ for (int i = 0; i < dockWidgets.size(); ++i) {
+ QDockWidget *w = dockWidgets.at(i);
+ QList<int> path = dockAreaLayout.indexOf(w);
+ if (path.isEmpty()) {
+ QList<int> oldPath = oldState.dockAreaLayout.indexOf(w);
+ if (oldPath.isEmpty()) {
+ continue;
+ }
+ QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath);
+ if (info == 0) {
+ continue;
+ }
+ info->item_list.append(QDockAreaLayoutItem(new QDockWidgetItem(w)));
+ }
+ }
+ }
+ break;
+#endif // QT_NO_DOCKWIDGET
+
+#ifndef QT_NO_TOOLBAR
+ case QToolBarAreaLayout::ToolBarStateMarker:
+ case QToolBarAreaLayout::ToolBarStateMarkerEx:
+ {
+ QList<QToolBar *> toolBars = findChildrenHelper<QToolBar*>(mainWindow);
+ if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, oldFormat))
+ return false;
+
+ for (int i = 0; i < toolBars.size(); ++i) {
+ QToolBar *w = toolBars.at(i);
+ QList<int> path = toolBarAreaLayout.indexOf(w);
+ if (path.isEmpty()) {
+ QList<int> oldPath = oldState.toolBarAreaLayout.indexOf(w);
+ if (oldPath.isEmpty()) {
+ continue;
+ }
+ toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(0, w);
+ }
+ }
+ }
+ break;
+#endif //QT_NO_TOOLBAR
+ default:
+ return false;
+ }// switch
+ } //while
+
+
+ return true;
+}
+
+/******************************************************************************
+** QMainWindowLayoutState - toolbars
+*/
+
+#ifndef QT_NO_TOOLBAR
+
+static inline void validateToolBarArea(Qt::ToolBarArea &area)
+{
+ switch (area) {
+ case Qt::LeftToolBarArea:
+ case Qt::RightToolBarArea:
+ case Qt::TopToolBarArea:
+ case Qt::BottomToolBarArea:
+ break;
+ default:
+ area = Qt::TopToolBarArea;
+ }
+}
+
+static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
+{
+ switch (area) {
+ case Qt::LeftToolBarArea: return QInternal::LeftDock;
+ case Qt::RightToolBarArea: return QInternal::RightDock;
+ case Qt::TopToolBarArea: return QInternal::TopDock;
+ case Qt::BottomToolBarArea: return QInternal::BottomDock;
+ default:
+ break;
+ }
+
+ return QInternal::DockCount;
+}
+
+static Qt::ToolBarArea toToolBarArea(QInternal::DockPosition pos)
+{
+ switch (pos) {
+ case QInternal::LeftDock: return Qt::LeftToolBarArea;
+ case QInternal::RightDock: return Qt::RightToolBarArea;
+ case QInternal::TopDock: return Qt::TopToolBarArea;
+ case QInternal::BottomDock: return Qt::BottomToolBarArea;
+ default: break;
+ }
+ return Qt::NoToolBarArea;
+}
+
+static inline Qt::ToolBarArea toToolBarArea(int pos)
+{
+ return toToolBarArea(static_cast<QInternal::DockPosition>(pos));
+}
+
+void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
+{
+ validateToolBarArea(area);
+
+ layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
+ if (savedState.isValid())
+ savedState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
+
+ invalidate();
+}
+
+void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
+{
+ layoutState.toolBarAreaLayout.insertToolBarBreak(before);
+ if (savedState.isValid())
+ savedState.toolBarAreaLayout.insertToolBarBreak(before);
+ invalidate();
+}
+
+void QMainWindowLayout::removeToolBarBreak(QToolBar *before)
+{
+ layoutState.toolBarAreaLayout.removeToolBarBreak(before);
+ if (savedState.isValid())
+ savedState.toolBarAreaLayout.removeToolBarBreak(before);
+ invalidate();
+}
+
+void QMainWindowLayout::moveToolBar(QToolBar *toolbar, int pos)
+{
+ layoutState.toolBarAreaLayout.moveToolBar(toolbar, pos);
+ if (savedState.isValid())
+ savedState.toolBarAreaLayout.moveToolBar(toolbar, pos);
+ invalidate();
+}
+
+/* Removes the toolbar from the mainwindow so that it can be added again. Does not
+ explicitly hide the toolbar. */
+void QMainWindowLayout::removeToolBar(QToolBar *toolbar)
+{
+ if (toolbar) {
+ QObject::disconnect(parentWidget(), SIGNAL(iconSizeChanged(QSize)),
+ toolbar, SLOT(_q_updateIconSize(QSize)));
+ QObject::disconnect(parentWidget(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
+ toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
+
+#ifdef Q_WS_MAC
+ if (usesHIToolBar(toolbar)) {
+ removeFromMacToolbar(toolbar);
+ } else
+#endif // Q_WS_MAC
+ {
+ removeWidget(toolbar);
+ }
+ }
+}
+
+/*!
+ Adds \a toolbar to \a area, continuing the current line.
+*/
+void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
+ QToolBar *toolbar,
+ bool)
+{
+ validateToolBarArea(area);
+#ifdef Q_WS_MAC
+ if ((area == Qt::TopToolBarArea)
+ && layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
+ insertIntoMacToolbar(0, toolbar);
+ } else
+#endif
+ {
+ //let's add the toolbar to the layout
+ addChildWidget(toolbar);
+ QLayoutItem * item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
+ if (savedState.isValid() && item) {
+ // copy the toolbar also in the saved state
+ savedState.toolBarAreaLayout.insertItem(toDockPos(area), item);
+ }
+ invalidate();
+
+ //this ensures that the toolbar has the right window flags (not floating any more)
+ toolbar->d_func()->updateWindowFlags(false /*floating*/);
+ }
+}
+
+/*!
+ Adds \a toolbar before \a before
+*/
+void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
+{
+#ifdef Q_WS_MAC
+ if (usesHIToolBar(before)) {
+ insertIntoMacToolbar(before, toolbar);
+ } else
+#endif // Q_WS_MAC
+ {
+ addChildWidget(toolbar);
+ QLayoutItem * item = layoutState.toolBarAreaLayout.insertToolBar(before, toolbar);
+ if (savedState.isValid() && item) {
+ // copy the toolbar also in the saved state
+ savedState.toolBarAreaLayout.insertItem(before, item);
+ }
+ if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) {
+ currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
+ if (!currentGapPos.isEmpty()) {
+ currentGapPos.prepend(0);
+ currentGapRect = layoutState.itemRect(currentGapPos);
+ }
+ }
+ invalidate();
+ }
+}
+
+Qt::ToolBarArea QMainWindowLayout::toolBarArea(QToolBar *toolbar) const
+{
+ QInternal::DockPosition pos = layoutState.toolBarAreaLayout.findToolBar(toolbar);
+ switch (pos) {
+ case QInternal::LeftDock: return Qt::LeftToolBarArea;
+ case QInternal::RightDock: return Qt::RightToolBarArea;
+ case QInternal::TopDock: return Qt::TopToolBarArea;
+ case QInternal::BottomDock: return Qt::BottomToolBarArea;
+ default: break;
+ }
+#ifdef Q_WS_MAC
+ if (pos == QInternal::DockCount) {
+ if (qtoolbarsInUnifiedToolbarList.contains(toolbar))
+ return Qt::TopToolBarArea;
+ }
+#endif
+ return Qt::NoToolBarArea;
+}
+
+bool QMainWindowLayout::toolBarBreak(QToolBar *toolBar) const
+{
+ return layoutState.toolBarAreaLayout.toolBarBreak(toolBar);
+}
+
+void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
+{
+ option->toolBarArea = toolBarArea(toolBar);
+ layoutState.toolBarAreaLayout.getStyleOptionInfo(option, toolBar);
+}
+
+void QMainWindowLayout::toggleToolBarsVisible()
+{
+ bool updateNonUnifiedParts = true;
+#ifdef Q_WS_MAC
+ if (layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
+ // If we hit this case, someone has pressed the "toolbar button" which will
+ // toggle the unified toolbar visibility, because that's what the user wants.
+ // We might be in a situation where someone has hidden all the toolbars
+ // beforehand (maybe in construction), but now they've hit this button and
+ // and are expecting the items to show. What do we do?
+ // 1) Check the visibility of all the toolbars, if one is visible, do nothing, this
+ // preserves what people would expect (these toolbars were visible when I clicked last time).
+ // 2) If NONE are visible, then show them all. Again, this preserves the user expectation
+ // of, "I want to see the toolbars." The user may get more toolbars than expected, but this
+ // is better seeing nothing.
+ // Don't worry about any of this if we are going invisible. This does mean we may get
+ // into issues when switching into and out of fullscreen mode, but this is probably minor.
+ // If we ever need to do hiding, that would have to be taken care of after the unified toolbar
+ // has finished hiding.
+ // People can of course handle the QEvent::ToolBarChange event themselves and do
+ // WHATEVER they want if they don't like what we are doing (though the unified toolbar
+ // will fire regardless).
+
+ // Check if we REALLY need to update the geometry below. If we only have items in the
+ // unified toolbar, all the docks will be empty, so there's very little point
+ // in doing the geometry as Apple will do it (we also avoid flicker in Cocoa as well).
+ // FWIW, layoutState.toolBarAreaLayout.visible and the state of the unified toolbar
+ // visibility can get out of sync. I really don't think it's a big issue. It is kept
+ // to a minimum because we only change the visibility if we absolutely must.
+ // update the "non unified parts."
+ updateNonUnifiedParts = !layoutState.toolBarAreaLayout.isEmpty();
+
+ // We get this function before the unified toolbar does its thing.
+ // So, the value will be opposite of what we expect.
+ bool goingVisible = !macWindowToolbarIsVisible(qt_mac_window_for(layoutState.mainWindow));
+ if (goingVisible) {
+ const int ToolBarCount = qtoolbarsInUnifiedToolbarList.size();
+ bool needAllVisible = true;
+ for (int i = 0; i < ToolBarCount; ++i) {
+ if (!qtoolbarsInUnifiedToolbarList.at(i)->isHidden()) {
+ needAllVisible = false;
+ break;
+ }
+ }
+ if (needAllVisible) {
+ QBoolBlocker blocker(blockVisiblityCheck); // Disable the visibilty check because
+ // the toggle has already happened.
+ for (int i = 0; i < ToolBarCount; ++i)
+ qtoolbarsInUnifiedToolbarList.at(i)->setVisible(true);
+ }
+ }
+ if (!updateNonUnifiedParts)
+ layoutState.toolBarAreaLayout.visible = goingVisible;
+ }
+#endif
+ if (updateNonUnifiedParts) {
+ layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
+ if (!layoutState.mainWindow->isMaximized()) {
+ QPoint topLeft = parentWidget()->geometry().topLeft();
+ QRect r = parentWidget()->geometry();
+ r = layoutState.toolBarAreaLayout.rectHint(r);
+ r.moveTo(topLeft);
+ parentWidget()->setGeometry(r);
+ } else {
+ update();
+ }
+ }
+}
+
+#endif // QT_NO_TOOLBAR
+
+/******************************************************************************
+** QMainWindowLayoutState - dock areas
+*/
+
+#ifndef QT_NO_DOCKWIDGET
+
+static inline void validateDockWidgetArea(Qt::DockWidgetArea &area)
+{
+ switch (area) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ break;
+ default:
+ area = Qt::LeftDockWidgetArea;
+ }
+}
+
+static QInternal::DockPosition toDockPos(Qt::DockWidgetArea area)
+{
+ switch (area) {
+ case Qt::LeftDockWidgetArea: return QInternal::LeftDock;
+ case Qt::RightDockWidgetArea: return QInternal::RightDock;
+ case Qt::TopDockWidgetArea: return QInternal::TopDock;
+ case Qt::BottomDockWidgetArea: return QInternal::BottomDock;
+ default:
+ break;
+ }
+
+ return QInternal::DockCount;
+}
+
+static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos)
+{
+ switch (pos) {
+ case QInternal::LeftDock : return Qt::LeftDockWidgetArea;
+ case QInternal::RightDock : return Qt::RightDockWidgetArea;
+ case QInternal::TopDock : return Qt::TopDockWidgetArea;
+ case QInternal::BottomDock : return Qt::BottomDockWidgetArea;
+ default:
+ break;
+ }
+
+ return Qt::NoDockWidgetArea;
+}
+
+inline static Qt::DockWidgetArea toDockWidgetArea(int pos)
+{
+ return toDockWidgetArea(static_cast<QInternal::DockPosition>(pos));
+}
+
+void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
+{
+ if (layoutState.dockAreaLayout.corners[corner] == area)
+ return;
+ layoutState.dockAreaLayout.corners[corner] = area;
+ if (savedState.isValid())
+ savedState.dockAreaLayout.corners[corner] = area;
+ invalidate();
+}
+
+Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const
+{
+ return layoutState.dockAreaLayout.corners[corner];
+}
+
+void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
+ QDockWidget *dockwidget,
+ Qt::Orientation orientation)
+{
+ addChildWidget(dockwidget);
+
+ // If we are currently moving a separator, then we need to abort the move, since each
+ // time we move the mouse layoutState is replaced by savedState modified by the move.
+ if (!movingSeparator.isEmpty())
+ endSeparatorMove(movingSeparatorPos);
+
+ layoutState.dockAreaLayout.addDockWidget(toDockPos(area), dockwidget, orientation);
+ emit dockwidget->dockLocationChanged(area);
+ invalidate();
+}
+
+void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
+{
+ addChildWidget(second);
+ layoutState.dockAreaLayout.tabifyDockWidget(first, second);
+ emit second->dockLocationChanged(dockWidgetArea(first));
+ invalidate();
+}
+
+bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
+{
+ addChildWidget(dockwidget);
+ if (!layoutState.dockAreaLayout.restoreDockWidget(dockwidget))
+ return false;
+ emit dockwidget->dockLocationChanged(dockWidgetArea(dockwidget));
+ invalidate();
+ return true;
+}
+
+#ifndef QT_NO_TABBAR
+bool QMainWindowLayout::documentMode() const
+{
+ return _documentMode;
+}
+
+void QMainWindowLayout::setDocumentMode(bool enabled)
+{
+ if (_documentMode == enabled)
+ return;
+
+ _documentMode = enabled;
+
+ // Update the document mode for all tab bars
+ foreach (QTabBar *bar, usedTabBars)
+ bar->setDocumentMode(_documentMode);
+ foreach (QTabBar *bar, unusedTabBars)
+ bar->setDocumentMode(_documentMode);
+}
+#endif // QT_NO_TABBAR
+
+void QMainWindowLayout::setVerticalTabsEnabled(bool enabled)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(enabled);
+#else
+ if (verticalTabsEnabled == enabled)
+ return;
+
+ verticalTabsEnabled = enabled;
+
+ updateTabBarShapes();
+#endif // QT_NO_TABBAR
+}
+
+#ifndef QT_NO_TABWIDGET
+QTabWidget::TabShape QMainWindowLayout::tabShape() const
+{
+ return _tabShape;
+}
+
+void QMainWindowLayout::setTabShape(QTabWidget::TabShape tabShape)
+{
+ if (_tabShape == tabShape)
+ return;
+
+ _tabShape = tabShape;
+
+ updateTabBarShapes();
+}
+
+QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) const
+{
+ return tabPositions[toDockPos(area)];
+}
+
+void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
+{
+ const Qt::DockWidgetArea dockWidgetAreas[] = {
+ Qt::TopDockWidgetArea,
+ Qt::LeftDockWidgetArea,
+ Qt::BottomDockWidgetArea,
+ Qt::RightDockWidgetArea
+ };
+ const QInternal::DockPosition dockPositions[] = {
+ QInternal::TopDock,
+ QInternal::LeftDock,
+ QInternal::BottomDock,
+ QInternal::RightDock
+ };
+
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ if (areas & dockWidgetAreas[i])
+ tabPositions[dockPositions[i]] = tabPosition;
+
+ updateTabBarShapes();
+}
+
+static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
+{
+ const bool rounded = (shape == QTabWidget::Rounded);
+ if (position == QTabWidget::North)
+ return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
+ if (position == QTabWidget::South)
+ return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
+ if (position == QTabWidget::East)
+ return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
+ if (position == QTabWidget::West)
+ return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
+ return QTabBar::RoundedNorth;
+}
+#endif // QT_NO_TABWIDGET
+
+#ifndef QT_NO_TABBAR
+void QMainWindowLayout::updateTabBarShapes()
+{
+#ifndef QT_NO_TABWIDGET
+ const QTabWidget::TabPosition vertical[] = {
+ QTabWidget::West,
+ QTabWidget::East,
+ QTabWidget::North,
+ QTabWidget::South
+ };
+#else
+ const QTabBar::Shape vertical[] = {
+ QTabBar::RoundedWest,
+ QTabBar::RoundedEast,
+ QTabBar::RoundedNorth,
+ QTabBar::RoundedSouth
+ };
+#endif
+
+ QDockAreaLayout &layout = layoutState.dockAreaLayout;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+#ifndef QT_NO_TABWIDGET
+ QTabWidget::TabPosition pos = verticalTabsEnabled ? vertical[i] : tabPositions[i];
+ QTabBar::Shape shape = tabBarShapeFrom(_tabShape, pos);
+#else
+ QTabBar::Shape shape = verticalTabsEnabled ? vertical[i] : QTabBar::RoundedSouth;
+#endif
+ layout.docks[i].setTabBarShape(shape);
+ }
+}
+#endif // QT_NO_TABBAR
+
+void QMainWindowLayout::splitDockWidget(QDockWidget *after,
+ QDockWidget *dockwidget,
+ Qt::Orientation orientation)
+{
+ addChildWidget(dockwidget);
+ layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
+ emit dockwidget->dockLocationChanged(dockWidgetArea(after));
+ invalidate();
+}
+
+Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *widget) const
+{
+ QList<int> pathToWidget = layoutState.dockAreaLayout.indexOf(widget);
+ if (pathToWidget.isEmpty())
+ return Qt::NoDockWidgetArea;
+ return toDockWidgetArea(pathToWidget.first());
+}
+
+void QMainWindowLayout::keepSize(QDockWidget *w)
+{
+ layoutState.dockAreaLayout.keepSize(w);
+}
+
+#ifndef QT_NO_TABBAR
+
+class QMainWindowTabBar : public QTabBar
+{
+public:
+ QMainWindowTabBar(QWidget *parent);
+protected:
+ bool event(QEvent *e);
+};
+
+QMainWindowTabBar::QMainWindowTabBar(QWidget *parent)
+ : QTabBar(parent)
+{
+ setExpanding(false);
+}
+
+bool QMainWindowTabBar::event(QEvent *e)
+{
+ // show the tooltip if tab is too small to fit label
+
+ if (e->type() != QEvent::ToolTip)
+ return QTabBar::event(e);
+ QSize size = this->size();
+ QSize hint = sizeHint();
+ if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
+ size.transpose();
+ hint.transpose();
+ }
+ if (size.width() < hint.width())
+ return QTabBar::event(e);
+ e->accept();
+ return true;
+}
+
+QTabBar *QMainWindowLayout::getTabBar()
+{
+ QTabBar *result = 0;
+ if (!unusedTabBars.isEmpty()) {
+ result = unusedTabBars.takeLast();
+ } else {
+ result = new QMainWindowTabBar(parentWidget());
+ result->setDrawBase(true);
+ result->setElideMode(Qt::ElideRight);
+ result->setDocumentMode(_documentMode);
+ connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
+ }
+
+ usedTabBars.insert(result);
+ return result;
+}
+
+// Allocates a new separator widget if needed
+QWidget *QMainWindowLayout::getSeparatorWidget()
+{
+ QWidget *result = 0;
+ if (!unusedSeparatorWidgets.isEmpty()) {
+ result = unusedSeparatorWidgets.takeLast();
+ } else {
+ result = new QWidget(parentWidget());
+ result->setAttribute(Qt::WA_MouseNoMask, true);
+ result->setAutoFillBackground(false);
+ result->setObjectName(QLatin1String("qt_qmainwindow_extended_splitter"));
+ }
+ usedSeparatorWidgets.insert(result);
+ return result;
+}
+
+void QMainWindowLayout::tabChanged()
+{
+ QTabBar *tb = qobject_cast<QTabBar*>(sender());
+ if (tb == 0)
+ return;
+ QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(tb);
+ if (info == 0)
+ return;
+ info->apply(false);
+
+ if (QWidget *w = centralWidget())
+ w->raise();
+}
+#endif // QT_NO_TABBAR
+
+bool QMainWindowLayout::startSeparatorMove(const QPoint &pos)
+{
+ movingSeparator = layoutState.dockAreaLayout.findSeparator(pos);
+
+ if (movingSeparator.isEmpty())
+ return false;
+
+ savedState = layoutState;
+ movingSeparatorPos = movingSeparatorOrigin = pos;
+
+ return true;
+}
+
+bool QMainWindowLayout::separatorMove(const QPoint &pos)
+{
+ if (movingSeparator.isEmpty())
+ return false;
+ movingSeparatorPos = pos;
+ separatorMoveTimer.start(0, this);
+ return true;
+}
+
+bool QMainWindowLayout::endSeparatorMove(const QPoint&)
+{
+ bool result = !movingSeparator.isEmpty();
+ movingSeparator.clear();
+ savedState.clear();
+ return result;
+}
+
+void QMainWindowLayout::raise(QDockWidget *widget)
+{
+ QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget);
+ if (info == 0)
+ return;
+#ifndef QT_NO_TABBAR
+ if (!info->tabbed)
+ return;
+ info->setCurrentTab(widget);
+#endif
+}
+
+#endif // QT_NO_DOCKWIDGET
+
+
+/******************************************************************************
+** QMainWindowLayoutState - layout interface
+*/
+
+int QMainWindowLayout::count() const
+{
+ qWarning("QMainWindowLayout::count: ?");
+ return 0; //#################################################
+}
+
+QLayoutItem *QMainWindowLayout::itemAt(int index) const
+{
+ int x = 0;
+
+ if (QLayoutItem *ret = layoutState.itemAt(index, &x))
+ return ret;
+
+ if (statusbar && x++ == index)
+ return statusbar;
+
+ return 0;
+}
+
+QLayoutItem *QMainWindowLayout::takeAt(int index)
+{
+ int x = 0;
+
+ if (QLayoutItem *ret = layoutState.takeAt(index, &x)) {
+ // the widget might in fact have been destroyed by now
+ if (QWidget *w = ret->widget()) {
+ widgetAnimator.abort(w);
+ if (w == pluggingWidget)
+ pluggingWidget = 0;
+ }
+
+ if (savedState.isValid() ) {
+ //we need to remove the item also from the saved state to prevent crash
+ savedState.remove(ret);
+ //Also, the item may be contained several times as a gap item.
+ layoutState.remove(ret);
+ }
+
+#ifndef QT_NO_TOOLBAR
+ if (!currentGapPos.isEmpty() && currentGapPos.first() == 0) {
+ currentGapPos = layoutState.toolBarAreaLayout.currentGapIndex();
+ if (!currentGapPos.isEmpty()) {
+ currentGapPos.prepend(0);
+ currentGapRect = layoutState.itemRect(currentGapPos);
+ }
+ }
+#endif
+
+ return ret;
+ }
+
+ if (statusbar && x++ == index) {
+ QLayoutItem *ret = statusbar;
+ statusbar = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+void QMainWindowLayout::setGeometry(const QRect &_r)
+{
+ if (savedState.isValid())
+ return;
+
+ QRect r = _r;
+
+ QLayout::setGeometry(r);
+
+ if (statusbar) {
+ QRect sbr(QPoint(0, 0),
+ QSize(r.width(), statusbar->heightForWidth(r.width()))
+ .expandedTo(statusbar->minimumSize()));
+ sbr.moveBottom(r.bottom());
+ QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr);
+ statusbar->setGeometry(vr);
+ r.setBottom(sbr.top() - 1);
+ }
+
+ layoutState.rect = r;
+ layoutState.fitLayout();
+ applyState(layoutState, false);
+}
+
+void QMainWindowLayout::addItem(QLayoutItem *)
+{ qWarning("QMainWindowLayout::addItem: Please use the public QMainWindow API instead"); }
+
+QSize QMainWindowLayout::sizeHint() const
+{
+ if (!szHint.isValid()) {
+ szHint = layoutState.sizeHint();
+ const QSize sbHint = statusbar ? statusbar->sizeHint() : QSize(0, 0);
+ szHint = QSize(qMax(sbHint.width(), szHint.width()),
+ sbHint.height() + szHint.height());
+ }
+ return szHint;
+}
+
+QSize QMainWindowLayout::minimumSize() const
+{
+ if (!minSize.isValid()) {
+ minSize = layoutState.minimumSize();
+ const QSize sbMin = statusbar ? statusbar->minimumSize() : QSize(0, 0);
+ minSize = QSize(qMax(sbMin.width(), minSize.width()),
+ sbMin.height() + minSize.height());
+#ifdef Q_WS_MAC
+ const QSize storedSize = minSize;
+ int minWidth = 0;
+ foreach (QToolBar *toolbar, qtoolbarsInUnifiedToolbarList) {
+ minWidth += toolbar->sizeHint().width() + 20;
+ }
+ minSize = QSize(qMax(minWidth, storedSize.width()), storedSize.height());
+#endif
+ }
+ return minSize;
+}
+
+void QMainWindowLayout::invalidate()
+{
+ QLayout::invalidate();
+ minSize = szHint = QSize();
+}
+
+/******************************************************************************
+** QMainWindowLayout - remaining stuff
+*/
+
+static void fixToolBarOrientation(QLayoutItem *item, int dockPos)
+{
+#ifndef QT_NO_TOOLBAR
+ QToolBar *toolBar = qobject_cast<QToolBar*>(item->widget());
+ if (toolBar == 0)
+ return;
+
+ QRect oldGeo = toolBar->geometry();
+
+ QInternal::DockPosition pos
+ = static_cast<QInternal::DockPosition>(dockPos);
+ Qt::Orientation o = pos == QInternal::TopDock || pos == QInternal::BottomDock
+ ? Qt::Horizontal : Qt::Vertical;
+ if (o != toolBar->orientation())
+ toolBar->setOrientation(o);
+
+ QSize hint = toolBar->sizeHint().boundedTo(toolBar->maximumSize())
+ .expandedTo(toolBar->minimumSize());
+
+ if (toolBar->size() != hint) {
+ QRect newGeo(oldGeo.topLeft(), hint);
+ if (toolBar->layoutDirection() == Qt::RightToLeft)
+ newGeo.moveRight(oldGeo.right());
+ toolBar->setGeometry(newGeo);
+ }
+
+#else
+ Q_UNUSED(item);
+ Q_UNUSED(dockPos);
+#endif
+}
+
+void QMainWindowLayout::revert(QLayoutItem *widgetItem)
+{
+ if (!savedState.isValid())
+ return;
+
+ QWidget *widget = widgetItem->widget();
+ layoutState = savedState;
+ currentGapPos = layoutState.indexOf(widget);
+ fixToolBarOrientation(widgetItem, currentGapPos.at(1));
+ layoutState.unplug(currentGapPos);
+ layoutState.fitLayout();
+ currentGapRect = layoutState.itemRect(currentGapPos);
+
+ plug(widgetItem);
+}
+
+bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
+{
+ if (!parentWidget()->isVisible() || parentWidget()->isMinimized() || currentGapPos.isEmpty())
+ return false;
+
+ fixToolBarOrientation(widgetItem, currentGapPos.at(1));
+
+ QWidget *widget = widgetItem->widget();
+
+ QList<int> previousPath = layoutState.indexOf(widget);
+
+ QLayoutItem *it = layoutState.plug(currentGapPos);
+ Q_ASSERT(it == widgetItem);
+ Q_UNUSED(it);
+ if (!previousPath.isEmpty())
+ layoutState.remove(previousPath);
+
+ pluggingWidget = widget;
+ QRect globalRect = currentGapRect;
+ globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
+#ifndef QT_NO_DOCKWIDGET
+ if (qobject_cast<QDockWidget*>(widget) != 0) {
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout());
+ if (layout->nativeWindowDeco()) {
+ globalRect.adjust(0, layout->titleHeight(), 0, 0);
+ } else {
+ int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget);
+ globalRect.adjust(-fw, -fw, fw, fw);
+ }
+ }
+#endif
+ widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks);
+
+ return true;
+}
+
+void QMainWindowLayout::animationFinished(QWidget *widget)
+{
+ //this function is called from within the Widget Animator whenever an animation is finished
+ //on a certain widget
+#ifndef QT_NO_TOOLBAR
+ if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
+ QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(tb->layout());
+ if (tbl->animating) {
+ tbl->animating = false;
+ if (tbl->expanded)
+ tbl->layoutActions(tb->size());
+ tb->update();
+ }
+ }
+#endif
+
+ if (widget == pluggingWidget) {
+
+#ifndef QT_NO_DOCKWIDGET
+ if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
+ dw->d_func()->plug(currentGapRect);
+#endif
+#ifndef QT_NO_TOOLBAR
+ if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
+ tb->d_func()->plug(currentGapRect);
+#endif
+
+ savedState.clear();
+ currentGapPos.clear();
+ pluggingWidget = 0;
+ //applying the state will make sure that the currentGap is updated correctly
+ //and all the geometries (especially the one from the central widget) is correct
+ layoutState.apply(false);
+
+#ifndef QT_NO_DOCKWIDGET
+#ifndef QT_NO_TABBAR
+ if (qobject_cast<QDockWidget*>(widget) != 0) {
+ // info() might return null if the widget is destroyed while
+ // animating but before the animationFinished signal is received.
+ if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget))
+ info->setCurrentTab(widget);
+ }
+#endif
+#endif
+ }
+
+ if (!widgetAnimator.animating()) {
+ //all animations are finished
+#ifndef QT_NO_DOCKWIDGET
+ parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
+#ifndef QT_NO_TABBAR
+ foreach (QTabBar *tab_bar, usedTabBars)
+ tab_bar->show();
+#endif // QT_NO_TABBAR
+#endif // QT_NO_DOCKWIDGET
+ }
+
+ updateGapIndicator();
+}
+
+void QMainWindowLayout::restore(bool keepSavedState)
+{
+ if (!savedState.isValid())
+ return;
+
+ layoutState = savedState;
+ applyState(layoutState);
+ if (!keepSavedState)
+ savedState.clear();
+ currentGapPos.clear();
+ pluggingWidget = 0;
+ updateGapIndicator();
+}
+
+QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout)
+ : QLayout(parentLayout ? static_cast<QWidget *>(0) : mainwindow)
+ , layoutState(mainwindow)
+ , savedState(mainwindow)
+ , dockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
+ , statusbar(0)
+#ifndef QT_NO_DOCKWIDGET
+#ifndef QT_NO_TABBAR
+ , _documentMode(false)
+ , verticalTabsEnabled(false)
+#ifndef QT_NO_TABWIDGET
+ , _tabShape(QTabWidget::Rounded)
+#endif
+#endif
+#endif // QT_NO_DOCKWIDGET
+ , widgetAnimator(this)
+ , pluggingWidget(0)
+#ifndef QT_NO_RUBBERBAND
+ , gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow))
+#endif //QT_NO_RUBBERBAND
+#ifdef Q_WS_MAC
+ , blockVisiblityCheck(false)
+#endif
+{
+ if (parentLayout)
+ setParent(parentLayout);
+
+#ifndef QT_NO_DOCKWIDGET
+#ifndef QT_NO_TABBAR
+ sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow);
+#endif
+
+#ifndef QT_NO_TABWIDGET
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ tabPositions[i] = QTabWidget::South;
+#endif
+#endif // QT_NO_DOCKWIDGET
+
+#ifndef QT_NO_RUBBERBAND
+ // For accessibility to identify this special widget.
+ gapIndicator->setObjectName(QLatin1String("qt_rubberband"));
+ gapIndicator->hide();
+#endif
+ pluggingWidget = 0;
+
+ setObjectName(mainwindow->objectName() + QLatin1String("_layout"));
+}
+
+QMainWindowLayout::~QMainWindowLayout()
+{
+ layoutState.deleteAllLayoutItems();
+ layoutState.deleteCentralWidgetItem();
+
+#ifdef Q_WS_MAC
+ cleanUpMacToolbarItems();
+#endif
+
+ delete statusbar;
+}
+
+void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts)
+{
+ if (opts == dockOptions)
+ return;
+
+ dockOptions = opts;
+
+#ifndef QT_NO_DOCKWIDGET
+ setVerticalTabsEnabled(opts & QMainWindow::VerticalTabs);
+#endif
+
+ invalidate();
+}
+
+#ifndef QT_NO_STATUSBAR
+QStatusBar *QMainWindowLayout::statusBar() const
+{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
+
+void QMainWindowLayout::setStatusBar(QStatusBar *sb)
+{
+ if (sb)
+ addChildWidget(sb);
+ delete statusbar;
+ statusbar = sb ? new QWidgetItemV2(sb) : 0;
+ invalidate();
+}
+#endif // QT_NO_STATUSBAR
+
+QWidget *QMainWindowLayout::centralWidget() const
+{
+ return layoutState.centralWidget();
+}
+
+void QMainWindowLayout::setCentralWidget(QWidget *widget)
+{
+ if (widget != 0)
+ addChildWidget(widget);
+ layoutState.setCentralWidget(widget);
+ if (savedState.isValid()) {
+#ifndef QT_NO_DOCKWIDGET
+ savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem;
+ savedState.dockAreaLayout.fallbackToSizeHints = true;
+#else
+ savedState.centralWidgetItem = layoutState.centralWidgetItem;
+#endif
+ }
+ invalidate();
+}
+
+QLayoutItem *QMainWindowLayout::unplug(QWidget *widget)
+{
+ QList<int> path = layoutState.indexOf(widget);
+ if (path.isEmpty())
+ return 0;
+
+ QLayoutItem *item = layoutState.item(path);
+ if (widget->isWindow())
+ return item;
+
+ QRect r = layoutState.itemRect(path);
+ savedState = layoutState;
+
+#ifndef QT_NO_DOCKWIDGET
+ if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
+ dw->d_func()->unplug(r);
+ }
+#endif
+#ifndef QT_NO_TOOLBAR
+ if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) {
+ tb->d_func()->unplug(r);
+ }
+#endif
+
+
+ layoutState.unplug(path ,&savedState);
+ savedState.fitLayout();
+ currentGapPos = path;
+ currentGapRect = r;
+ updateGapIndicator();
+
+ fixToolBarOrientation(item, currentGapPos.at(1));
+
+ return item;
+}
+
+void QMainWindowLayout::updateGapIndicator()
+{
+#ifndef QT_NO_RUBBERBAND
+ gapIndicator->setVisible(!widgetAnimator.animating() && !currentGapPos.isEmpty());
+ gapIndicator->setGeometry(currentGapRect);
+#endif
+}
+
+QList<int> QMainWindowLayout::hover(QLayoutItem *widgetItem, const QPoint &mousePos)
+{
+ if (!parentWidget()->isVisible() || parentWidget()->isMinimized()
+ || pluggingWidget != 0 || widgetItem == 0)
+ return QList<int>();
+
+ QWidget *widget = widgetItem->widget();
+ QPoint pos = parentWidget()->mapFromGlobal(mousePos);
+
+ if (!savedState.isValid())
+ savedState = layoutState;
+
+ QList<int> path = savedState.gapIndex(widget, pos);
+
+ if (!path.isEmpty()) {
+ bool allowed = false;
+
+#ifndef QT_NO_DOCKWIDGET
+ if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
+ allowed = dw->isAreaAllowed(toDockWidgetArea(path.at(1)));
+#endif
+#ifndef QT_NO_TOOLBAR
+ if (QToolBar *tb = qobject_cast<QToolBar*>(widget))
+ allowed = tb->isAreaAllowed(toToolBarArea(path.at(1)));
+#endif
+
+ if (!allowed)
+ path.clear();
+ }
+
+ if (path == currentGapPos)
+ return currentGapPos; // the gap is already there
+
+ currentGapPos = path;
+ if (path.isEmpty()) {
+ fixToolBarOrientation(widgetItem, 2); // 2 = top dock, ie. horizontal
+ restore(true);
+ return QList<int>();
+ }
+
+ fixToolBarOrientation(widgetItem, currentGapPos.at(1));
+
+ QMainWindowLayoutState newState = savedState;
+
+ if (!newState.insertGap(path, widgetItem)) {
+ restore(true); // not enough space
+ return QList<int>();
+ }
+
+ QSize min = newState.minimumSize();
+ QSize size = newState.rect.size();
+
+ if (min.width() > size.width() || min.height() > size.height()) {
+ restore(true);
+ return QList<int>();
+ }
+
+ newState.fitLayout();
+
+ currentGapRect = newState.gapRect(currentGapPos);
+
+#ifndef QT_NO_DOCKWIDGET
+ parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
+#endif
+ layoutState = newState;
+ applyState(layoutState);
+
+ updateGapIndicator();
+
+ return path;
+}
+
+void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animate)
+{
+#ifndef QT_NO_DOCKWIDGET
+#ifndef QT_NO_TABBAR
+ QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
+ QSet<QTabBar*> retired = usedTabBars - used;
+ usedTabBars = used;
+ foreach (QTabBar *tab_bar, retired) {
+ tab_bar->hide();
+ while (tab_bar->count() > 0)
+ tab_bar->removeTab(0);
+ unusedTabBars.append(tab_bar);
+ }
+
+ if (sep == 1) {
+ QSet<QWidget*> usedSeps = newState.dockAreaLayout.usedSeparatorWidgets();
+ QSet<QWidget*> retiredSeps = usedSeparatorWidgets - usedSeps;
+ usedSeparatorWidgets = usedSeps;
+ foreach (QWidget *sepWidget, retiredSeps) {
+ unusedSeparatorWidgets.append(sepWidget);
+ }
+ }
+
+
+#endif // QT_NO_TABBAR
+#endif // QT_NO_DOCKWIDGET
+ newState.apply(dockOptions & QMainWindow::AnimatedDocks && animate);
+}
+
+void QMainWindowLayout::saveState(QDataStream &stream) const
+{
+ layoutState.saveState(stream);
+}
+
+bool QMainWindowLayout::restoreState(QDataStream &stream)
+{
+ savedState = layoutState;
+ layoutState.clear();
+ layoutState.rect = savedState.rect;
+
+ if (!layoutState.restoreState(stream, savedState)) {
+ layoutState.deleteAllLayoutItems();
+ layoutState = savedState;
+ if (parentWidget()->isVisible())
+ applyState(layoutState, false); // hides tabBars allocated by newState
+ return false;
+ }
+
+ if (parentWidget()->isVisible()) {
+ layoutState.fitLayout();
+ applyState(layoutState, false);
+ }
+
+ savedState.deleteAllLayoutItems();
+ savedState.clear();
+
+#ifndef QT_NO_DOCKWIDGET
+ if (parentWidget()->isVisible()) {
+#ifndef QT_NO_TABBAR
+ foreach (QTabBar *tab_bar, usedTabBars)
+ tab_bar->show();
+
+#endif
+ }
+#endif // QT_NO_DOCKWIDGET
+
+ return true;
+}
+
+
+// Returns if this toolbar *should* be using HIToolbar. Won't work for all in between cases
+// for example, you have a toolbar in the top area and then you suddenly turn on
+// HIToolbar.
+bool QMainWindowLayout::usesHIToolBar(QToolBar *toolbar) const
+{
+#ifndef Q_WS_MAC
+ Q_UNUSED(toolbar);
+ return false;
+#else
+ return qtoolbarsInUnifiedToolbarList.contains(toolbar)
+ || ((toolBarArea(toolbar) == Qt::TopToolBarArea)
+ && layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
+#endif
+}
+
+void QMainWindowLayout::timerEvent(QTimerEvent *e)
+{
+#ifndef QT_NO_DOCKWIDGET
+ if (e->timerId() == separatorMoveTimer.timerId()) {
+ //let's move the separators
+ separatorMoveTimer.stop();
+ if (movingSeparator.isEmpty())
+ return;
+ if (movingSeparatorOrigin == movingSeparatorPos)
+ return;
+
+ //when moving the separator, we need to update the previous position
+ parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
+
+ layoutState = savedState;
+ layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
+ movingSeparatorPos);
+ movingSeparatorPos = movingSeparatorOrigin;
+ }
+#endif
+ QLayout::timerEvent(e);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MAINWINDOW
diff --git a/src/widgets/widgets/qmainwindowlayout_mac.mm b/src/widgets/widgets/qmainwindowlayout_mac.mm
new file mode 100644
index 0000000000..28e8764fcb
--- /dev/null
+++ b/src/widgets/widgets/qmainwindowlayout_mac.mm
@@ -0,0 +1,607 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qmainwindowlayout_p.h>
+#include <qtoolbar.h>
+#include <private/qtoolbarlayout_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qtoolbar_p.h>
+
+#ifndef QT_MAC_USE_COCOA
+#include <Carbon/Carbon.h>
+#else
+#include <private/qcocoatoolbardelegate_mac_p.h>
+#import <private/qcocoawindowdelegate_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+#ifdef QT_NAMESPACE
+
+// namespace up the stuff
+#define SS(x) #x
+#define S0(x) SS(x)
+#define S "com.trolltech.qt-" S0(QT_NAMESPACE) ".qmainwindow.qtoolbarInHIToolbar"
+#define SToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".hitoolbar-qtoolbar"
+#define SNSToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".qtoolbarInNSToolbar"
+#define MacToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".qmainwindow.mactoolbar"
+
+#ifndef QT_MAC_USE_COCOA
+static CFStringRef kQToolBarHIToolbarItemClassID = CFSTR(S);
+static CFStringRef kQToolBarHIToolbarIdentifier = CFSTR(SToolbar);
+#else
+static NSString *kQToolBarNSToolbarIdentifier = @SNSToolbar;
+#endif
+static CFStringRef kQMainWindowMacToolbarID = CFSTR(MacToolbar);
+#undef SS
+#undef S0
+#undef S
+#undef SToolbar
+#undef SNSToolbar
+#undef MacToolbar
+
+#else
+#ifndef QT_MAC_USE_COCOA
+static CFStringRef kQToolBarHIToolbarItemClassID = CFSTR("com.trolltech.qt.qmainwindow.qtoolbarInHIToolbar");
+static CFStringRef kQToolBarHIToolbarIdentifier = CFSTR("com.trolltech.qt.hitoolbar-qtoolbar");
+#else
+static NSString *kQToolBarNSToolbarIdentifier = @"com.trolltech.qt.qmainwindow.qtoolbarInNSToolbar";
+#endif
+static CFStringRef kQMainWindowMacToolbarID = CFSTR("com.trolltech.qt.qmainwindow.mactoolbar");
+#endif // QT_NAMESPACE
+
+#ifndef QT_MAC_USE_COCOA
+
+static const int kEventParamQToolBar = 'QTBR';
+static const int kEventParamQMainWindowLayout = 'QMWL';
+
+const EventTypeSpec qtoolbarEvents[] =
+{
+ { kEventClassHIObject, kEventHIObjectConstruct },
+ { kEventClassHIObject, kEventHIObjectDestruct },
+ { kEventClassHIObject, kEventHIObjectInitialize },
+ { kEventClassToolbarItem, kEventToolbarItemCreateCustomView }
+};
+
+struct QToolBarInHIToolbarInfo
+{
+ QToolBarInHIToolbarInfo(HIToolbarItemRef item)
+ : toolbarItem(item), mainWindowLayout(0)
+ {}
+ HIToolbarItemRef toolbarItem;
+ QMainWindowLayout *mainWindowLayout;
+};
+
+OSStatus QMainWindowLayout::qtoolbarInHIToolbarHandler(EventHandlerCallRef inCallRef,
+ EventRef event, void *data)
+{
+ OSStatus result = eventNotHandledErr;
+ QToolBarInHIToolbarInfo *object = static_cast<QToolBarInHIToolbarInfo *>(data);
+
+ switch (GetEventClass(event)) {
+ case kEventClassHIObject:
+ switch (GetEventKind(event)) {
+ case kEventHIObjectConstruct:
+ {
+ HIObjectRef toolbarItem;
+ GetEventParameter(event, kEventParamHIObjectInstance, typeHIObjectRef,
+ 0, sizeof( HIObjectRef ), 0, &toolbarItem);
+
+ QToolBarInHIToolbarInfo *item = new QToolBarInHIToolbarInfo(toolbarItem);
+ SetEventParameter(event, kEventParamHIObjectInstance, typeVoidPtr,
+ sizeof(void *), &item);
+ result = noErr;
+ }
+ break;
+ case kEventHIObjectInitialize:
+ result = CallNextEventHandler(inCallRef, event);
+ if (result == noErr) {
+ QToolBar *toolbar = 0;
+ QMainWindowLayout *layout = 0;
+ GetEventParameter(event, kEventParamQToolBar, typeVoidPtr,
+ 0, sizeof(void *), 0, &toolbar);
+ GetEventParameter(event, kEventParamQMainWindowLayout, typeVoidPtr,
+ 0, sizeof(void *), 0, &layout);
+ object->mainWindowLayout = layout;
+ object->mainWindowLayout->unifiedToolbarHash.insert(object->toolbarItem, toolbar);
+ HIToolbarItemChangeAttributes(object->toolbarItem,
+ kHIToolbarItemLabelDisabled, 0);
+ }
+ break;
+
+ case kEventHIObjectDestruct:
+ delete object;
+ result = noErr;
+ break;
+ }
+ break;
+
+ case kEventClassToolbarItem:
+ switch (GetEventKind(event))
+ {
+ case kEventToolbarItemCreateCustomView:
+ {
+ QToolBar *toolbar
+ = object->mainWindowLayout->unifiedToolbarHash.value(object->toolbarItem);
+ if (toolbar) {
+ HIViewRef hiview = HIViewRef(toolbar->winId());
+ SetEventParameter(event, kEventParamControlRef, typeControlRef,
+ sizeof(HIViewRef), &hiview);
+ result = noErr;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return result;
+}
+
+void QMainWindowLayout::qtMacHIToolbarRegisterQToolBarInHIToolborItemClass()
+{
+ static bool registered = false;
+
+ if (!registered) {
+ HIObjectRegisterSubclass( kQToolBarHIToolbarItemClassID,
+ kHIToolbarItemClassID, 0, QMainWindowLayout::qtoolbarInHIToolbarHandler,
+ GetEventTypeCount(qtoolbarEvents), qtoolbarEvents, 0, 0 );
+ registered = true;
+ }
+}
+
+static void GetToolbarAllowedItems(CFMutableArrayRef array)
+{
+ CFArrayAppendValue(array, kQToolBarHIToolbarIdentifier);
+}
+
+HIToolbarItemRef QMainWindowLayout::createQToolBarInHIToolbarItem(QToolBar *toolbar,
+ QMainWindowLayout *layout)
+{
+ QMainWindowLayout::qtMacHIToolbarRegisterQToolBarInHIToolborItemClass();
+
+ EventRef event;
+ HIToolbarItemRef result = 0;
+
+ CFStringRef identifier = kQToolBarHIToolbarIdentifier;
+ UInt32 options = kHIToolbarItemAllowDuplicates;
+
+ CreateEvent(0, kEventClassHIObject, kEventHIObjectInitialize,
+ GetCurrentEventTime(), 0, &event);
+ SetEventParameter(event, kEventParamToolbarItemIdentifier, typeCFStringRef,
+ sizeof(CFStringRef), &identifier);
+ SetEventParameter(event, kEventParamAttributes, typeUInt32, sizeof(UInt32), &options);
+ SetEventParameter(event, kEventParamQToolBar, typeVoidPtr, sizeof(void *), &toolbar);
+ SetEventParameter(event, kEventParamQMainWindowLayout, typeVoidPtr, sizeof(void *), &layout);
+
+ HIObjectCreate(kQToolBarHIToolbarItemClassID, event,
+ static_cast<HIObjectRef *>(&result));
+
+ ReleaseEvent(event);
+ return result;
+
+}
+
+HIToolbarItemRef QMainWindowLayout::CreateToolbarItemForIdentifier(CFStringRef identifier,
+ CFTypeRef data)
+{
+ HIToolbarItemRef item = 0;
+ if (CFStringCompare(kQToolBarHIToolbarIdentifier, identifier,
+ kCFCompareBackwards) == kCFCompareEqualTo) {
+ if (data && CFGetTypeID(data) == CFArrayGetTypeID()) {
+ CFArrayRef array = static_cast<CFArrayRef>(data);
+ QToolBar *toolbar = static_cast<QToolBar *>(const_cast<void *>(CFArrayGetValueAtIndex(array, 0)));
+ QMainWindowLayout *layout = static_cast<QMainWindowLayout *>(const_cast<void *>(CFArrayGetValueAtIndex(array, 1)));
+ item = createQToolBarInHIToolbarItem(toolbar, layout);
+ }
+ }
+ return item;
+}
+
+static const EventTypeSpec kToolbarEvents[] = {
+{ kEventClassToolbar, kEventToolbarGetDefaultIdentifiers },
+{ kEventClassToolbar, kEventToolbarGetAllowedIdentifiers },
+{ kEventClassToolbar, kEventToolbarCreateItemWithIdentifier },
+{ kEventClassToolbar, kEventToolbarItemAdded },
+{ kEventClassToolbar, kEventToolbarItemRemoved }
+};
+
+OSStatus QMainWindowLayout::qtmacToolbarDelegate(EventHandlerCallRef, EventRef event, void *data)
+{
+ QMainWindowLayout *mainWindowLayout = static_cast<QMainWindowLayout *>(data);
+ OSStatus result = eventNotHandledErr;
+ CFMutableArrayRef array;
+ CFStringRef identifier;
+ switch (GetEventKind(event)) {
+ case kEventToolbarGetDefaultIdentifiers:
+ case kEventToolbarGetAllowedIdentifiers:
+ GetEventParameter(event, kEventParamMutableArray, typeCFMutableArrayRef, 0,
+ sizeof(CFMutableArrayRef), 0, &array);
+ GetToolbarAllowedItems(array);
+ result = noErr;
+ break;
+ case kEventToolbarCreateItemWithIdentifier: {
+ HIToolbarItemRef item;
+ CFTypeRef data = 0;
+ OSStatus err = GetEventParameter(event, kEventParamToolbarItemIdentifier, typeCFStringRef,
+ 0, sizeof(CFStringRef), 0, &identifier);
+ err = GetEventParameter(event, kEventParamToolbarItemConfigData, typeCFTypeRef,
+ 0, sizeof(CFTypeRef), 0, &data);
+ item = CreateToolbarItemForIdentifier(identifier, data);
+ if (item) {
+ result = SetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
+ sizeof(HIToolbarItemRef), &item );
+ }
+ break;
+ }
+ case kEventToolbarItemAdded: {
+ // Double check that our "view" of the toolbar is similar.
+ HIToolbarItemRef item;
+ CFIndex index;
+ if (GetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
+ 0, sizeof(HIToolbarItemRef), 0, &item) == noErr
+ && GetEventParameter(event, kEventParamIndex, typeCFIndex, 0,
+ sizeof(CFIndex), 0, &index) == noErr) {
+ CFRetain(item); // We will watch this until it's removed from the list (or bust).
+ mainWindowLayout->toolbarItemsCopy.insert(index, item);
+ QToolBar *toolbar = mainWindowLayout->unifiedToolbarHash.value(item);
+ if (toolbar) {
+ int toolbarIndex = mainWindowLayout->qtoolbarsInUnifiedToolbarList.indexOf(toolbar);
+ if (index != toolbarIndex) {
+ // Dang, we must be out of sync, rebuild it from the "toolbarItemsCopy"
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.clear();
+ for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
+ // This will either append the correct toolbar or an
+ // null toolbar. This is fine because this list
+ // is really only kept to make sure that things are but in the right order.
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.append(
+ mainWindowLayout->unifiedToolbarHash.value(mainWindowLayout->
+ toolbarItemsCopy.at(i)));
+ }
+ }
+ }
+ }
+ break;
+ }
+ case kEventToolbarItemRemoved: {
+ HIToolbarItemRef item;
+ if (GetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
+ 0, sizeof(HIToolbarItemRef), 0, &item) == noErr) {
+ mainWindowLayout->unifiedToolbarHash.remove(item);
+ for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
+ if (mainWindowLayout->toolbarItemsCopy.at(i) == item) {
+ // I know about it, so release it.
+ mainWindowLayout->toolbarItemsCopy.removeAt(i);
+ mainWindowLayout->qtoolbarsInUnifiedToolbarList.removeAt(i);
+ CFRelease(item);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return result;
+}
+#endif // ! QT_MAC_USE_COCOA
+
+#ifndef kWindowUnifiedTitleAndToolbarAttribute
+#define kWindowUnifiedTitleAndToolbarAttribute (1 << 7)
+#endif
+
+void QMainWindowLayout::updateHIToolBarStatus()
+{
+ bool useMacToolbar = layoutState.mainWindow->unifiedTitleAndToolBarOnMac();
+#ifndef QT_MAC_USE_COCOA
+ if (useMacToolbar) {
+ ChangeWindowAttributes(qt_mac_window_for(layoutState.mainWindow),
+ kWindowUnifiedTitleAndToolbarAttribute, 0);
+ } else {
+ ChangeWindowAttributes(qt_mac_window_for(layoutState.mainWindow),
+ 0, kWindowUnifiedTitleAndToolbarAttribute);
+ }
+#endif
+
+ layoutState.mainWindow->setUpdatesEnabled(false); // reduces a little bit of flicker, not all though
+#if defined(QT_MAC_USE_COCOA)
+ QMacCocoaAutoReleasePool pool;
+ NSView *cView = [qt_mac_window_for(layoutState.mainWindow) contentView];
+ if (useMacToolbar) {
+ [cView setPostsFrameChangedNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver: [QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate]
+ selector: @selector(syncContentViewFrame:)
+ name: NSViewFrameDidChangeNotification
+ object: cView];
+ }
+#endif
+ if (!useMacToolbar) {
+ macWindowToolbarShow(layoutState.mainWindow, false);
+ // Move everything out of the HIToolbar into the main toolbar.
+ while (!qtoolbarsInUnifiedToolbarList.isEmpty()) {
+ // Should shrink the list by one every time.
+ QToolBar *toolbar = qtoolbarsInUnifiedToolbarList.first();
+#if defined(QT_MAC_USE_COCOA)
+ unifiedSurface->removeToolbar(toolbar);
+#endif
+ layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
+ }
+ macWindowToolbarSet(qt_mac_window_for(layoutState.mainWindow), 0);
+ } else {
+ QList<QToolBar *> toolbars = layoutState.mainWindow->findChildren<QToolBar *>();
+ for (int i = 0; i < toolbars.size(); ++i) {
+ QToolBar *toolbar = toolbars.at(i);
+ if (toolBarArea(toolbar) == Qt::TopToolBarArea) {
+ // Do this here, because we are in an in-between state.
+ removeWidget(toolbar);
+ layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
+ }
+ }
+ syncUnifiedToolbarVisibility();
+ }
+#if defined(QT_MAC_USE_COCOA)
+ if (!useMacToolbar) {
+ [cView setPostsFrameChangedNotifications:NO];
+ [[NSNotificationCenter defaultCenter] removeObserver: [QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate]
+ name: NSViewFrameDidChangeNotification
+ object: cView];
+ }
+#endif
+ layoutState.mainWindow->setUpdatesEnabled(true);
+}
+
+void QMainWindowLayout::insertIntoMacToolbar(QToolBar *before, QToolBar *toolbar)
+{
+ // This layering could go on to one more level, but I decided to stop here.
+ // The HIToolbar and NSToolbar APIs are fairly similar as you will see.
+ if (toolbar == 0)
+ return;
+
+#if defined(QT_MAC_USE_COCOA)
+ // toolbar will now become native (if not already) since we need
+ // an nsview for it inside the corresponding NSToolbarItem.
+ // Setting isInUnifiedToolbar will (among other things) stop alien
+ // siblings from becoming native when this happends since the toolbar
+ // will not overlap with other children of the QMainWindow. NB: Switching
+ // unified toolbar off after this stage is not supported, as this means
+ // that either the menubar must be alien again, or the sibling must
+ // be backed by an nsview to protect from overlapping issues:
+ toolbar->d_func()->isInUnifiedToolbar = true;
+#endif
+
+ QToolBarLayout *toolbarLayout = static_cast<QToolBarLayout *>(toolbar->layout());
+ toolbarSaveState.insert(toolbar, ToolBarSaveState(toolbar->isMovable(), toolbar->maximumSize()));
+
+ if (toolbarLayout->hasExpandFlag() == false)
+ toolbar->setMaximumSize(toolbar->sizeHint());
+
+ toolbar->setMovable(false);
+ toolbarLayout->setUsePopupMenu(true);
+ // Make the toolbar a child of the mainwindow to avoid creating a window.
+ toolbar->setParent(layoutState.mainWindow);
+
+ toolbar->winId(); // Now create the OSViewRef.
+ layoutState.mainWindow->createWinId();
+
+ OSWindowRef window = qt_mac_window_for(layoutState.mainWindow);
+ int beforeIndex = qtoolbarsInUnifiedToolbarList.indexOf(before);
+ if (beforeIndex == -1)
+ beforeIndex = qtoolbarsInUnifiedToolbarList.size();
+
+ int toolbarIndex = qtoolbarsInUnifiedToolbarList.indexOf(toolbar);
+
+#ifndef QT_MAC_USE_COCOA
+ HIToolbarRef macToolbar = NULL;
+ if ((GetWindowToolbar(window, &macToolbar) == noErr) && !macToolbar) {
+ HIToolbarCreate(kQMainWindowMacToolbarID,
+ kHIToolbarItemAllowDuplicates, &macToolbar);
+ InstallEventHandler(HIObjectGetEventTarget(static_cast<HIToolbarRef>(macToolbar)),
+ QMainWindowLayout::qtmacToolbarDelegate, GetEventTypeCount(kToolbarEvents),
+ kToolbarEvents, this, 0);
+ HIToolbarSetDisplaySize(macToolbar, kHIToolbarDisplaySizeNormal);
+ HIToolbarSetDisplayMode(macToolbar, kHIToolbarDisplayModeIconOnly);
+ macWindowToolbarSet(window, macToolbar);
+ if (layoutState.mainWindow->isVisible())
+ macWindowToolbarShow(layoutState.mainWindow, true);
+ CFRelease(macToolbar);
+ }
+#else
+ QMacCocoaAutoReleasePool pool;
+ NSToolbar *macToolbar = [window toolbar];
+ if (macToolbar == nil) {
+ macToolbar = [[NSToolbar alloc] initWithIdentifier:(NSString *)kQMainWindowMacToolbarID];
+ [macToolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
+ [macToolbar setSizeMode:NSToolbarSizeModeRegular];
+ [macToolbar setDelegate:[[QT_MANGLE_NAMESPACE(QCocoaToolBarDelegate) alloc] initWithMainWindowLayout:this]];
+ [window setToolbar:macToolbar];
+ [macToolbar release];
+ }
+#endif
+ if (toolbarIndex != -1) {
+ qtoolbarsInUnifiedToolbarList.removeAt(toolbarIndex);
+#ifndef QT_MAC_USE_COCOA
+ HIToolbarRemoveItemAtIndex(macToolbar, toolbarIndex);
+#else
+ [macToolbar removeItemAtIndex:toolbarIndex];
+#endif
+ }
+ qtoolbarsInUnifiedToolbarList.insert(beforeIndex, toolbar);
+
+ // Adding to the unified toolbar surface for the raster engine.
+ if (layoutState.mainWindow->windowSurface()) {
+ QPoint offset(0, 0);
+ for (int i = 0; i < beforeIndex; ++i) {
+ offset.setX(offset.x() + qtoolbarsInUnifiedToolbarList.at(i)->size().width());
+ }
+#ifdef QT_MAC_USE_COCOA
+ unifiedSurface->insertToolbar(toolbar, offset);
+#endif // QT_MAC_USE_COCOA
+ }
+
+#ifndef QT_MAC_USE_COCOA
+ QCFType<HIToolbarItemRef> outItem;
+ const QObject *stupidArray[] = { toolbar, this };
+ QCFType<CFArrayRef> array = CFArrayCreate(0, reinterpret_cast<const void **>(&stupidArray),
+ 2, 0);
+ HIToolbarCreateItemWithIdentifier(macToolbar, kQToolBarHIToolbarIdentifier,
+ array, &outItem);
+ HIToolbarInsertItemAtIndex(macToolbar, outItem, beforeIndex);
+#else
+ NSString *toolbarID = kQToolBarNSToolbarIdentifier;
+ toolbarID = [toolbarID stringByAppendingFormat:@"%p", toolbar];
+ cocoaItemIDToToolbarHash.insert(qt_mac_NSStringToQString(toolbarID), toolbar);
+ [macToolbar insertItemWithItemIdentifier:toolbarID atIndex:beforeIndex];
+#endif
+}
+
+#ifdef QT_MAC_USE_COCOA
+void QMainWindowLayout::updateUnifiedToolbarOffset()
+{
+ QPoint offset(0, 0);
+
+ for (int i = 1; i < qtoolbarsInUnifiedToolbarList.length(); ++i) {
+ offset.setX(offset.x() + qtoolbarsInUnifiedToolbarList.at(i - 1)->size().width());
+ qtoolbarsInUnifiedToolbarList.at(i)->d_func()->toolbar_offset = offset;
+ }
+}
+#endif // QT_MAC_USE_COCOA
+
+
+void QMainWindowLayout::removeFromMacToolbar(QToolBar *toolbar)
+{
+ QHash<void *, QToolBar *>::iterator it = unifiedToolbarHash.begin();
+ while (it != unifiedToolbarHash.end()) {
+ if (it.value() == toolbar) {
+ // Rescue our HIView and set it on the mainWindow again.
+ bool saveVisible = !toolbar->isHidden();
+ toolbar->setParent(0);
+ toolbar->setParent(parentWidget());
+ toolbar->setVisible(saveVisible);
+ ToolBarSaveState saveState = toolbarSaveState.value(toolbar);
+ static_cast<QToolBarLayout *>(toolbar->layout())->setUsePopupMenu(false);
+ toolbar->setMovable(saveState.movable);
+ toolbar->setMaximumSize(saveState.maximumSize);
+ toolbarSaveState.remove(toolbar);
+#ifndef QT_MAC_USE_COCOA
+ HIToolbarItemRef item = static_cast<HIToolbarItemRef>(it.key());
+ HIToolbarRemoveItemAtIndex(HIToolbarItemGetToolbar(item),
+ toolbarItemsCopy.indexOf(item));
+#else
+ NSToolbarItem *item = static_cast<NSToolbarItem *>(it.key());
+ [[qt_mac_window_for(layoutState.mainWindow->window()) toolbar]
+ removeItemAtIndex:toolbarItemsCopy.indexOf(item)];
+ unifiedToolbarHash.remove(item);
+ qtoolbarsInUnifiedToolbarList.removeAll(toolbar);
+#endif
+ break;
+ }
+ ++it;
+ }
+}
+
+void QMainWindowLayout::cleanUpMacToolbarItems()
+{
+#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
+#endif
+ for (int i = 0; i < toolbarItemsCopy.size(); ++i) {
+#ifdef QT_MAC_USE_COCOA
+ NSToolbarItem *item = static_cast<NSToolbarItem *>(toolbarItemsCopy.at(i));
+ [item setView:0];
+#endif
+ CFRelease(toolbarItemsCopy.at(i));
+ }
+ toolbarItemsCopy.clear();
+ unifiedToolbarHash.clear();
+
+#ifdef QT_MAC_USE_COCOA
+ OSWindowRef window = qt_mac_window_for(layoutState.mainWindow);
+ NSToolbar *macToolbar = [window toolbar];
+ if (macToolbar) {
+ [[macToolbar delegate] release];
+ [macToolbar setDelegate:nil];
+ }
+#endif
+}
+
+void QMainWindowLayout::fixSizeInUnifiedToolbar(QToolBar *tb) const
+{
+#ifdef QT_MAC_USE_COCOA
+ QHash<void *, QToolBar *>::const_iterator it = unifiedToolbarHash.constBegin();
+ NSToolbarItem *item = nil;
+ while (it != unifiedToolbarHash.constEnd()) {
+ if (tb == it.value()) {
+ item = static_cast<NSToolbarItem *>(it.key());
+ break;
+ }
+ ++it;
+ }
+ if (item) {
+ QMacCocoaAutoReleasePool pool;
+ QWidgetItem layoutItem(tb);
+ QSize size = layoutItem.maximumSize();
+ NSSize nssize = NSMakeSize(size.width(), size.height());
+ [item setMaxSize:nssize];
+ size = layoutItem.minimumSize();
+ nssize.width = size.width();
+ nssize.height = size.height();
+ [item setMinSize:nssize];
+ }
+#else
+ Q_UNUSED(tb);
+#endif
+}
+
+void QMainWindowLayout::syncUnifiedToolbarVisibility()
+{
+ if (blockVisiblityCheck)
+ return;
+
+ Q_ASSERT(layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
+ bool show = false;
+ const int ToolBarCount = qtoolbarsInUnifiedToolbarList.count();
+ for (int i = 0; i < ToolBarCount; ++i) {
+ if (qtoolbarsInUnifiedToolbarList.at(i)->isVisible()) {
+ show = true;
+ break;
+ }
+ }
+ macWindowToolbarShow(layoutState.mainWindow, show);
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h
new file mode 100644
index 0000000000..f8116096c7
--- /dev/null
+++ b/src/widgets/widgets/qmainwindowlayout_p.h
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICMAINWINDOWLAYOUT_P_H
+#define QDYNAMICMAINWINDOWLAYOUT_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 "qmainwindow.h"
+
+#ifndef QT_NO_MAINWINDOW
+
+#include "QtWidgets/qlayout.h"
+#include "QtWidgets/qtabbar.h"
+#include "QtCore/qvector.h"
+#include "QtCore/qset.h"
+#include "QtCore/qbasictimer.h"
+#include "private/qlayoutengine_p.h"
+#include "private/qwidgetanimator_p.h"
+
+#include "qdockarealayout_p.h"
+#include "qtoolbararealayout_p.h"
+
+//#define Q_DEBUG_MAINWINDOW_LAYOUT
+
+#if defined(Q_DEBUG_MAINWINDOW_LAYOUT) && !defined(QT_NO_DOCKWIDGET)
+QT_BEGIN_NAMESPACE
+class QTextStream;
+Q_WIDGETS_EXPORT void qt_dumpLayout(QTextStream &qout, QMainWindow *window);
+QT_END_NAMESPACE
+#endif // Q_DEBUG_MAINWINDOW_LAYOUT && !QT_NO_DOCKWIDGET
+
+#ifdef Q_WS_MAC
+// Forward defs to make avoid including Carbon.h (faster compile you know ;).
+struct OpaqueHIObjectRef;
+typedef struct OpaqueHIObjectRef* HIObjectRef;
+typedef HIObjectRef HIToolbarItemRef;
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+
+# ifdef QT_MAC_USE_COCOA
+#include <private/qunifiedtoolbarsurface_mac_p.h>
+# endif // QT_MAC_USE_COCOA
+
+#endif // Q_WS_MAC
+
+QT_BEGIN_NAMESPACE
+
+class QToolBar;
+class QRubberBand;
+
+/* This data structure represents the state of all the tool-bars and dock-widgets. It's value based
+ so it can be easilly copied into a temporary variable. All operations are performed without moving
+ any widgets. Only when we are sure we have the desired state, we call apply(), which moves the
+ widgets.
+*/
+
+class QMainWindowLayoutState
+{
+public:
+ QRect rect;
+ QMainWindow *mainWindow;
+
+ QMainWindowLayoutState(QMainWindow *win);
+
+#ifndef QT_NO_TOOLBAR
+ QToolBarAreaLayout toolBarAreaLayout;
+#endif
+
+#ifndef QT_NO_DOCKWIDGET
+ QDockAreaLayout dockAreaLayout;
+#else
+ QLayoutItem *centralWidgetItem;
+ QRect centralWidgetRect;
+#endif
+
+ void apply(bool animated);
+ void deleteAllLayoutItems();
+ void deleteCentralWidgetItem();
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ void fitLayout();
+
+ QLayoutItem *itemAt(int index, int *x) const;
+ QLayoutItem *takeAt(int index, int *x);
+ QList<int> indexOf(QWidget *widget) const;
+ QLayoutItem *item(const QList<int> &path);
+ QRect itemRect(const QList<int> &path) const;
+ QRect gapRect(const QList<int> &path) const; // ### get rid of this, use itemRect() instead
+
+ bool contains(QWidget *widget) const;
+
+ void setCentralWidget(QWidget *widget);
+ QWidget *centralWidget() const;
+
+ QList<int> gapIndex(QWidget *widget, const QPoint &pos) const;
+ bool insertGap(const QList<int> &path, QLayoutItem *item);
+ void remove(const QList<int> &path);
+ void remove(QLayoutItem *item);
+ void clear();
+ bool isValid() const;
+
+ QLayoutItem *plug(const QList<int> &path);
+ QLayoutItem *unplug(const QList<int> &path, QMainWindowLayoutState *savedState = 0);
+
+ void saveState(QDataStream &stream) const;
+ bool checkFormat(QDataStream &stream, bool pre43);
+ bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState);
+};
+
+class Q_AUTOTEST_EXPORT QMainWindowLayout : public QLayout
+{
+ Q_OBJECT
+
+public:
+ QMainWindowLayoutState layoutState, savedState;
+
+ QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLayout);
+ ~QMainWindowLayout();
+
+ QMainWindow::DockOptions dockOptions;
+ void setDockOptions(QMainWindow::DockOptions opts);
+ bool usesHIToolBar(QToolBar *toolbar) const;
+
+ void timerEvent(QTimerEvent *e);
+
+ // status bar
+
+ QLayoutItem *statusbar;
+
+#ifndef QT_NO_STATUSBAR
+ QStatusBar *statusBar() const;
+ void setStatusBar(QStatusBar *sb);
+#endif
+
+ // central widget
+
+ QWidget *centralWidget() const;
+ void setCentralWidget(QWidget *cw);
+
+ // toolbars
+
+#ifndef QT_NO_TOOLBAR
+ void addToolBarBreak(Qt::ToolBarArea area);
+ void insertToolBarBreak(QToolBar *before);
+ void removeToolBarBreak(QToolBar *before);
+
+ void addToolBar(Qt::ToolBarArea area, QToolBar *toolbar, bool needAddChildWidget = true);
+ void insertToolBar(QToolBar *before, QToolBar *toolbar);
+ Qt::ToolBarArea toolBarArea(QToolBar *toolbar) const;
+ bool toolBarBreak(QToolBar *toolBar) const;
+ void getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const;
+ void removeToolBar(QToolBar *toolbar);
+ void toggleToolBarsVisible();
+ void moveToolBar(QToolBar *toolbar, int pos);
+#endif
+
+ // dock widgets
+
+#ifndef QT_NO_DOCKWIDGET
+ void setCorner(Qt::Corner corner, Qt::DockWidgetArea area);
+ Qt::DockWidgetArea corner(Qt::Corner corner) const;
+ void addDockWidget(Qt::DockWidgetArea area,
+ QDockWidget *dockwidget,
+ Qt::Orientation orientation);
+ void splitDockWidget(QDockWidget *after,
+ QDockWidget *dockwidget,
+ Qt::Orientation orientation);
+ void tabifyDockWidget(QDockWidget *first, QDockWidget *second);
+ Qt::DockWidgetArea dockWidgetArea(QDockWidget *dockwidget) const;
+ void raise(QDockWidget *widget);
+ void setVerticalTabsEnabled(bool enabled);
+ bool restoreDockWidget(QDockWidget *dockwidget);
+
+#ifndef QT_NO_TABBAR
+ bool _documentMode;
+ bool documentMode() const;
+ void setDocumentMode(bool enabled);
+
+ QTabBar *getTabBar();
+ QSet<QTabBar*> usedTabBars;
+ QList<QTabBar*> unusedTabBars;
+ bool verticalTabsEnabled;
+
+ QWidget *getSeparatorWidget();
+ QSet<QWidget*> usedSeparatorWidgets;
+ QList<QWidget*> unusedSeparatorWidgets;
+ int sep; // separator extent
+
+#ifndef QT_NO_TABWIDGET
+ QTabWidget::TabPosition tabPositions[4];
+ QTabWidget::TabShape _tabShape;
+
+ QTabWidget::TabShape tabShape() const;
+ void setTabShape(QTabWidget::TabShape tabShape);
+ QTabWidget::TabPosition tabPosition(Qt::DockWidgetArea area) const;
+ void setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition);
+#endif // QT_NO_TABWIDGET
+#endif // QT_NO_TABBAR
+
+ // separators
+
+ QList<int> movingSeparator;
+ QPoint movingSeparatorOrigin, movingSeparatorPos;
+ QBasicTimer separatorMoveTimer;
+
+ bool startSeparatorMove(const QPoint &pos);
+ bool separatorMove(const QPoint &pos);
+ bool endSeparatorMove(const QPoint &pos);
+ void keepSize(QDockWidget *w);
+#endif // QT_NO_DOCKWIDGET
+
+ // save/restore
+
+ enum { // sentinel values used to validate state data
+ VersionMarker = 0xff
+ };
+ void saveState(QDataStream &stream) const;
+ bool restoreState(QDataStream &stream);
+
+ // QLayout interface
+
+ void addItem(QLayoutItem *item);
+ void setGeometry(const QRect &r);
+ QLayoutItem *itemAt(int index) const;
+ QLayoutItem *takeAt(int index);
+ int count() const;
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ mutable QSize szHint;
+ mutable QSize minSize;
+ void invalidate();
+
+ // animations
+
+ QWidgetAnimator widgetAnimator;
+ QList<int> currentGapPos;
+ QRect currentGapRect;
+ QWidget *pluggingWidget;
+#ifndef QT_NO_RUBBERBAND
+ QRubberBand *gapIndicator;
+#endif
+
+ QList<int> hover(QLayoutItem *widgetItem, const QPoint &mousePos);
+ bool plug(QLayoutItem *widgetItem);
+ QLayoutItem *unplug(QWidget *widget);
+ void revert(QLayoutItem *widgetItem);
+ void updateGapIndicator();
+ void paintDropIndicator(QPainter *p, QWidget *widget, const QRegion &clip);
+ void applyState(QMainWindowLayoutState &newState, bool animate = true);
+ void restore(bool keepSavedState = false);
+ void updateHIToolBarStatus();
+ void animationFinished(QWidget *widget);
+
+private Q_SLOTS:
+#ifndef QT_NO_DOCKWIDGET
+#ifndef QT_NO_TABBAR
+ void tabChanged();
+#endif
+#endif
+private:
+#ifndef QT_NO_TABBAR
+ void updateTabBarShapes();
+#endif
+#ifdef Q_WS_MAC
+# ifndef QT_MAC_USE_COCOA
+ static OSStatus qtmacToolbarDelegate(EventHandlerCallRef, EventRef , void *);
+ static OSStatus qtoolbarInHIToolbarHandler(EventHandlerCallRef inCallRef, EventRef event,
+ void *data);
+ static void qtMacHIToolbarRegisterQToolBarInHIToolborItemClass();
+ static HIToolbarItemRef CreateToolbarItemForIdentifier(CFStringRef identifier, CFTypeRef data);
+ static HIToolbarItemRef createQToolBarInHIToolbarItem(QToolBar *toolbar,
+ QMainWindowLayout *layout);
+# endif
+public:
+ struct ToolBarSaveState {
+ ToolBarSaveState() : movable(false) { }
+ ToolBarSaveState(bool newMovable, const QSize &newMax)
+ : movable(newMovable), maximumSize(newMax) { }
+ bool movable;
+ QSize maximumSize;
+ };
+ QList<QToolBar *> qtoolbarsInUnifiedToolbarList;
+ QList<void *> toolbarItemsCopy;
+ QHash<void *, QToolBar *> unifiedToolbarHash;
+ QHash<QToolBar *, ToolBarSaveState> toolbarSaveState;
+ QHash<QString, QToolBar *> cocoaItemIDToToolbarHash;
+ void insertIntoMacToolbar(QToolBar *before, QToolBar *after);
+ void removeFromMacToolbar(QToolBar *toolbar);
+ void cleanUpMacToolbarItems();
+ void fixSizeInUnifiedToolbar(QToolBar *tb) const;
+ bool useHIToolBar;
+ bool activateUnifiedToolbarAfterFullScreen;
+ void syncUnifiedToolbarVisibility();
+ bool blockVisiblityCheck;
+
+#ifdef QT_MAC_USE_COCOA
+ QUnifiedToolbarSurface *unifiedSurface;
+ void updateUnifiedToolbarOffset();
+#endif // QT_MAC_USE_COCOA
+
+#endif // Q_WS_MAC
+};
+QT_END_NAMESPACE
+
+#endif // QT_NO_MAINWINDOW
+
+#endif // QDYNAMICMAINWINDOWLAYOUT_P_H
diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp
new file mode 100644
index 0000000000..2fe9706edf
--- /dev/null
+++ b/src/widgets/widgets/qmdiarea.cpp
@@ -0,0 +1,2678 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QMdiArea
+ \brief The QMdiArea widget provides an area in which MDI windows are displayed.
+ \since 4.3
+ \ingroup mainwindow-classes
+
+
+ QMdiArea functions, essentially, like a window manager for MDI
+ windows. For instance, it draws the windows it manages on itself
+ and arranges them in a cascading or tile pattern. QMdiArea is
+ commonly used as the center widget in a QMainWindow to create MDI
+ applications, but can also be placed in any layout. The following
+ code adds an area to a main window:
+
+ \snippet doc/src/snippets/mdiareasnippets.cpp 0
+
+ Unlike the window managers for top-level windows, all window flags
+ (Qt::WindowFlags) are supported by QMdiArea as long as the flags
+ are supported by the current widget style. If a specific flag is
+ not supported by the style (e.g., the
+ \l{Qt::}{WindowShadeButtonHint}), you can still shade the window
+ with showShaded().
+
+ Subwindows in QMdiArea are instances of QMdiSubWindow. They
+ are added to an MDI area with addSubWindow(). It is common to pass
+ a QWidget, which is set as the internal widget, to this function,
+ but it is also possible to pass a QMdiSubWindow directly.The class
+ inherits QWidget, and you can use the same API as with a normal
+ top-level window when programming. QMdiSubWindow also has behavior
+ that is specific to MDI windows. See the QMdiSubWindow class
+ description for more details.
+
+ A subwindow becomes active when it gets the keyboard focus, or
+ when setFocus() is called. The user activates a window by moving
+ focus in the usual ways. The MDI area emits the
+ subWindowActivated() signal when the active window changes, and
+ the activeSubWindow() function returns the active subwindow.
+
+ The convenience function subWindowList() returns a list of all
+ subwindows. This information could be used in a popup menu
+ containing a list of windows, for example.
+
+ The subwindows are sorted by the current
+ \l{QMdiArea::}{WindowOrder}. This is used for the subWindowList()
+ and for activateNextSubWindow() and acivatePreviousSubWindow().
+ Also, it is used when cascading or tiling the windows with
+ cascadeSubWindows() and tileSubWindows().
+
+ QMdiArea provides two built-in layout strategies for
+ subwindows: cascadeSubWindows() and tileSubWindows(). Both are
+ slots and are easily connected to menu entries.
+
+ \table
+ \row \o \inlineimage mdi-cascade.png
+ \o \inlineimage mdi-tile.png
+ \endtable
+
+ \note The default scroll bar property for QMdiArea is Qt::ScrollBarAlwaysOff.
+
+ \sa QMdiSubWindow
+*/
+
+/*!
+ \fn QMdiArea::subWindowActivated(QMdiSubWindow *window)
+
+ QMdiArea emits this signal after \a window has been activated. When \a
+ window is 0, QMdiArea has just deactivated its last active window, and
+ there are no active windows on the workspace.
+
+ \sa QMdiArea::activeSubWindow()
+*/
+
+/*!
+ \enum QMdiArea::AreaOption
+
+ This enum describes options that customize the behavior of the
+ QMdiArea.
+
+ \value DontMaximizeSubWindowOnActivation When the active subwindow
+ is maximized, the default behavior is to maximize the next
+ subwindow that is activated. Set this option if you do not want
+ this behavior.
+*/
+
+/*!
+ \enum QMdiArea::WindowOrder
+
+ Specifies the criteria to use for ordering the list of child windows
+ returned by subWindowList(). The functions cascadeSubWindows() and
+ tileSubWindows() follow this order when arranging the windows.
+
+ \value CreationOrder The windows are returned in the order of
+ their creation.
+
+ \value StackingOrder The windows are returned in the order in
+ which they are stacked, with the top-most window being last in
+ the list.
+
+ \value ActivationHistoryOrder The windows are returned in the order in
+ which they were activated.
+
+ \sa subWindowList()
+*/
+
+/*!
+ \enum QMdiArea::ViewMode
+ \since 4.4
+
+ This enum describes the view mode of the area; i.e. how sub-windows
+ will be displayed.
+
+ \value SubWindowView Display sub-windows with window frames (default).
+ \value TabbedView Display sub-windows with tabs in a tab bar.
+
+ \sa setViewMode()
+*/
+
+#include "qmdiarea_p.h"
+
+#ifndef QT_NO_MDIAREA
+
+#include <QApplication>
+#include <QStyle>
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+#include <QMacStyle>
+#endif
+#include <QChildEvent>
+#include <QResizeEvent>
+#include <QScrollBar>
+#include <QtAlgorithms>
+#include <QMutableListIterator>
+#include <QPainter>
+#include <QFontMetrics>
+#include <QStyleOption>
+#include <QDesktopWidget>
+#include <QDebug>
+#include <qmath.h>
+#include <private/qlayoutengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QMdi;
+
+// Asserts in debug mode, gives warning otherwise.
+static bool sanityCheck(const QMdiSubWindow * const child, const char *where)
+{
+ if (!child) {
+ const char error[] = "null pointer";
+ Q_ASSERT_X(false, where, error);
+ qWarning("%s:%s", where, error);
+ return false;
+ }
+ return true;
+}
+
+static bool sanityCheck(const QList<QWidget *> &widgets, const int index, const char *where)
+{
+ if (index < 0 || index >= widgets.size()) {
+ const char error[] = "index out of range";
+ Q_ASSERT_X(false, where, error);
+ qWarning("%s:%s", where, error);
+ return false;
+ }
+ if (!widgets.at(index)) {
+ const char error[] = "null pointer";
+ Q_ASSERT_X(false, where, error);
+ qWarning("%s:%s", where, error);
+ return false;
+ }
+ return true;
+}
+
+static void setIndex(int *index, int candidate, int min, int max, bool isIncreasing)
+{
+ if (!index)
+ return;
+
+ if (isIncreasing) {
+ if (candidate > max)
+ *index = min;
+ else
+ *index = qMax(candidate, min);
+ } else {
+ if (candidate < min)
+ *index = max;
+ else
+ *index = qMin(candidate, max);
+ }
+ Q_ASSERT(*index >= min && *index <= max);
+}
+
+static inline bool useScrollBar(const QRect &childrenRect, const QSize &maxViewportSize,
+ Qt::Orientation orientation)
+{
+ if (orientation == Qt::Horizontal)
+ return childrenRect.width() > maxViewportSize.width()
+ || childrenRect.left() < 0
+ || childrenRect.right() >= maxViewportSize.width();
+ else
+ return childrenRect.height() > maxViewportSize.height()
+ || childrenRect.top() < 0
+ || childrenRect.bottom() >= maxViewportSize.height();
+}
+
+// Returns the closest mdi area containing the widget (if any).
+static inline QMdiArea *mdiAreaParent(QWidget *widget)
+{
+ if (!widget)
+ return 0;
+
+ QWidget *parent = widget->parentWidget();
+ while (parent) {
+ if (QMdiArea *area = qobject_cast<QMdiArea *>(parent))
+ return area;
+ parent = parent->parentWidget();
+ }
+ return 0;
+}
+
+#ifndef QT_NO_TABWIDGET
+static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
+{
+ const bool rounded = (shape == QTabWidget::Rounded);
+ if (position == QTabWidget::North)
+ return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
+ if (position == QTabWidget::South)
+ return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
+ if (position == QTabWidget::East)
+ return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
+ if (position == QTabWidget::West)
+ return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
+ return QTabBar::RoundedNorth;
+}
+#endif // QT_NO_TABWIDGET
+
+static inline QString tabTextFor(QMdiSubWindow *subWindow)
+{
+ if (!subWindow)
+ return QString();
+
+ QString title = subWindow->windowTitle();
+ if (subWindow->isWindowModified()) {
+ title.replace(QLatin1String("[*]"), QLatin1String("*"));
+ } else {
+ extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
+ title = qt_setWindowTitle_helperHelper(title, subWindow);
+ }
+
+ return title.isEmpty() ? QMdiArea::tr("(Untitled)") : title;
+}
+
+/*!
+ \internal
+*/
+void RegularTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
+{
+ if (widgets.isEmpty())
+ return;
+
+ const int n = widgets.size();
+ const int ncols = qMax(qCeil(qSqrt(qreal(n))), 1);
+ const int nrows = qMax((n % ncols) ? (n / ncols + 1) : (n / ncols), 1);
+ const int nspecial = (n % ncols) ? (ncols - n % ncols) : 0;
+ const int dx = domain.width() / ncols;
+ const int dy = domain.height() / nrows;
+
+ int i = 0;
+ for (int row = 0; row < nrows; ++row) {
+ const int y1 = int(row * (dy + 1));
+ for (int col = 0; col < ncols; ++col) {
+ if (row == 1 && col < nspecial)
+ continue;
+ const int x1 = int(col * (dx + 1));
+ int x2 = int(x1 + dx);
+ int y2 = int(y1 + dy);
+ if (row == 0 && col < nspecial) {
+ y2 *= 2;
+ if (nrows != 2)
+ y2 += 1;
+ else
+ y2 = domain.bottom();
+ }
+ if (col == ncols - 1 && x2 != domain.right())
+ x2 = domain.right();
+ if (row == nrows - 1 && y2 != domain.bottom())
+ y2 = domain.bottom();
+ if (!sanityCheck(widgets, i, "RegularTiler"))
+ continue;
+ QWidget *widget = widgets.at(i++);
+ QRect newGeometry = QRect(QPoint(x1, y1), QPoint(x2, y2));
+ widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void SimpleCascader::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
+{
+ if (widgets.isEmpty())
+ return;
+
+ // Tunables:
+ const int topOffset = 0;
+ const int bottomOffset = 50;
+ const int leftOffset = 0;
+ const int rightOffset = 100;
+ const int dx = 10;
+
+ QStyleOptionTitleBar options;
+ options.initFrom(widgets.at(0));
+ int titleBarHeight = widgets.at(0)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, widgets.at(0));
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ // ### Remove this after the mac style has been fixed
+ if (qobject_cast<QMacStyle *>(widgets.at(0)->style()))
+ titleBarHeight -= 4;
+#endif
+ const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar"));
+ const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1);
+
+ const int n = widgets.size();
+ const int nrows = qMax((domain.height() - (topOffset + bottomOffset)) / dy, 1);
+ const int ncols = qMax(n / nrows + ((n % nrows) ? 1 : 0), 1);
+ const int dcol = (domain.width() - (leftOffset + rightOffset)) / ncols;
+
+ int i = 0;
+ for (int row = 0; row < nrows; ++row) {
+ for (int col = 0; col < ncols; ++col) {
+ const int x = leftOffset + row * dx + col * dcol;
+ const int y = topOffset + row * dy;
+ if (!sanityCheck(widgets, i, "SimpleCascader"))
+ continue;
+ QWidget *widget = widgets.at(i++);
+ QRect newGeometry = QRect(QPoint(x, y), widget->sizeHint());
+ widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
+ if (i == n)
+ return;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void IconTiler::rearrange(QList<QWidget *> &widgets, const QRect &domain) const
+{
+ if (widgets.isEmpty() || !sanityCheck(widgets, 0, "IconTiler"))
+ return;
+
+ const int n = widgets.size();
+ const int width = widgets.at(0)->width();
+ const int height = widgets.at(0)->height();
+ const int ncols = qMax(domain.width() / width, 1);
+ const int nrows = n / ncols + ((n % ncols) ? 1 : 0);
+
+ int i = 0;
+ for (int row = 0; row < nrows; ++row) {
+ for (int col = 0; col < ncols; ++col) {
+ const int x = col * width;
+ const int y = domain.height() - height - row * height;
+ if (!sanityCheck(widgets, i, "IconTiler"))
+ continue;
+ QWidget *widget = widgets.at(i++);
+ QPoint newPos(x, y);
+ QRect newGeometry = QRect(newPos.x(), newPos.y(), widget->width(), widget->height());
+ widget->setGeometry(QStyle::visualRect(widget->layoutDirection(), domain, newGeometry));
+ if (i == n)
+ return;
+ }
+ }
+}
+
+/*!
+ \internal
+ Calculates the accumulated overlap (intersection area) between 'source' and 'rects'.
+*/
+int MinOverlapPlacer::accumulatedOverlap(const QRect &source, const QList<QRect> &rects)
+{
+ int accOverlap = 0;
+ foreach (const QRect &rect, rects) {
+ QRect intersection = source.intersected(rect);
+ accOverlap += intersection.width() * intersection.height();
+ }
+ return accOverlap;
+}
+
+
+/*!
+ \internal
+ Finds among 'source' the rectangle with the minimum accumulated overlap with the
+ rectangles in 'rects'.
+*/
+QRect MinOverlapPlacer::findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects)
+{
+ int minAccOverlap = -1;
+ QRect minAccOverlapRect;
+ foreach (const QRect &srcRect, source) {
+ const int accOverlap = accumulatedOverlap(srcRect, rects);
+ if (accOverlap < minAccOverlap || minAccOverlap == -1) {
+ minAccOverlap = accOverlap;
+ minAccOverlapRect = srcRect;
+ }
+ }
+ return minAccOverlapRect;
+}
+
+/*!
+ \internal
+ Gets candidates for the final placement.
+*/
+void MinOverlapPlacer::getCandidatePlacements(const QSize &size, const QList<QRect> &rects,
+ const QRect &domain,QList<QRect> &candidates)
+{
+ QSet<int> xset;
+ QSet<int> yset;
+ xset << domain.left() << domain.right() - size.width() + 1;
+ yset << domain.top();
+ if (domain.bottom() - size.height() + 1 >= 0)
+ yset << domain.bottom() - size.height() + 1;
+ foreach (const QRect &rect, rects) {
+ xset << rect.right() + 1;
+ yset << rect.bottom() + 1;
+ }
+
+ QList<int> xlist = xset.values();
+ qSort(xlist.begin(), xlist.end());
+ QList<int> ylist = yset.values();
+ qSort(ylist.begin(), ylist.end());
+
+ foreach (int y, ylist)
+ foreach (int x, xlist)
+ candidates << QRect(QPoint(x, y), size);
+}
+
+/*!
+ \internal
+ Finds all rectangles in 'source' not completely inside 'domain'. The result is stored
+ in 'result' and also removed from 'source'.
+*/
+void MinOverlapPlacer::findNonInsiders(const QRect &domain, QList<QRect> &source,
+ QList<QRect> &result)
+{
+ QMutableListIterator<QRect> it(source);
+ while (it.hasNext()) {
+ const QRect srcRect = it.next();
+ if (!domain.contains(srcRect)) {
+ result << srcRect;
+ it.remove();
+ }
+ }
+}
+
+/*!
+ \internal
+ Finds all rectangles in 'source' that overlaps 'domain' by the maximum overlap area
+ between 'domain' and any rectangle in 'source'. The result is stored in 'result'.
+*/
+void MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const QList<QRect> &source,
+ QList<QRect> &result)
+{
+ int maxOverlap = -1;
+ foreach (const QRect &srcRect, source) {
+ QRect intersection = domain.intersected(srcRect);
+ const int overlap = intersection.width() * intersection.height();
+ if (overlap >= maxOverlap || maxOverlap == -1) {
+ if (overlap > maxOverlap) {
+ maxOverlap = overlap;
+ result.clear();
+ }
+ result << srcRect;
+ }
+ }
+}
+
+/*!
+ \internal
+ Finds among the rectangles in 'source' the best placement. Here, 'best' means the
+ placement that overlaps the rectangles in 'rects' as little as possible while at the
+ same time being as much as possible inside 'domain'.
+*/
+QPoint MinOverlapPlacer::findBestPlacement(const QRect &domain, const QList<QRect> &rects,
+ QList<QRect> &source)
+{
+ QList<QRect> nonInsiders;
+ findNonInsiders(domain, source, nonInsiders);
+
+ if (!source.empty())
+ return findMinOverlapRect(source, rects).topLeft();
+
+ QList<QRect> maxOverlappers;
+ findMaxOverlappers(domain, nonInsiders, maxOverlappers);
+ return findMinOverlapRect(maxOverlappers, rects).topLeft();
+}
+
+
+/*!
+ \internal
+ Places the rectangle defined by 'size' relative to 'rects' and 'domain' so that it
+ overlaps 'rects' as little as possible and 'domain' as much as possible.
+ Returns the position of the resulting rectangle.
+*/
+QPoint MinOverlapPlacer::place(const QSize &size, const QList<QRect> &rects,
+ const QRect &domain) const
+{
+ if (size.isEmpty() || !domain.isValid())
+ return QPoint();
+ foreach (const QRect &rect, rects) {
+ if (!rect.isValid())
+ return QPoint();
+ }
+
+ QList<QRect> candidates;
+ getCandidatePlacements(size, rects, domain, candidates);
+ return findBestPlacement(domain, rects, candidates);
+}
+
+#ifndef QT_NO_TABBAR
+class QMdiAreaTabBar : public QTabBar
+{
+public:
+ QMdiAreaTabBar(QWidget *parent) : QTabBar(parent) {}
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *event);
+#endif
+
+private:
+ QMdiSubWindow *subWindowFromIndex(int index) const;
+};
+
+/*!
+ \internal
+*/
+void QMdiAreaTabBar::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::MidButton) {
+ QTabBar::mousePressEvent(event);
+ return;
+ }
+
+ QMdiSubWindow *subWindow = subWindowFromIndex(tabAt(event->pos()));
+ if (!subWindow) {
+ event->ignore();
+ return;
+ }
+
+ subWindow->close();
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \internal
+*/
+void QMdiAreaTabBar::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPointer<QMdiSubWindow> subWindow = subWindowFromIndex(tabAt(event->pos()));
+ if (!subWindow || subWindow->isHidden()) {
+ event->ignore();
+ return;
+ }
+
+#ifndef QT_NO_MENU
+ QMdiSubWindowPrivate *subWindowPrivate = subWindow->d_func();
+ if (!subWindowPrivate->systemMenu) {
+ event->ignore();
+ return;
+ }
+
+ QMdiSubWindow *currentSubWindow = subWindowFromIndex(currentIndex());
+ Q_ASSERT(currentSubWindow);
+
+ // We don't want these actions to show up in the system menu when the
+ // current sub-window is maximized, i.e. covers the entire viewport.
+ if (currentSubWindow->isMaximized()) {
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::MoveAction, false);
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::ResizeAction, false);
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::MinimizeAction, false);
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::MaximizeAction, false);
+ subWindowPrivate->setVisible(QMdiSubWindowPrivate::StayOnTopAction, false);
+ }
+
+ // Show system menu.
+ subWindowPrivate->systemMenu->exec(event->globalPos());
+ if (!subWindow)
+ return;
+
+ // Restore action visibility.
+ subWindowPrivate->updateActions();
+#endif // QT_NO_MENU
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ \internal
+*/
+QMdiSubWindow *QMdiAreaTabBar::subWindowFromIndex(int index) const
+{
+ if (index < 0 || index >= count())
+ return 0;
+
+ QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parentWidget());
+ Q_ASSERT(mdiArea);
+
+ const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
+ Q_ASSERT(index < subWindows.size());
+
+ QMdiSubWindow *subWindow = mdiArea->subWindowList().at(index);
+ Q_ASSERT(subWindow);
+
+ return subWindow;
+}
+#endif // QT_NO_TABBAR
+
+/*!
+ \internal
+*/
+QMdiAreaPrivate::QMdiAreaPrivate()
+ : cascader(0),
+ regularTiler(0),
+ iconTiler(0),
+ placer(0),
+#ifndef QT_NO_RUBBERBAND
+ rubberBand(0),
+#endif
+#ifndef QT_NO_TABBAR
+ tabBar(0),
+#endif
+ activationOrder(QMdiArea::CreationOrder),
+ viewMode(QMdiArea::SubWindowView),
+#ifndef QT_NO_TABBAR
+ documentMode(false),
+ tabsClosable(false),
+ tabsMovable(false),
+#endif
+#ifndef QT_NO_TABWIDGET
+ tabShape(QTabWidget::Rounded),
+ tabPosition(QTabWidget::North),
+#endif
+ ignoreGeometryChange(false),
+ ignoreWindowStateChange(false),
+ isActivated(false),
+ isSubWindowsTiled(false),
+ showActiveWindowMaximized(false),
+ tileCalledFromResizeEvent(false),
+ updatesDisabledByUs(false),
+ inViewModeChange(false),
+ indexToNextWindow(-1),
+ indexToPreviousWindow(-1),
+ indexToHighlighted(-1),
+ indexToLastActiveTab(-1),
+ resizeTimerId(-1),
+ tabToPreviousTimerId(-1)
+{
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)
+{
+ if (ignoreWindowStateChange)
+ return;
+
+ Q_Q(QMdiArea);
+ if (!aboutToActivate)
+ aboutToBecomeActive = qobject_cast<QMdiSubWindow *>(q->sender());
+ else
+ aboutToBecomeActive = aboutToActivate;
+ Q_ASSERT(aboutToBecomeActive);
+
+ foreach (QMdiSubWindow *child, childWindows) {
+ if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
+ continue;
+ // We don't want to handle signals caused by child->showNormal().
+ ignoreWindowStateChange = true;
+ if(!(options & QMdiArea::DontMaximizeSubWindowOnActivation) && !showActiveWindowMaximized)
+ showActiveWindowMaximized = child->isMaximized() && child->isVisible();
+ if (showActiveWindowMaximized && child->isMaximized()) {
+ if (q->updatesEnabled()) {
+ updatesDisabledByUs = true;
+ q->setUpdatesEnabled(false);
+ }
+ child->showNormal();
+ }
+ if (child->isMinimized() && !child->isShaded() && !windowStaysOnTop(child))
+ child->lower();
+ ignoreWindowStateChange = false;
+ child->d_func()->setActive(false);
+ }
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::_q_processWindowStateChanged(Qt::WindowStates oldState,
+ Qt::WindowStates newState)
+{
+ if (ignoreWindowStateChange)
+ return;
+
+ Q_Q(QMdiArea);
+ QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(q->sender());
+ if (!child)
+ return;
+
+ // windowActivated
+ if (!(oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
+ emitWindowActivated(child);
+ // windowDeactivated
+ else if ((oldState & Qt::WindowActive) && !(newState & Qt::WindowActive))
+ resetActiveWindow(child);
+
+ // windowMinimized
+ if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized)) {
+ isSubWindowsTiled = false;
+ arrangeMinimizedSubWindows();
+ // windowMaximized
+ } else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) {
+ internalRaise(child);
+ // windowRestored
+ } else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) {
+ internalRaise(child);
+ if (oldState & Qt::WindowMinimized)
+ arrangeMinimizedSubWindows();
+ }
+}
+
+void QMdiAreaPrivate::_q_currentTabChanged(int index)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(index);
+#else
+ if (!tabBar || index < 0)
+ return;
+
+ // If the previous active sub-window was hidden, disable the tab.
+ if (indexToLastActiveTab >= 0 && indexToLastActiveTab < tabBar->count()
+ && indexToLastActiveTab < childWindows.count()) {
+ QMdiSubWindow *lastActive = childWindows.at(indexToLastActiveTab);
+ if (lastActive && lastActive->isHidden())
+ tabBar->setTabEnabled(indexToLastActiveTab, false);
+ }
+
+ indexToLastActiveTab = index;
+ Q_ASSERT(childWindows.size() > index);
+ QMdiSubWindow *subWindow = childWindows.at(index);
+ Q_ASSERT(subWindow);
+ activateWindow(subWindow);
+#endif // QT_NO_TABBAR
+}
+
+void QMdiAreaPrivate::_q_closeTab(int index)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(index);
+#else
+ QMdiSubWindow *subWindow = childWindows.at(index);
+ Q_ASSERT(subWindow);
+ subWindow->close();
+#endif // QT_NO_TABBAR
+}
+
+void QMdiAreaPrivate::_q_moveTab(int from, int to)
+{
+#ifdef QT_NO_TABBAR
+ Q_UNUSED(from);
+ Q_UNUSED(to);
+#else
+ childWindows.move(from, to);
+#endif // QT_NO_TABBAR
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::appendChild(QMdiSubWindow *child)
+{
+ Q_Q(QMdiArea);
+ Q_ASSERT(child && childWindows.indexOf(child) == -1);
+
+ if (child->parent() != viewport)
+ child->setParent(viewport, child->windowFlags());
+ childWindows.append(QPointer<QMdiSubWindow>(child));
+
+ if (!child->testAttribute(Qt::WA_Resized) && q->isVisible()) {
+ QSize newSize(child->sizeHint().boundedTo(viewport->size()));
+ child->resize(newSize.expandedTo(qSmartMinSize(child)));
+ }
+
+ if (!placer)
+ placer = new MinOverlapPlacer;
+ place(placer, child);
+
+ if (hbarpolicy != Qt::ScrollBarAlwaysOff)
+ child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, true);
+ else
+ child->setOption(QMdiSubWindow::AllowOutsideAreaHorizontally, false);
+
+ if (vbarpolicy != Qt::ScrollBarAlwaysOff)
+ child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, true);
+ else
+ child->setOption(QMdiSubWindow::AllowOutsideAreaVertically, false);
+
+ internalRaise(child);
+ indicesToActivatedChildren.prepend(childWindows.size() - 1);
+ Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
+
+#ifndef QT_NO_TABBAR
+ if (tabBar) {
+ tabBar->addTab(child->windowIcon(), tabTextFor(child));
+ updateTabBarGeometry();
+ if (childWindows.count() == 1 && !(options & QMdiArea::DontMaximizeSubWindowOnActivation))
+ showActiveWindowMaximized = true;
+ }
+#endif
+
+ if (!(child->windowFlags() & Qt::SubWindow))
+ child->setWindowFlags(Qt::SubWindow);
+ child->installEventFilter(q);
+
+ QObject::connect(child, SIGNAL(aboutToActivate()), q, SLOT(_q_deactivateAllWindows()));
+ QObject::connect(child, SIGNAL(windowStateChanged(Qt::WindowStates,Qt::WindowStates)),
+ q, SLOT(_q_processWindowStateChanged(Qt::WindowStates,Qt::WindowStates)));
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)
+{
+ if (!placer || !child)
+ return;
+
+ Q_Q(QMdiArea);
+ if (!q->isVisible()) {
+ // The window is only laid out when it's added to QMdiArea,
+ // so there's no need to check that we don't have it in the
+ // list already. appendChild() ensures that.
+ pendingPlacements.append(child);
+ return;
+ }
+
+ QList<QRect> rects;
+ QRect parentRect = q->rect();
+ foreach (QMdiSubWindow *window, childWindows) {
+ if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
+ || !window->testAttribute(Qt::WA_Moved)) {
+ continue;
+ }
+ QRect occupiedGeometry;
+ if (window->isMaximized()) {
+ occupiedGeometry = QRect(window->d_func()->oldGeometry.topLeft(),
+ window->d_func()->restoreSize);
+ } else {
+ occupiedGeometry = window->geometry();
+ }
+ rects.append(QStyle::visualRect(child->layoutDirection(), parentRect, occupiedGeometry));
+ }
+ QPoint newPos = placer->place(child->size(), rects, parentRect);
+ QRect newGeometry = QRect(newPos.x(), newPos.y(), child->width(), child->height());
+ child->setGeometry(QStyle::visualRect(child->layoutDirection(), parentRect, newGeometry));
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
+{
+ if (!rearranger)
+ return;
+
+ Q_Q(QMdiArea);
+ if (!q->isVisible()) {
+ // Compress if we already have the rearranger in the list.
+ int index = pendingRearrangements.indexOf(rearranger);
+ if (index != -1)
+ pendingRearrangements.move(index, pendingRearrangements.size() - 1);
+ else
+ pendingRearrangements.append(rearranger);
+ return;
+ }
+
+ QList<QWidget *> widgets;
+ const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
+ const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
+ QSize minSubWindowSize;
+ foreach (QMdiSubWindow *child, subWindows) {
+ if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
+ continue;
+ if (rearranger->type() == Rearranger::IconTiler) {
+ if (child->isMinimized() && !child->isShaded() && !(child->windowFlags() & Qt::FramelessWindowHint))
+ widgets.append(child);
+ } else {
+ if (child->isMinimized() && !child->isShaded())
+ continue;
+ if (child->isMaximized() || child->isShaded())
+ child->showNormal();
+ minSubWindowSize = minSubWindowSize.expandedTo(child->minimumSize())
+ .expandedTo(child->d_func()->internalMinimumSize);
+ widgets.append(child);
+ }
+ }
+
+ if (active && rearranger->type() == Rearranger::RegularTiler) {
+ // Move active window in front if necessary. That's the case if we
+ // have any windows with staysOnTopHint set.
+ int indexToActive = widgets.indexOf((QWidget *)active);
+ if (indexToActive > 0)
+ widgets.move(indexToActive, 0);
+ }
+
+ QRect domain = viewport->rect();
+ if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty())
+ domain = resizeToMinimumTileSize(minSubWindowSize, widgets.count());
+
+ rearranger->rearrange(widgets, domain);
+
+ if (rearranger->type() == Rearranger::RegularTiler && !widgets.isEmpty()) {
+ isSubWindowsTiled = true;
+ updateScrollBars();
+ } else if (rearranger->type() == Rearranger::SimpleCascader) {
+ isSubWindowsTiled = false;
+ }
+}
+
+/*!
+ \internal
+
+ Arranges all minimized windows at the bottom of the workspace.
+*/
+void QMdiAreaPrivate::arrangeMinimizedSubWindows()
+{
+ if (!iconTiler)
+ iconTiler = new IconTiler;
+ rearrange(iconTiler);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::activateWindow(QMdiSubWindow *child)
+{
+ if (childWindows.isEmpty()) {
+ Q_ASSERT(!child);
+ Q_ASSERT(!active);
+ return;
+ }
+
+ if (!child) {
+ if (active) {
+ Q_ASSERT(active->d_func()->isActive);
+ active->d_func()->setActive(false);
+ resetActiveWindow();
+ }
+ return;
+ }
+
+ if (child->isHidden() || child == active)
+ return;
+ child->d_func()->setActive(true);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::activateCurrentWindow()
+{
+ QMdiSubWindow *current = q_func()->currentSubWindow();
+ if (current && !isExplicitlyDeactivated(current)) {
+ current->d_func()->activationEnabled = true;
+ current->d_func()->setActive(true, /*changeFocus=*/false);
+ }
+}
+
+void QMdiAreaPrivate::activateHighlightedWindow()
+{
+ if (indexToHighlighted < 0)
+ return;
+
+ Q_ASSERT(indexToHighlighted < childWindows.size());
+ if (tabToPreviousTimerId != -1)
+ activateWindow(nextVisibleSubWindow(-1, QMdiArea::ActivationHistoryOrder));
+ else
+ activateWindow(childWindows.at(indexToHighlighted));
+#ifndef QT_NO_RUBBERBAND
+ hideRubberBand();
+#endif
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::emitWindowActivated(QMdiSubWindow *activeWindow)
+{
+ Q_Q(QMdiArea);
+ Q_ASSERT(activeWindow);
+ if (activeWindow == active)
+ return;
+ Q_ASSERT(activeWindow->d_func()->isActive);
+
+ if (!aboutToBecomeActive)
+ _q_deactivateAllWindows(activeWindow);
+ Q_ASSERT(aboutToBecomeActive);
+
+ // This is true only if 'DontMaximizeSubWindowOnActivation' is disabled
+ // and the previous active window was maximized.
+ if (showActiveWindowMaximized) {
+ if (!activeWindow->isMaximized())
+ activeWindow->showMaximized();
+ showActiveWindowMaximized = false;
+ }
+
+ // Put in front to update activation order.
+ const int indexToActiveWindow = childWindows.indexOf(activeWindow);
+ Q_ASSERT(indexToActiveWindow != -1);
+ const int index = indicesToActivatedChildren.indexOf(indexToActiveWindow);
+ Q_ASSERT(index != -1);
+ indicesToActivatedChildren.move(index, 0);
+ internalRaise(activeWindow);
+
+ if (updatesDisabledByUs) {
+ q->setUpdatesEnabled(true);
+ updatesDisabledByUs = false;
+ }
+
+ Q_ASSERT(aboutToBecomeActive == activeWindow);
+ active = activeWindow;
+ aboutToBecomeActive = 0;
+ Q_ASSERT(active->d_func()->isActive);
+
+#ifndef QT_NO_TABBAR
+ if (tabBar && tabBar->currentIndex() != indexToActiveWindow)
+ tabBar->setCurrentIndex(indexToActiveWindow);
+#endif
+
+ if (active->isMaximized() && scrollBarsEnabled())
+ updateScrollBars();
+
+ emit q->subWindowActivated(active);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::resetActiveWindow(QMdiSubWindow *deactivatedWindow)
+{
+ Q_Q(QMdiArea);
+ if (deactivatedWindow) {
+ if (deactivatedWindow != active)
+ return;
+ active = 0;
+ if ((aboutToBecomeActive || isActivated || lastWindowAboutToBeDestroyed())
+ && !isExplicitlyDeactivated(deactivatedWindow) && !q->window()->isMinimized()) {
+ return;
+ }
+ emit q->subWindowActivated(0);
+ return;
+ }
+
+ if (aboutToBecomeActive)
+ return;
+
+ active = 0;
+ emit q->subWindowActivated(0);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::updateActiveWindow(int removedIndex, bool activeRemoved)
+{
+ Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
+
+#ifndef QT_NO_TABBAR
+ if (tabBar && removedIndex >= 0) {
+ tabBar->blockSignals(true);
+ tabBar->removeTab(removedIndex);
+ updateTabBarGeometry();
+ tabBar->blockSignals(false);
+ }
+#endif
+
+ if (childWindows.isEmpty()) {
+ showActiveWindowMaximized = false;
+ resetActiveWindow();
+ return;
+ }
+
+ if (indexToHighlighted >= 0) {
+#ifndef QT_NO_RUBBERBAND
+ // Hide rubber band if highlighted window is removed.
+ if (indexToHighlighted == removedIndex)
+ hideRubberBand();
+ else
+#endif
+ // or update index if necessary.
+ if (indexToHighlighted > removedIndex)
+ --indexToHighlighted;
+ }
+
+ // Update indices list
+ for (int i = 0; i < indicesToActivatedChildren.size(); ++i) {
+ int *index = &indicesToActivatedChildren[i];
+ if (*index > removedIndex)
+ --*index;
+ }
+
+ if (!activeRemoved)
+ return;
+
+ // Activate next window.
+ QMdiSubWindow *next = nextVisibleSubWindow(0, activationOrder, removedIndex);
+ if (next)
+ activateWindow(next);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::updateScrollBars()
+{
+ if (ignoreGeometryChange || !scrollBarsEnabled())
+ return;
+
+ Q_Q(QMdiArea);
+ QSize maxSize = q->maximumViewportSize();
+ QSize hbarExtent = hbar->sizeHint();
+ QSize vbarExtent = vbar->sizeHint();
+
+ if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {
+ const int doubleFrameWidth = frameWidth * 2;
+ if (hbarpolicy == Qt::ScrollBarAlwaysOn)
+ maxSize.rheight() -= doubleFrameWidth;
+ if (vbarpolicy == Qt::ScrollBarAlwaysOn)
+ maxSize.rwidth() -= doubleFrameWidth;
+ hbarExtent.rheight() += doubleFrameWidth;
+ vbarExtent.rwidth() += doubleFrameWidth;
+ }
+
+ const QRect childrenRect = active && active->isMaximized()
+ ? active->geometry() : viewport->childrenRect();
+ bool useHorizontalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Horizontal);
+ bool useVerticalScrollBar = useScrollBar(childrenRect, maxSize, Qt::Vertical);
+
+ if (useHorizontalScrollBar && !useVerticalScrollBar) {
+ const QSize max = maxSize - QSize(0, hbarExtent.height());
+ useVerticalScrollBar = useScrollBar(childrenRect, max, Qt::Vertical);
+ }
+
+ if (useVerticalScrollBar && !useHorizontalScrollBar) {
+ const QSize max = maxSize - QSize(vbarExtent.width(), 0);
+ useHorizontalScrollBar = useScrollBar(childrenRect, max, Qt::Horizontal);
+ }
+
+ if (useHorizontalScrollBar && hbarpolicy != Qt::ScrollBarAlwaysOn)
+ maxSize.rheight() -= hbarExtent.height();
+ if (useVerticalScrollBar && vbarpolicy != Qt::ScrollBarAlwaysOn)
+ maxSize.rwidth() -= vbarExtent.width();
+
+ QRect viewportRect(QPoint(0, 0), maxSize);
+ const int startX = q->isLeftToRight() ? childrenRect.left() : viewportRect.right()
+ - childrenRect.right();
+
+ // Horizontal scroll bar.
+ if (isSubWindowsTiled && hbar->value() != 0)
+ hbar->setValue(0);
+ const int xOffset = startX + hbar->value();
+ hbar->setRange(qMin(0, xOffset),
+ qMax(0, xOffset + childrenRect.width() - viewportRect.width()));
+ hbar->setPageStep(childrenRect.width());
+ hbar->setSingleStep(childrenRect.width() / 20);
+
+ // Vertical scroll bar.
+ if (isSubWindowsTiled && vbar->value() != 0)
+ vbar->setValue(0);
+ const int yOffset = childrenRect.top() + vbar->value();
+ vbar->setRange(qMin(0, yOffset),
+ qMax(0, yOffset + childrenRect.height() - viewportRect.height()));
+ vbar->setPageStep(childrenRect.height());
+ vbar->setSingleStep(childrenRect.height() / 20);
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::internalRaise(QMdiSubWindow *mdiChild) const
+{
+ if (!sanityCheck(mdiChild, "QMdiArea::internalRaise") || childWindows.size() < 2)
+ return;
+
+ QMdiSubWindow *stackUnderChild = 0;
+ if (!windowStaysOnTop(mdiChild)) {
+ foreach (QObject *object, viewport->children()) {
+ QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
+ if (!child || !childWindows.contains(child))
+ continue;
+ if (!child->isHidden() && windowStaysOnTop(child)) {
+ if (stackUnderChild)
+ child->stackUnder(stackUnderChild);
+ else
+ child->raise();
+ stackUnderChild = child;
+ }
+ }
+ }
+
+ if (stackUnderChild)
+ mdiChild->stackUnder(stackUnderChild);
+ else
+ mdiChild->raise();
+}
+
+QRect QMdiAreaPrivate::resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount)
+{
+ Q_Q(QMdiArea);
+ if (!minSubWindowSize.isValid() || subWindowCount <= 0)
+ return viewport->rect();
+
+ // Calculate minimum size.
+ const int columns = qMax(qCeil(qSqrt(qreal(subWindowCount))), 1);
+ const int rows = qMax((subWindowCount % columns) ? (subWindowCount / columns + 1)
+ : (subWindowCount / columns), 1);
+ const int minWidth = minSubWindowSize.width() * columns;
+ const int minHeight = minSubWindowSize.height() * rows;
+
+ // Increase area size if necessary. Scroll bars are provided if we're not able
+ // to resize to the minimum size.
+ if (!tileCalledFromResizeEvent) {
+ QWidget *topLevel = q;
+ // Find the topLevel for this area, either a real top-level or a sub-window.
+ while (topLevel && !topLevel->isWindow() && topLevel->windowType() != Qt::SubWindow)
+ topLevel = topLevel->parentWidget();
+ // We don't want sub-subwindows to be placed at the edge, thus add 2 pixels.
+ int minAreaWidth = minWidth + left + right + 2;
+ int minAreaHeight = minHeight + top + bottom + 2;
+ if (hbar->isVisible())
+ minAreaHeight += hbar->height();
+ if (vbar->isVisible())
+ minAreaWidth += vbar->width();
+ if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, q)) {
+ const int frame = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, q);
+ minAreaWidth += 2 * frame;
+ minAreaHeight += 2 * frame;
+ }
+ const QSize diff = QSize(minAreaWidth, minAreaHeight).expandedTo(q->size()) - q->size();
+ topLevel->resize(topLevel->size() + diff);
+ }
+
+ QRect domain = viewport->rect();
+
+ // Adjust domain width and provide horizontal scroll bar.
+ if (domain.width() < minWidth) {
+ domain.setWidth(minWidth);
+ if (hbarpolicy == Qt::ScrollBarAlwaysOff)
+ q->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ else
+ hbar->setValue(0);
+ }
+ // Adjust domain height and provide vertical scroll bar.
+ if (domain.height() < minHeight) {
+ domain.setHeight(minHeight);
+ if (vbarpolicy == Qt::ScrollBarAlwaysOff)
+ q->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ else
+ vbar->setValue(0);
+ }
+ return domain;
+}
+
+/*!
+ \internal
+*/
+bool QMdiAreaPrivate::scrollBarsEnabled() const
+{
+ return hbarpolicy != Qt::ScrollBarAlwaysOff || vbarpolicy != Qt::ScrollBarAlwaysOff;
+}
+
+/*!
+ \internal
+*/
+bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
+{
+ if (childWindows.count() != 1)
+ return false;
+
+ QMdiSubWindow *last = childWindows.at(0);
+ if (!last)
+ return true;
+
+ if (!last->testAttribute(Qt::WA_DeleteOnClose))
+ return false;
+
+ return last->d_func()->data.is_closing;
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
+{
+ foreach (QMdiSubWindow *subWindow, childWindows) {
+ if (!subWindow || !subWindow->isVisible())
+ continue;
+ if (onlyNextActivationEvent)
+ subWindow->d_func()->ignoreNextActivationEvent = !enable;
+ else
+ subWindow->d_func()->activationEnabled = enable;
+ }
+}
+
+/*!
+ \internal
+ \reimp
+*/
+void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
+{
+ if (childWindows.isEmpty())
+ return;
+
+ const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
+ QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
+ const bool enable = policy != Qt::ScrollBarAlwaysOff;
+ foreach (QMdiSubWindow *child, childWindows) {
+ if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
+ continue;
+ child->setOption(option, enable);
+ }
+ updateScrollBars();
+}
+
+QList<QMdiSubWindow*>
+QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
+{
+ QList<QMdiSubWindow *> list;
+ if (childWindows.isEmpty())
+ return list;
+
+ if (order == QMdiArea::CreationOrder) {
+ foreach (QMdiSubWindow *child, childWindows) {
+ if (!child)
+ continue;
+ if (!reversed)
+ list.append(child);
+ else
+ list.prepend(child);
+ }
+ } else if (order == QMdiArea::StackingOrder) {
+ foreach (QObject *object, viewport->children()) {
+ QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(object);
+ if (!child || !childWindows.contains(child))
+ continue;
+ if (!reversed)
+ list.append(child);
+ else
+ list.prepend(child);
+ }
+ } else { // ActivationHistoryOrder
+ Q_ASSERT(indicesToActivatedChildren.size() == childWindows.size());
+ for (int i = indicesToActivatedChildren.count() - 1; i >= 0; --i) {
+ QMdiSubWindow *child = childWindows.at(indicesToActivatedChildren.at(i));
+ if (!child)
+ continue;
+ if (!reversed)
+ list.append(child);
+ else
+ list.prepend(child);
+ }
+ }
+ return list;
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::disconnectSubWindow(QObject *subWindow)
+{
+ if (!subWindow)
+ return;
+
+ Q_Q(QMdiArea);
+ QObject::disconnect(subWindow, 0, q, 0);
+ subWindow->removeEventFilter(q);
+}
+
+/*!
+ \internal
+*/
+QMdiSubWindow *QMdiAreaPrivate::nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder order,
+ int removedIndex, int fromIndex) const
+{
+ if (childWindows.isEmpty())
+ return 0;
+
+ Q_Q(const QMdiArea);
+ const QList<QMdiSubWindow *> subWindows = q->subWindowList(order);
+ QMdiSubWindow *current = 0;
+
+ if (removedIndex < 0) {
+ if (fromIndex >= 0 && fromIndex < subWindows.size())
+ current = childWindows.at(fromIndex);
+ else
+ current = q->currentSubWindow();
+ }
+
+ // There's no current sub-window (removed or deactivated),
+ // so we have to pick the last active or the next in creation order.
+ if (!current) {
+ if (removedIndex >= 0 && order == QMdiArea::CreationOrder) {
+ int candidateIndex = -1;
+ setIndex(&candidateIndex, removedIndex, 0, subWindows.size() - 1, true);
+ current = childWindows.at(candidateIndex);
+ } else {
+ current = subWindows.back();
+ }
+ }
+ Q_ASSERT(current);
+
+ // Find the index for the current sub-window in the given activation order
+ const int indexToCurrent = subWindows.indexOf(current);
+ const bool increasing = increaseFactor > 0 ? true : false;
+
+ // and use that index + increseFactor as a candidate.
+ int index = -1;
+ setIndex(&index, indexToCurrent + increaseFactor, 0, subWindows.size() - 1, increasing);
+ Q_ASSERT(index != -1);
+
+ // Try to find another window if the candidate is hidden.
+ while (subWindows.at(index)->isHidden()) {
+ setIndex(&index, index + increaseFactor, 0, subWindows.size() - 1, increasing);
+ if (index == indexToCurrent)
+ break;
+ }
+
+ if (!subWindows.at(index)->isHidden())
+ return subWindows.at(index);
+ return 0;
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor)
+{
+ if (childWindows.size() == 1)
+ return;
+
+ Q_Q(QMdiArea);
+ // There's no highlighted sub-window atm, use current.
+ if (indexToHighlighted < 0) {
+ QMdiSubWindow *current = q->currentSubWindow();
+ if (!current)
+ return;
+ indexToHighlighted = childWindows.indexOf(current);
+ }
+
+ Q_ASSERT(indexToHighlighted >= 0);
+ Q_ASSERT(indexToHighlighted < childWindows.size());
+
+ QMdiSubWindow *highlight = nextVisibleSubWindow(increaseFactor, activationOrder, -1, indexToHighlighted);
+ if (!highlight)
+ return;
+
+#ifndef QT_NO_RUBBERBAND
+ if (!rubberBand) {
+ rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport);
+ // For accessibility to identify this special widget.
+ rubberBand->setObjectName(QLatin1String("qt_rubberband"));
+ rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint);
+ }
+#endif
+
+ // Only highlight if we're not switching back to the previously active window (Ctrl-Tab once).
+#ifndef QT_NO_RUBBERBAND
+ if (tabToPreviousTimerId == -1)
+ showRubberBandFor(highlight);
+#endif
+
+ indexToHighlighted = childWindows.indexOf(highlight);
+ Q_ASSERT(indexToHighlighted >= 0);
+}
+
+/*!
+ \internal
+ \since 4.4
+*/
+void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
+{
+ Q_Q(QMdiArea);
+ if (viewMode == mode || inViewModeChange)
+ return;
+
+ // Just a guard since we cannot set viewMode = mode here.
+ inViewModeChange = true;
+
+#ifndef QT_NO_TABBAR
+ if (mode == QMdiArea::TabbedView) {
+ Q_ASSERT(!tabBar);
+ tabBar = new QMdiAreaTabBar(q);
+ tabBar->setDocumentMode(documentMode);
+ tabBar->setTabsClosable(tabsClosable);
+ tabBar->setMovable(tabsMovable);
+#ifndef QT_NO_TABWIDGET
+ tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+#endif
+
+ isSubWindowsTiled = false;
+
+ foreach (QMdiSubWindow *subWindow, childWindows)
+ tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
+
+ QMdiSubWindow *current = q->currentSubWindow();
+ if (current) {
+ tabBar->setCurrentIndex(childWindows.indexOf(current));
+ // Restore sub-window (i.e. cleanup buttons in menu bar and window title).
+ if (current->isMaximized())
+ current->showNormal();
+
+ viewMode = mode;
+
+ // Now, maximize it.
+ if (!q->testOption(QMdiArea::DontMaximizeSubWindowOnActivation)) {
+ current->showMaximized();
+ }
+ } else {
+ viewMode = mode;
+ }
+
+ if (q->isVisible())
+ tabBar->show();
+ updateTabBarGeometry();
+
+ QObject::connect(tabBar, SIGNAL(currentChanged(int)), q, SLOT(_q_currentTabChanged(int)));
+ QObject::connect(tabBar, SIGNAL(tabCloseRequested(int)), q, SLOT(_q_closeTab(int)));
+ QObject::connect(tabBar, SIGNAL(tabMoved(int,int)), q, SLOT(_q_moveTab(int,int)));
+ } else
+#endif // QT_NO_TABBAR
+ { // SubWindowView
+#ifndef QT_NO_TABBAR
+ delete tabBar;
+ tabBar = 0;
+#endif // QT_NO_TABBAR
+
+ viewMode = mode;
+ q->setViewportMargins(0, 0, 0, 0);
+ indexToLastActiveTab = -1;
+
+ QMdiSubWindow *current = q->currentSubWindow();
+ if (current && current->isMaximized())
+ current->showNormal();
+ }
+
+ Q_ASSERT(viewMode == mode);
+ inViewModeChange = false;
+}
+
+#ifndef QT_NO_TABBAR
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::updateTabBarGeometry()
+{
+ if (!tabBar)
+ return;
+
+ Q_Q(QMdiArea);
+#ifndef QT_NO_TABWIDGET
+ Q_ASSERT(tabBarShapeFrom(tabShape, tabPosition) == tabBar->shape());
+#endif
+ const QSize tabBarSizeHint = tabBar->sizeHint();
+
+ int areaHeight = q->height();
+ if (hbar && hbar->isVisible())
+ areaHeight -= hbar->height();
+
+ int areaWidth = q->width();
+ if (vbar && vbar->isVisible())
+ areaWidth -= vbar->width();
+
+ QRect tabBarRect;
+#ifndef QT_NO_TABWIDGET
+ switch (tabPosition) {
+ case QTabWidget::North:
+ q->setViewportMargins(0, tabBarSizeHint.height(), 0, 0);
+ tabBarRect = QRect(0, 0, areaWidth, tabBarSizeHint.height());
+ break;
+ case QTabWidget::South:
+ q->setViewportMargins(0, 0, 0, tabBarSizeHint.height());
+ tabBarRect = QRect(0, areaHeight - tabBarSizeHint.height(), areaWidth, tabBarSizeHint.height());
+ break;
+ case QTabWidget::East:
+ if (q->layoutDirection() == Qt::LeftToRight)
+ q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
+ else
+ q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
+ tabBarRect = QRect(areaWidth - tabBarSizeHint.width(), 0, tabBarSizeHint.width(), areaHeight);
+ break;
+ case QTabWidget::West:
+ if (q->layoutDirection() == Qt::LeftToRight)
+ q->setViewportMargins(tabBarSizeHint.width(), 0, 0, 0);
+ else
+ q->setViewportMargins(0, 0, tabBarSizeHint.width(), 0);
+ tabBarRect = QRect(0, 0, tabBarSizeHint.width(), areaHeight);
+ break;
+ default:
+ break;
+ }
+#endif // QT_NO_TABWIDGET
+
+ tabBar->setGeometry(QStyle::visualRect(q->layoutDirection(), q->contentsRect(), tabBarRect));
+}
+
+/*!
+ \internal
+*/
+void QMdiAreaPrivate::refreshTabBar()
+{
+ if (!tabBar)
+ return;
+
+ tabBar->setDocumentMode(documentMode);
+ tabBar->setTabsClosable(tabsClosable);
+ tabBar->setMovable(tabsMovable);
+#ifndef QT_NO_TABWIDGET
+ tabBar->setShape(tabBarShapeFrom(tabShape, tabPosition));
+#endif
+ updateTabBarGeometry();
+}
+#endif // QT_NO_TABBAR
+
+/*!
+ Constructs an empty mdi area. \a parent is passed to QWidget's
+ constructor.
+*/
+QMdiArea::QMdiArea(QWidget *parent)
+ : QAbstractScrollArea(*new QMdiAreaPrivate, parent)
+{
+ setBackground(palette().brush(QPalette::Dark));
+ setFrameStyle(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setViewport(0);
+ setFocusPolicy(Qt::NoFocus);
+ QApplication::instance()->installEventFilter(this);
+}
+
+/*!
+ Destroys the MDI area.
+*/
+QMdiArea::~QMdiArea()
+{
+ Q_D(QMdiArea);
+ delete d->cascader;
+ d->cascader = 0;
+
+ delete d->regularTiler;
+ d->regularTiler = 0;
+
+ delete d->iconTiler;
+ d->iconTiler = 0;
+
+ delete d->placer;
+ d->placer = 0;
+}
+
+/*!
+ \reimp
+*/
+QSize QMdiArea::sizeHint() const
+{
+ // Calculate a proper scale factor for QDesktopWidget::size().
+ // This also takes into account that we can have nested workspaces.
+ int nestedCount = 0;
+ QWidget *widget = this->parentWidget();
+ while (widget) {
+ if (qobject_cast<QMdiArea *>(widget))
+ ++nestedCount;
+ widget = widget->parentWidget();
+ }
+ const int scaleFactor = 3 * (nestedCount + 1);
+
+ QSize desktopSize = QApplication::desktop()->size();
+ QSize size(desktopSize.width() * 2 / scaleFactor, desktopSize.height() * 2 / scaleFactor);
+ foreach (QMdiSubWindow *child, d_func()->childWindows) {
+ if (!sanityCheck(child, "QMdiArea::sizeHint"))
+ continue;
+ size = size.expandedTo(child->sizeHint());
+ }
+ return size.expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+QSize QMdiArea::minimumSizeHint() const
+{
+ Q_D(const QMdiArea);
+ QSize size(style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this),
+ style()->pixelMetric(QStyle::PM_TitleBarHeight, 0, this));
+ size = size.expandedTo(QAbstractScrollArea::minimumSizeHint());
+ if (!d->scrollBarsEnabled()) {
+ foreach (QMdiSubWindow *child, d->childWindows) {
+ if (!sanityCheck(child, "QMdiArea::sizeHint"))
+ continue;
+ size = size.expandedTo(child->minimumSizeHint());
+ }
+ }
+ return size.expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ Returns a pointer to the current subwindow, or 0 if there is
+ no current subwindow.
+
+ This function will return the same as activeSubWindow() if
+ the QApplication containing QMdiArea is active.
+
+ \sa activeSubWindow(), QApplication::activeWindow()
+*/
+QMdiSubWindow *QMdiArea::currentSubWindow() const
+{
+ Q_D(const QMdiArea);
+ if (d->childWindows.isEmpty())
+ return 0;
+
+ if (d->active)
+ return d->active;
+
+ if (d->isActivated && !window()->isMinimized())
+ return 0;
+
+ Q_ASSERT(d->indicesToActivatedChildren.count() > 0);
+ int index = d->indicesToActivatedChildren.at(0);
+ Q_ASSERT(index >= 0 && index < d->childWindows.size());
+ QMdiSubWindow *current = d->childWindows.at(index);
+ Q_ASSERT(current);
+ return current;
+}
+
+/*!
+ Returns a pointer to the current active subwindow. If no
+ window is currently active, 0 is returned.
+
+ Subwindows are treated as top-level windows with respect to
+ window state, i.e., if a widget outside the MDI area is the active
+ window, no subwindow will be active. Note that if a widget in the
+ window in which the MDI area lives gains focus, the window will be
+ activated.
+
+ \sa setActiveSubWindow(), Qt::WindowState
+*/
+QMdiSubWindow *QMdiArea::activeSubWindow() const
+{
+ Q_D(const QMdiArea);
+ return d->active;
+}
+
+/*!
+ Activates the subwindow \a window. If \a window is 0, any
+ current active window is deactivated.
+
+ \sa activeSubWindow()
+*/
+void QMdiArea::setActiveSubWindow(QMdiSubWindow *window)
+{
+ Q_D(QMdiArea);
+ if (!window) {
+ d->activateWindow(0);
+ return;
+ }
+
+ if (d->childWindows.isEmpty()) {
+ qWarning("QMdiArea::setActiveSubWindow: workspace is empty");
+ return;
+ }
+
+ if (d->childWindows.indexOf(window) == -1) {
+ qWarning("QMdiArea::setActiveSubWindow: window is not inside workspace");
+ return;
+ }
+
+ d->activateWindow(window);
+}
+
+/*!
+ Closes the active subwindow.
+
+ \sa closeAllSubWindows()
+*/
+void QMdiArea::closeActiveSubWindow()
+{
+ Q_D(QMdiArea);
+ if (d->active)
+ d->active->close();
+}
+
+/*!
+ Returns a list of all subwindows in the MDI area. If \a order is
+ CreationOrder (the default), the windows are sorted in the order
+ in which they were inserted into the workspace. If \a order is
+ StackingOrder, the windows are listed in their stacking order,
+ with the topmost window as the last item in the list. If \a order
+ is ActivationHistoryOrder, the windows are listed according to
+ their recent activation history.
+
+ \sa WindowOrder
+*/
+QList<QMdiSubWindow *> QMdiArea::subWindowList(WindowOrder order) const
+{
+ Q_D(const QMdiArea);
+ return d->subWindowList(order, false);
+}
+
+/*!
+ Closes all subwindows by sending a QCloseEvent to each window.
+ You may receive subWindowActivated() signals from subwindows
+ before they are closed (if the MDI area activates the subwindow
+ when another is closing).
+
+ Subwindows that ignore the close event will remain open.
+
+ \sa closeActiveSubWindow()
+*/
+void QMdiArea::closeAllSubWindows()
+{
+ Q_D(QMdiArea);
+ if (d->childWindows.isEmpty())
+ return;
+
+ d->isSubWindowsTiled = false;
+ foreach (QMdiSubWindow *child, d->childWindows) {
+ if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
+ continue;
+ child->close();
+ }
+
+ d->updateScrollBars();
+}
+
+/*!
+ Gives the keyboard focus to another window in the list of child
+ windows. The window activated will be the next one determined
+ by the current \l{QMdiArea::WindowOrder} {activation order}.
+
+ \sa activatePreviousSubWindow(), QMdiArea::WindowOrder
+*/
+void QMdiArea::activateNextSubWindow()
+{
+ Q_D(QMdiArea);
+ if (d->childWindows.isEmpty())
+ return;
+
+ QMdiSubWindow *next = d->nextVisibleSubWindow(1, d->activationOrder);
+ if (next)
+ d->activateWindow(next);
+}
+
+/*!
+ Gives the keyboard focus to another window in the list of child
+ windows. The window activated will be the previous one determined
+ by the current \l{QMdiArea::WindowOrder} {activation order}.
+
+ \sa activateNextSubWindow(), QMdiArea::WindowOrder
+*/
+void QMdiArea::activatePreviousSubWindow()
+{
+ Q_D(QMdiArea);
+ if (d->childWindows.isEmpty())
+ return;
+
+ QMdiSubWindow *previous = d->nextVisibleSubWindow(-1, d->activationOrder);
+ if (previous)
+ d->activateWindow(previous);
+}
+
+/*!
+ Adds \a widget as a new subwindow to the MDI area. If \a
+ windowFlags are non-zero, they will override the flags set on the
+ widget.
+
+ The \a widget can be either a QMdiSubWindow or another QWidget
+ (in which case the MDI area will create a subwindow and set the \a
+ widget as the internal widget).
+
+ \note Once the subwindow has been added, its parent will be the
+ \e{viewport widget} of the QMdiArea.
+
+ \snippet doc/src/snippets/mdiareasnippets.cpp 1
+
+ When you create your own subwindow, you must set the
+ Qt::WA_DeleteOnClose widget attribute if you want the window to be
+ deleted when closed in the MDI area. If not, the window will be
+ hidden and the MDI area will not activate the next subwindow.
+
+ Returns the QMdiSubWindow that is added to the MDI area.
+
+ \sa removeSubWindow()
+*/
+QMdiSubWindow *QMdiArea::addSubWindow(QWidget *widget, Qt::WindowFlags windowFlags)
+{
+ if (!widget) {
+ qWarning("QMdiArea::addSubWindow: null pointer to widget");
+ return 0;
+ }
+
+ Q_D(QMdiArea);
+ // QWidget::setParent clears focusWidget so store it
+ QWidget *childFocus = widget->focusWidget();
+ QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget);
+
+ // Widget is already a QMdiSubWindow
+ if (child) {
+ if (d->childWindows.indexOf(child) != -1) {
+ qWarning("QMdiArea::addSubWindow: window is already added");
+ return child;
+ }
+ child->setParent(viewport(), windowFlags ? windowFlags : child->windowFlags());
+ // Create a QMdiSubWindow
+ } else {
+ child = new QMdiSubWindow(viewport(), windowFlags);
+ child->setAttribute(Qt::WA_DeleteOnClose);
+ child->setWidget(widget);
+ Q_ASSERT(child->testAttribute(Qt::WA_DeleteOnClose));
+ }
+
+ if (childFocus)
+ childFocus->setFocus();
+ d->appendChild(child);
+ return child;
+}
+
+/*!
+ Removes \a widget from the MDI area. The \a widget must be
+ either a QMdiSubWindow or a widget that is the internal widget of
+ a subwindow. Note \a widget is never actually deleted by QMdiArea.
+ If a QMdiSubWindow is passed in its parent is set to 0 and it is
+ removed, but if an internal widget is passed in the child widget
+ is set to 0 but the QMdiSubWindow is not removed.
+
+ \sa addSubWindow()
+*/
+void QMdiArea::removeSubWindow(QWidget *widget)
+{
+ if (!widget) {
+ qWarning("QMdiArea::removeSubWindow: null pointer to widget");
+ return;
+ }
+
+ Q_D(QMdiArea);
+ if (d->childWindows.isEmpty())
+ return;
+
+ if (QMdiSubWindow *child = qobject_cast<QMdiSubWindow *>(widget)) {
+ int index = d->childWindows.indexOf(child);
+ if (index == -1) {
+ qWarning("QMdiArea::removeSubWindow: window is not inside workspace");
+ return;
+ }
+ d->disconnectSubWindow(child);
+ d->childWindows.removeAll(child);
+ d->indicesToActivatedChildren.removeAll(index);
+ d->updateActiveWindow(index, d->active == child);
+ child->setParent(0);
+ return;
+ }
+
+ bool found = false;
+ foreach (QMdiSubWindow *child, d->childWindows) {
+ if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
+ continue;
+ if (child->widget() == widget) {
+ child->setWidget(0);
+ Q_ASSERT(!child->widget());
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ qWarning("QMdiArea::removeSubWindow: widget is not child of any window inside QMdiArea");
+}
+
+/*!
+ \property QMdiArea::background
+ \brief the background brush for the workspace
+
+ This property sets the background brush for the workspace area
+ itself. By default, it is a gray color, but can be any brush
+ (e.g., colors, gradients or pixmaps).
+*/
+QBrush QMdiArea::background() const
+{
+ return d_func()->background;
+}
+
+void QMdiArea::setBackground(const QBrush &brush)
+{
+ Q_D(QMdiArea);
+ if (d->background != brush) {
+ d->background = brush;
+ d->viewport->setAttribute(Qt::WA_OpaquePaintEvent, brush.isOpaque());
+ update();
+ }
+}
+
+
+/*!
+ \property QMdiArea::activationOrder
+ \brief the ordering criteria for subwindow lists
+ \since 4.4
+
+ This property specifies the ordering criteria for the list of
+ subwindows returned by subWindowList(). By default, it is the window
+ creation order.
+
+ \sa subWindowList()
+*/
+QMdiArea::WindowOrder QMdiArea::activationOrder() const
+{
+ Q_D(const QMdiArea);
+ return d->activationOrder;
+}
+
+void QMdiArea::setActivationOrder(WindowOrder order)
+{
+ Q_D(QMdiArea);
+ if (order != d->activationOrder)
+ d->activationOrder = order;
+}
+
+/*!
+ If \a on is true, \a option is enabled on the MDI area; otherwise
+ it is disabled. See AreaOption for the effect of each option.
+
+ \sa AreaOption, testOption()
+*/
+void QMdiArea::setOption(AreaOption option, bool on)
+{
+ Q_D(QMdiArea);
+ if (on && !(d->options & option))
+ d->options |= option;
+ else if (!on && (d->options & option))
+ d->options &= ~option;
+}
+
+/*!
+ Returns true if \a option is enabled; otherwise returns false.
+
+ \sa AreaOption, setOption()
+*/
+bool QMdiArea::testOption(AreaOption option) const
+{
+ return d_func()->options & option;
+}
+
+/*!
+ \property QMdiArea::viewMode
+ \brief the way sub-windows are displayed in the QMdiArea.
+ \since 4.4
+
+ By default, the SubWindowView is used to display sub-windows.
+
+ \sa ViewMode, setTabShape(), setTabPosition()
+*/
+QMdiArea::ViewMode QMdiArea::viewMode() const
+{
+ Q_D(const QMdiArea);
+ return d->viewMode;
+}
+
+void QMdiArea::setViewMode(ViewMode mode)
+{
+ Q_D(QMdiArea);
+ d->setViewMode(mode);
+}
+
+#ifndef QT_NO_TABBAR
+/*!
+ \property QMdiArea::documentMode
+ \brief whether the tab bar is set to document mode in tabbed view mode.
+ \since 4.5
+
+ Document mode is disabled by default.
+
+ \sa QTabBar::documentMode, setViewMode()
+*/
+bool QMdiArea::documentMode() const
+{
+ Q_D(const QMdiArea);
+ return d->documentMode;
+}
+
+void QMdiArea::setDocumentMode(bool enabled)
+{
+ Q_D(QMdiArea);
+ if (d->documentMode == enabled)
+ return;
+
+ d->documentMode = enabled;
+ d->refreshTabBar();
+}
+
+/*!
+ \property QMdiArea::tabsClosable
+ \brief whether the tab bar should place close buttons on each tab in tabbed view mode.
+ \since 4.8
+
+ Tabs are not closable by default.
+
+ \sa QTabBar::tabsClosable, setViewMode()
+*/
+bool QMdiArea::tabsClosable() const
+{
+ Q_D(const QMdiArea);
+ return d->tabsClosable;
+}
+
+void QMdiArea::setTabsClosable(bool closable)
+{
+ Q_D(QMdiArea);
+ if (d->tabsClosable == closable)
+ return;
+
+ d->tabsClosable = closable;
+ d->refreshTabBar();
+}
+
+/*!
+ \property QMdiArea::tabsMovable
+ \brief whether the user can move the tabs within the tabbar area in tabbed view mode.
+ \since 4.8
+
+ Tabs are not movable by default.
+
+ \sa QTabBar::movable, setViewMode()
+*/
+bool QMdiArea::tabsMovable() const
+{
+ Q_D(const QMdiArea);
+ return d->tabsMovable;
+}
+
+void QMdiArea::setTabsMovable(bool movable)
+{
+ Q_D(QMdiArea);
+ if (d->tabsMovable == movable)
+ return;
+
+ d->tabsMovable = movable;
+ d->refreshTabBar();
+}
+#endif // QT_NO_TABBAR
+
+#ifndef QT_NO_TABWIDGET
+/*!
+ \property QMdiArea::tabShape
+ \brief the shape of the tabs in tabbed view mode.
+ \since 4.4
+
+ Possible values for this property are QTabWidget::Rounded
+ (default) or QTabWidget::Triangular.
+
+ \sa QTabWidget::TabShape, setViewMode()
+*/
+QTabWidget::TabShape QMdiArea::tabShape() const
+{
+ Q_D(const QMdiArea);
+ return d->tabShape;
+}
+
+void QMdiArea::setTabShape(QTabWidget::TabShape shape)
+{
+ Q_D(QMdiArea);
+ if (d->tabShape == shape)
+ return;
+
+ d->tabShape = shape;
+ d->refreshTabBar();
+}
+
+/*!
+ \property QMdiArea::tabPosition
+ \brief the position of the tabs in tabbed view mode.
+ \since 4.4
+
+ Possible values for this property are described by the
+ QTabWidget::TabPosition enum.
+
+ \sa QTabWidget::TabPosition, setViewMode()
+*/
+QTabWidget::TabPosition QMdiArea::tabPosition() const
+{
+ Q_D(const QMdiArea);
+ return d->tabPosition;
+}
+
+void QMdiArea::setTabPosition(QTabWidget::TabPosition position)
+{
+ Q_D(QMdiArea);
+ if (d->tabPosition == position)
+ return;
+
+ d->tabPosition = position;
+ d->refreshTabBar();
+}
+#endif // QT_NO_TABWIDGET
+
+/*!
+ \reimp
+*/
+void QMdiArea::childEvent(QChildEvent *childEvent)
+{
+ Q_D(QMdiArea);
+ if (childEvent->type() == QEvent::ChildPolished) {
+ if (QMdiSubWindow *mdiChild = qobject_cast<QMdiSubWindow *>(childEvent->child())) {
+ if (d->childWindows.indexOf(mdiChild) == -1)
+ d->appendChild(mdiChild);
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
+{
+ Q_D(QMdiArea);
+ if (d->childWindows.isEmpty()) {
+ resizeEvent->ignore();
+ return;
+ }
+
+#ifndef QT_NO_TABBAR
+ d->updateTabBarGeometry();
+#endif
+
+ // Re-tile the views if we're in tiled mode. Re-tile means we will change
+ // the geometry of the children, which in turn means 'isSubWindowsTiled'
+ // is set to false, so we have to update the state at the end.
+ if (d->isSubWindowsTiled) {
+ d->tileCalledFromResizeEvent = true;
+ tileSubWindows();
+ d->tileCalledFromResizeEvent = false;
+ d->isSubWindowsTiled = true;
+ d->startResizeTimer();
+ // We don't have scroll bars or any maximized views.
+ return;
+ }
+
+ // Resize maximized views.
+ bool hasMaximizedSubWindow = false;
+ foreach (QMdiSubWindow *child, d->childWindows) {
+ if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
+ && child->size() != resizeEvent->size()) {
+ child->resize(resizeEvent->size());
+ if (!hasMaximizedSubWindow)
+ hasMaximizedSubWindow = true;
+ }
+ }
+
+ d->updateScrollBars();
+
+ // Minimized views are stacked under maximized views so there's
+ // no need to re-arrange minimized views on-demand. Start a timer
+ // just to make things faster with subsequent resize events.
+ if (hasMaximizedSubWindow)
+ d->startResizeTimer();
+ else
+ d->arrangeMinimizedSubWindows();
+}
+
+/*!
+ \reimp
+*/
+void QMdiArea::timerEvent(QTimerEvent *timerEvent)
+{
+ Q_D(QMdiArea);
+ if (timerEvent->timerId() == d->resizeTimerId) {
+ killTimer(d->resizeTimerId);
+ d->resizeTimerId = -1;
+ d->arrangeMinimizedSubWindows();
+ } else if (timerEvent->timerId() == d->tabToPreviousTimerId) {
+ killTimer(d->tabToPreviousTimerId);
+ d->tabToPreviousTimerId = -1;
+ if (d->indexToHighlighted < 0)
+ return;
+#ifndef QT_NO_RUBBERBAND
+ // We're not doing a "quick switch" ... show rubber band.
+ Q_ASSERT(d->indexToHighlighted < d->childWindows.size());
+ Q_ASSERT(d->rubberBand);
+ d->showRubberBandFor(d->childWindows.at(d->indexToHighlighted));
+#endif
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMdiArea::showEvent(QShowEvent *showEvent)
+{
+ Q_D(QMdiArea);
+ if (!d->pendingRearrangements.isEmpty()) {
+ bool skipPlacement = false;
+ foreach (Rearranger *rearranger, d->pendingRearrangements) {
+ // If this is the case, we don't have to lay out pending child windows
+ // since the rearranger will find a placement for them.
+ if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
+ skipPlacement = true;
+ d->rearrange(rearranger);
+ }
+ d->pendingRearrangements.clear();
+
+ if (skipPlacement && !d->pendingPlacements.isEmpty())
+ d->pendingPlacements.clear();
+ }
+
+ if (!d->pendingPlacements.isEmpty()) {
+ foreach (QMdiSubWindow *window, d->pendingPlacements) {
+ if (!window)
+ continue;
+ if (!window->testAttribute(Qt::WA_Resized)) {
+ QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
+ window->resize(newSize.expandedTo(qSmartMinSize(window)));
+ }
+ if (!window->testAttribute(Qt::WA_Moved) && !window->isMinimized()
+ && !window->isMaximized()) {
+ d->place(d->placer, window);
+ }
+ }
+ d->pendingPlacements.clear();
+ }
+
+ d->setChildActivationEnabled(true);
+ d->activateCurrentWindow();
+
+ QAbstractScrollArea::showEvent(showEvent);
+}
+
+/*!
+ \reimp
+*/
+bool QMdiArea::viewportEvent(QEvent *event)
+{
+ Q_D(QMdiArea);
+ switch (event->type()) {
+ case QEvent::ChildRemoved: {
+ d->isSubWindowsTiled = false;
+ QObject *removedChild = static_cast<QChildEvent *>(event)->child();
+ for (int i = 0; i < d->childWindows.size(); ++i) {
+ QObject *child = d->childWindows.at(i);
+ if (!child || child == removedChild || !child->parent()
+ || child->parent() != viewport()) {
+ if (!testOption(DontMaximizeSubWindowOnActivation)) {
+ // In this case we can only rely on the child being a QObject
+ // (or 0), but let's try and see if we can get more information.
+ QWidget *mdiChild = qobject_cast<QWidget *>(removedChild);
+ if (mdiChild && mdiChild->isMaximized())
+ d->showActiveWindowMaximized = true;
+ }
+ d->disconnectSubWindow(child);
+ const bool activeRemoved = i == d->indicesToActivatedChildren.at(0);
+ d->childWindows.removeAt(i);
+ d->indicesToActivatedChildren.removeAll(i);
+ d->updateActiveWindow(i, activeRemoved);
+ d->arrangeMinimizedSubWindows();
+ break;
+ }
+ }
+ d->updateScrollBars();
+ break;
+ }
+ case QEvent::Destroy:
+ d->isSubWindowsTiled = false;
+ d->resetActiveWindow();
+ d->childWindows.clear();
+ qWarning("QMdiArea: Deleting the view port is undefined, use setViewport instead.");
+ break;
+ default:
+ break;
+ }
+ return QAbstractScrollArea::viewportEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QMdiArea::scrollContentsBy(int dx, int dy)
+{
+ Q_D(QMdiArea);
+ const bool wasSubWindowsTiled = d->isSubWindowsTiled;
+ d->ignoreGeometryChange = true;
+ viewport()->scroll(isLeftToRight() ? dx : -dx, dy);
+ d->arrangeMinimizedSubWindows();
+ d->ignoreGeometryChange = false;
+ if (wasSubWindowsTiled)
+ d->isSubWindowsTiled = true;
+}
+
+/*!
+ Arranges all child windows in a tile pattern.
+
+ \sa cascadeSubWindows()
+*/
+void QMdiArea::tileSubWindows()
+{
+ Q_D(QMdiArea);
+ if (!d->regularTiler)
+ d->regularTiler = new RegularTiler;
+ d->rearrange(d->regularTiler);
+}
+
+/*!
+ Arranges all the child windows in a cascade pattern.
+
+ \sa tileSubWindows()
+*/
+void QMdiArea::cascadeSubWindows()
+{
+ Q_D(QMdiArea);
+ if (!d->cascader)
+ d->cascader = new SimpleCascader;
+ d->rearrange(d->cascader);
+}
+
+/*!
+ \reimp
+*/
+bool QMdiArea::event(QEvent *event)
+{
+ Q_D(QMdiArea);
+ switch (event->type()) {
+#ifdef Q_WS_WIN
+ // QWidgetPrivate::hide_helper activates another sub-window when closing a
+ // modal dialog on Windows (see activateWindow() inside the the ifdef).
+ case QEvent::WindowUnblocked:
+ d->activateCurrentWindow();
+ break;
+#endif
+ case QEvent::WindowActivate: {
+ d->isActivated = true;
+ if (d->childWindows.isEmpty())
+ break;
+ if (!d->active)
+ d->activateCurrentWindow();
+ d->setChildActivationEnabled(false, true);
+ break;
+ }
+ case QEvent::WindowDeactivate:
+ d->isActivated = false;
+ d->setChildActivationEnabled(false, true);
+ break;
+ case QEvent::StyleChange:
+ // Re-tile the views if we're in tiled mode. Re-tile means we will change
+ // the geometry of the children, which in turn means 'isSubWindowsTiled'
+ // is set to false, so we have to update the state at the end.
+ if (d->isSubWindowsTiled) {
+ tileSubWindows();
+ d->isSubWindowsTiled = true;
+ }
+ break;
+ case QEvent::WindowIconChange:
+ foreach (QMdiSubWindow *window, d->childWindows) {
+ if (sanityCheck(window, "QMdiArea::WindowIconChange"))
+ QApplication::sendEvent(window, event);
+ }
+ break;
+ case QEvent::Hide:
+ d->setActive(d->active, false, false);
+ d->setChildActivationEnabled(false);
+ break;
+#ifndef QT_NO_TABBAR
+ case QEvent::LayoutDirectionChange:
+ d->updateTabBarGeometry();
+ break;
+#endif
+ default:
+ break;
+ }
+ return QAbstractScrollArea::event(event);
+}
+
+/*!
+ \reimp
+*/
+bool QMdiArea::eventFilter(QObject *object, QEvent *event)
+{
+ if (!object)
+ return QAbstractScrollArea::eventFilter(object, event);
+
+ Q_D(QMdiArea);
+ // Global key events with Ctrl modifier.
+ if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
+
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ // Ingore key events without a Ctrl modifier (except for press/release on the modifier itself).
+#ifdef Q_WS_MAC
+ if (!(keyEvent->modifiers() & Qt::MetaModifier) && keyEvent->key() != Qt::Key_Meta)
+#else
+ if (!(keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() != Qt::Key_Control)
+#endif
+ return QAbstractScrollArea::eventFilter(object, event);
+
+ // Find closest mdi area (in case we have a nested workspace).
+ QMdiArea *area = mdiAreaParent(static_cast<QWidget *>(object));
+ if (!area)
+ return QAbstractScrollArea::eventFilter(object, event);
+
+ const bool keyPress = (event->type() == QEvent::KeyPress) ? true : false;
+
+ // 1) Ctrl-Tab once -> activate the previously active window.
+ // 2) Ctrl-Tab (Tab, Tab, ...) -> iterate through all windows (activateNextSubWindow()).
+ // 3) Ctrl-Shift-Tab (Tab, Tab, ...) -> iterate through all windows in the opposite
+ // direction (activatePreviousSubWindow())
+ switch (keyEvent->key()) {
+#ifdef Q_WS_MAC
+ case Qt::Key_Meta:
+#else
+ case Qt::Key_Control:
+#endif
+ if (keyPress)
+ area->d_func()->startTabToPreviousTimer();
+ else
+ area->d_func()->activateHighlightedWindow();
+ break;
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ if (keyPress)
+ area->d_func()->highlightNextSubWindow(keyEvent->key() == Qt::Key_Tab ? 1 : -1);
+ return true;
+#ifndef QT_NO_RUBBERBAND
+ case Qt::Key_Escape:
+ area->d_func()->hideRubberBand();
+ break;
+#endif
+ default:
+ break;
+ }
+ return QAbstractScrollArea::eventFilter(object, event);
+ }
+
+ QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object);
+
+ if (!subWindow) {
+ // QApplication events:
+ if (event->type() == QEvent::ApplicationActivate && !d->active
+ && isVisible() && !window()->isMinimized()) {
+ d->activateCurrentWindow();
+ } else if (event->type() == QEvent::ApplicationDeactivate && d->active) {
+ d->setActive(d->active, false, false);
+ }
+ return QAbstractScrollArea::eventFilter(object, event);
+ }
+
+ // QMdiSubWindow events:
+ switch (event->type()) {
+ case QEvent::Move:
+ case QEvent::Resize:
+ if (d->tileCalledFromResizeEvent)
+ break;
+ d->updateScrollBars();
+ if (!subWindow->isMinimized())
+ d->isSubWindowsTiled = false;
+ break;
+ case QEvent::Show:
+#ifndef QT_NO_TABBAR
+ if (d->tabBar) {
+ const int tabIndex = d->childWindows.indexOf(subWindow);
+ if (!d->tabBar->isTabEnabled(tabIndex))
+ d->tabBar->setTabEnabled(tabIndex, true);
+ }
+#endif // QT_NO_TABBAR
+ // fall through
+ case QEvent::Hide:
+ d->isSubWindowsTiled = false;
+ break;
+#ifndef QT_NO_RUBBERBAND
+ case QEvent::Close:
+ if (d->childWindows.indexOf(subWindow) == d->indexToHighlighted)
+ d->hideRubberBand();
+ break;
+#endif
+#ifndef QT_NO_TABBAR
+ case QEvent::WindowTitleChange:
+ case QEvent::ModifiedChange:
+ if (d->tabBar)
+ d->tabBar->setTabText(d->childWindows.indexOf(subWindow), tabTextFor(subWindow));
+ break;
+ case QEvent::WindowIconChange:
+ if (d->tabBar)
+ d->tabBar->setTabIcon(d->childWindows.indexOf(subWindow), subWindow->windowIcon());
+ break;
+#endif // QT_NO_TABBAR
+ default:
+ break;
+ }
+ return QAbstractScrollArea::eventFilter(object, event);
+}
+
+/*!
+ \reimp
+*/
+void QMdiArea::paintEvent(QPaintEvent *paintEvent)
+{
+ Q_D(QMdiArea);
+ QPainter painter(d->viewport);
+ const QVector<QRect> &exposedRects = paintEvent->region().rects();
+ for (int i = 0; i < exposedRects.size(); ++i)
+ painter.fillRect(exposedRects.at(i), d->background);
+}
+
+/*!
+ This slot is called by QAbstractScrollArea after setViewport() has been
+ called. Reimplement this function in a subclass of QMdiArea to
+ initialize the new \a viewport before it is used.
+
+ \sa setViewport()
+*/
+void QMdiArea::setupViewport(QWidget *viewport)
+{
+ Q_D(QMdiArea);
+ if (viewport)
+ viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
+ foreach (QMdiSubWindow *child, d->childWindows) {
+ if (!sanityCheck(child, "QMdiArea::setupViewport"))
+ continue;
+ child->setParent(viewport, child->windowFlags());
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmdiarea.cpp"
+
+#endif // QT_NO_MDIAREA
diff --git a/src/widgets/widgets/qmdiarea.h b/src/widgets/widgets/qmdiarea.h
new file mode 100644
index 0000000000..f1ffb29e53
--- /dev/null
+++ b/src/widgets/widgets/qmdiarea.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMDIAREA_H
+#define QMDIAREA_H
+
+#include <QtWidgets/qabstractscrollarea.h>
+#include <QtWidgets/qtabwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MDIAREA
+
+class QMdiSubWindow;
+
+class QMdiAreaPrivate;
+class Q_WIDGETS_EXPORT QMdiArea : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_ENUMS(ViewMode)
+ Q_PROPERTY(QBrush background READ background WRITE setBackground)
+ Q_PROPERTY(WindowOrder activationOrder READ activationOrder WRITE setActivationOrder)
+ Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode)
+#ifndef QT_NO_TABBAR
+ Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
+ Q_PROPERTY(bool tabsClosable READ tabsClosable WRITE setTabsClosable)
+ Q_PROPERTY(bool tabsMovable READ tabsMovable WRITE setTabsMovable)
+#endif
+#ifndef QT_NO_TABWIDGET
+ Q_PROPERTY(QTabWidget::TabShape tabShape READ tabShape WRITE setTabShape)
+ Q_PROPERTY(QTabWidget::TabPosition tabPosition READ tabPosition WRITE setTabPosition)
+#endif
+ Q_ENUMS(WindowOrder)
+public:
+ enum AreaOption {
+ DontMaximizeSubWindowOnActivation = 0x1
+ };
+ Q_DECLARE_FLAGS(AreaOptions, AreaOption)
+
+ enum WindowOrder {
+ CreationOrder,
+ StackingOrder,
+ ActivationHistoryOrder
+ };
+
+ enum ViewMode {
+ SubWindowView,
+ TabbedView
+ };
+
+ QMdiArea(QWidget *parent = 0);
+ ~QMdiArea();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QMdiSubWindow *currentSubWindow() const;
+ QMdiSubWindow *activeSubWindow() const;
+ QList<QMdiSubWindow *> subWindowList(WindowOrder order = CreationOrder) const;
+
+ QMdiSubWindow *addSubWindow(QWidget *widget, Qt::WindowFlags flags = 0);
+ void removeSubWindow(QWidget *widget);
+
+ QBrush background() const;
+ void setBackground(const QBrush &background);
+
+ WindowOrder activationOrder() const;
+ void setActivationOrder(WindowOrder order);
+
+ void setOption(AreaOption option, bool on = true);
+ bool testOption(AreaOption opton) const;
+
+ void setViewMode(ViewMode mode);
+ ViewMode viewMode() const;
+
+#ifndef QT_NO_TABBAR
+ bool documentMode() const;
+ void setDocumentMode(bool enabled);
+
+ void setTabsClosable(bool closable);
+ bool tabsClosable() const;
+
+ void setTabsMovable(bool movable);
+ bool tabsMovable() const;
+#endif
+#ifndef QT_NO_TABWIDGET
+ void setTabShape(QTabWidget::TabShape shape);
+ QTabWidget::TabShape tabShape() const;
+
+ void setTabPosition(QTabWidget::TabPosition position);
+ QTabWidget::TabPosition tabPosition() const;
+#endif
+
+Q_SIGNALS:
+ void subWindowActivated(QMdiSubWindow *);
+
+public Q_SLOTS:
+ void setActiveSubWindow(QMdiSubWindow *window);
+ void tileSubWindows();
+ void cascadeSubWindows();
+ void closeActiveSubWindow();
+ void closeAllSubWindows();
+ void activateNextSubWindow();
+ void activatePreviousSubWindow();
+
+protected Q_SLOTS:
+ void setupViewport(QWidget *viewport);
+
+protected:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *object, QEvent *event);
+ void paintEvent(QPaintEvent *paintEvent);
+ void childEvent(QChildEvent *childEvent);
+ void resizeEvent(QResizeEvent *resizeEvent);
+ void timerEvent(QTimerEvent *timerEvent);
+ void showEvent(QShowEvent *showEvent);
+ bool viewportEvent(QEvent *event);
+ void scrollContentsBy(int dx, int dy);
+
+private:
+ Q_DISABLE_COPY(QMdiArea)
+ Q_DECLARE_PRIVATE(QMdiArea)
+ Q_PRIVATE_SLOT(d_func(), void _q_deactivateAllWindows())
+ Q_PRIVATE_SLOT(d_func(), void _q_processWindowStateChanged(Qt::WindowStates, Qt::WindowStates))
+ Q_PRIVATE_SLOT(d_func(), void _q_currentTabChanged(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_closeTab(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_moveTab(int, int))
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMdiArea::AreaOptions)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_MDIAREA
+#endif // QMDIAREA_H
diff --git a/src/widgets/widgets/qmdiarea_p.h b/src/widgets/widgets/qmdiarea_p.h
new file mode 100644
index 0000000000..18a022d7dd
--- /dev/null
+++ b/src/widgets/widgets/qmdiarea_p.h
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMDIAREA_P_H
+#define QMDIAREA_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 "qmdiarea.h"
+#include "qmdisubwindow.h"
+
+#ifndef QT_NO_MDIAREA
+
+#include <QList>
+#include <QRect>
+#include <QPoint>
+#include <QtWidgets/qapplication.h>
+#include <private/qmdisubwindow_p.h>
+#include <private/qabstractscrollarea_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QMdi {
+class Rearranger
+{
+public:
+ enum Type {
+ RegularTiler,
+ SimpleCascader,
+ IconTiler
+ };
+
+ // Rearranges widgets relative to domain.
+ virtual void rearrange(QList<QWidget *> &widgets, const QRect &domain) const = 0;
+ virtual Type type() const = 0;
+ virtual ~Rearranger() {}
+};
+
+class RegularTiler : public Rearranger
+{
+ // Rearranges widgets according to a regular tiling pattern
+ // covering the entire domain.
+ // Both positions and sizes may change.
+ void rearrange(QList<QWidget *> &widgets, const QRect &domain) const;
+ inline Type type() const { return Rearranger::RegularTiler; }
+};
+
+class SimpleCascader : public Rearranger
+{
+ // Rearranges widgets according to a simple, regular cascading pattern.
+ // Widgets are resized to minimumSize.
+ // Both positions and sizes may change.
+ void rearrange(QList<QWidget *> &widgets, const QRect &domain) const;
+ inline Type type() const { return Rearranger::SimpleCascader; }
+};
+
+class IconTiler : public Rearranger
+{
+ // Rearranges icons (assumed to be the same size) according to a regular
+ // tiling pattern filling up the domain from the bottom.
+ // Only positions may change.
+ void rearrange(QList<QWidget *> &widgets, const QRect &domain) const;
+ inline Type type() const { return Rearranger::IconTiler; }
+};
+
+class Placer
+{
+public:
+ // Places the rectangle defined by 'size' relative to 'rects' and 'domain'.
+ // Returns the position of the resulting rectangle.
+ virtual QPoint place(
+ const QSize &size, const QList<QRect> &rects, const QRect &domain) const = 0;
+ virtual ~Placer() {}
+};
+
+class MinOverlapPlacer : public Placer
+{
+ QPoint place(const QSize &size, const QList<QRect> &rects, const QRect &domain) const;
+ static int accumulatedOverlap(const QRect &source, const QList<QRect> &rects);
+ static QRect findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects);
+ static void getCandidatePlacements(
+ const QSize &size, const QList<QRect> &rects, const QRect &domain,
+ QList<QRect> &candidates);
+ static QPoint findBestPlacement(
+ const QRect &domain, const QList<QRect> &rects, QList<QRect> &source);
+ static void findNonInsiders(
+ const QRect &domain, QList<QRect> &source, QList<QRect> &result);
+ static void findMaxOverlappers(
+ const QRect &domain, const QList<QRect> &source, QList<QRect> &result);
+};
+} // namespace QMdi
+
+class QMdiAreaTabBar;
+class QMdiAreaPrivate : public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QMdiArea)
+public:
+ QMdiAreaPrivate();
+
+ // Variables.
+ QMdi::Rearranger *cascader;
+ QMdi::Rearranger *regularTiler;
+ QMdi::Rearranger *iconTiler;
+ QMdi::Placer *placer;
+#ifndef QT_NO_RUBBERBAND
+ QRubberBand *rubberBand;
+#endif
+ QMdiAreaTabBar *tabBar;
+ QList<QMdi::Rearranger *> pendingRearrangements;
+ QList< QPointer<QMdiSubWindow> > pendingPlacements;
+ QList< QPointer<QMdiSubWindow> > childWindows;
+ QList<int> indicesToActivatedChildren;
+ QPointer<QMdiSubWindow> active;
+ QPointer<QMdiSubWindow> aboutToBecomeActive;
+ QBrush background;
+ QMdiArea::WindowOrder activationOrder;
+ QMdiArea::AreaOptions options;
+ QMdiArea::ViewMode viewMode;
+#ifndef QT_NO_TABBAR
+ bool documentMode;
+ bool tabsClosable;
+ bool tabsMovable;
+#endif
+#ifndef QT_NO_TABWIDGET
+ QTabWidget::TabShape tabShape;
+ QTabWidget::TabPosition tabPosition;
+#endif
+ bool ignoreGeometryChange;
+ bool ignoreWindowStateChange;
+ bool isActivated;
+ bool isSubWindowsTiled;
+ bool showActiveWindowMaximized;
+ bool tileCalledFromResizeEvent;
+ bool updatesDisabledByUs;
+ bool inViewModeChange;
+ int indexToNextWindow;
+ int indexToPreviousWindow;
+ int indexToHighlighted;
+ int indexToLastActiveTab;
+ int resizeTimerId;
+ int tabToPreviousTimerId;
+
+ // Slots.
+ void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate = 0);
+ void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState);
+ void _q_currentTabChanged(int index);
+ void _q_closeTab(int index);
+ void _q_moveTab(int from, int to);
+
+ // Functions.
+ void appendChild(QMdiSubWindow *child);
+ void place(QMdi::Placer *placer, QMdiSubWindow *child);
+ void rearrange(QMdi::Rearranger *rearranger);
+ void arrangeMinimizedSubWindows();
+ void activateWindow(QMdiSubWindow *child);
+ void activateCurrentWindow();
+ void activateHighlightedWindow();
+ void emitWindowActivated(QMdiSubWindow *child);
+ void resetActiveWindow(QMdiSubWindow *child = 0);
+ void updateActiveWindow(int removedIndex, bool activeRemoved);
+ void updateScrollBars();
+ void internalRaise(QMdiSubWindow *child) const;
+ bool scrollBarsEnabled() const;
+ bool lastWindowAboutToBeDestroyed() const;
+ void setChildActivationEnabled(bool enable = true, bool onlyNextActivationEvent = false) const;
+ QRect resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount);
+ void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy); // reimp
+ QMdiSubWindow *nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder,
+ int removed = -1, int fromIndex = -1) const;
+ void highlightNextSubWindow(int increaseFactor);
+ QList<QMdiSubWindow *> subWindowList(QMdiArea::WindowOrder, bool reversed = false) const;
+ void disconnectSubWindow(QObject *subWindow);
+ void setViewMode(QMdiArea::ViewMode mode);
+#ifndef QT_NO_TABBAR
+ void updateTabBarGeometry();
+ void refreshTabBar();
+#endif
+
+ inline void startResizeTimer()
+ {
+ Q_Q(QMdiArea);
+ if (resizeTimerId > 0)
+ q->killTimer(resizeTimerId);
+ resizeTimerId = q->startTimer(200);
+ }
+
+ inline void startTabToPreviousTimer()
+ {
+ Q_Q(QMdiArea);
+ if (tabToPreviousTimerId > 0)
+ q->killTimer(tabToPreviousTimerId);
+ tabToPreviousTimerId = q->startTimer(QApplication::keyboardInputInterval());
+ }
+
+ inline bool windowStaysOnTop(QMdiSubWindow *subWindow) const
+ {
+ if (!subWindow)
+ return false;
+ return subWindow->windowFlags() & Qt::WindowStaysOnTopHint;
+ }
+
+ inline bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const
+ {
+ if (!subWindow)
+ return true;
+ return subWindow->d_func()->isExplicitlyDeactivated;
+ }
+
+ inline void setActive(QMdiSubWindow *subWindow, bool active = true, bool changeFocus = true) const
+ {
+ if (subWindow)
+ subWindow->d_func()->setActive(active, changeFocus);
+ }
+
+#ifndef QT_NO_RUBBERBAND
+ inline void showRubberBandFor(QMdiSubWindow *subWindow)
+ {
+ if (!subWindow || !rubberBand)
+ return;
+ rubberBand->setGeometry(subWindow->geometry());
+ rubberBand->raise();
+ rubberBand->show();
+ }
+
+ inline void hideRubberBand()
+ {
+ if (rubberBand && rubberBand->isVisible())
+ rubberBand->hide();
+ indexToHighlighted = -1;
+ }
+#endif // QT_NO_RUBBERBAND
+};
+
+#endif // QT_NO_MDIAREA
+
+QT_END_NAMESPACE
+
+#endif // QMDIAREA_P_H
diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp
new file mode 100644
index 0000000000..5cbd6208cf
--- /dev/null
+++ b/src/widgets/widgets/qmdisubwindow.cpp
@@ -0,0 +1,3547 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QMdiSubWindow
+ \brief The QMdiSubWindow class provides a subwindow class for
+ QMdiArea.
+ \since 4.3
+ \ingroup mainwindow-classes
+
+
+ QMdiSubWindow represents a top-level window in a QMdiArea, and consists
+ of a title bar with window decorations, an internal widget, and
+ (depending on the current style) a window frame and a size
+ grip. QMdiSubWindow has its own layout, which consists of the
+ title bar and a center area for the internal widget.
+
+ \image qmdisubwindowlayout.png
+
+ The most common way to construct a QMdiSubWindow is to call
+ QMdiArea::addSubWindow() with the internal widget as the argument.
+ You can also create a subwindow yourself, and set an internal
+ widget by calling setWidget().
+
+ You use the same API when programming with subwindows as with
+ regular top-level windows (e.g., you can call functions such as
+ show(), hide(), showMaximized(), and setWindowTitle()).
+
+ \section1 Subwindow Handling
+
+ QMdiSubWindow also supports behavior specific to subwindows in
+ an MDI area.
+
+ By default, each QMdiSubWindow is visible inside the MDI area
+ viewport when moved around, but it is also possible to specify
+ transparent window movement and resizing behavior, where only
+ the outline of a subwindow is updated during these operations.
+ The setOption() function is used to enable this behavior.
+
+ The isShaded() function detects whether the subwindow is
+ currently shaded (i.e., the window is collapsed so that only the
+ title bar is visible). To enter shaded mode, call showShaded().
+ QMdiSubWindow emits the windowStateChanged() signal whenever the
+ window state has changed (e.g., when the window becomes minimized,
+ or is restored). It also emits aboutToActivate() before it is
+ activated.
+
+ In keyboard-interactive mode, the windows are moved and resized
+ with the keyboard. You can enter this mode through the system menu
+ of the window. The keyboardSingleStep and keyboardPageStep
+ properties control the distance the widget is moved or resized for
+ each keypress event. When shift is pressed down page step is used;
+ otherwise single step is used.
+
+ You can also change the active window with the keyboard. By
+ pressing the control and tab keys at the same time, the next
+ (using the current \l{QMdiArea::}{WindowOrder}) subwindow will be
+ activated. By pressing control, shift, and tab, you will activate
+ the previous window. This is equivalent to calling
+ \l{QMdiArea::}{activateNextSubWindow()} and
+ \l{QMdiArea::}{activatePreviousSubWindow()}. Note that these
+ shortcuts overrides global shortcuts, but not the \l{QMdiArea}s
+ shortcuts.
+
+ \sa QMdiArea
+*/
+
+/*!
+ \enum QMdiSubWindow::SubWindowOption
+
+ This enum describes options that customize the behavior
+ of QMdiSubWindow.
+
+ \omitvalue AllowOutsideAreaHorizontally
+ \omitvalue AllowOutsideAreaVertically
+
+ \value RubberBandResize If you enable this option, a rubber band
+ control is used to represent the subwindow's outline, and the user
+ resizes this instead of the subwindow itself.
+ As a result, the subwindow maintains its original position and size
+ until the resize operation has been completed, at which time it will
+ receive a single QResizeEvent.
+ By default, this option is disabled.
+
+ \value RubberBandMove If you enable this option, a rubber band
+ control is used to represent the subwindow's outline, and the user
+ moves this instead of the subwindow itself.
+ As a result, the subwindow remains in its original position until
+ the move operation has completed, at which time a QMoveEvent is
+ sent to the window. By default, this option is disabled.
+*/
+
+/*!
+ \fn QMdiSubWindow::windowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState)
+
+ QMdiSubWindow emits this signal after the window state changes. \a
+ oldState is the window state before it changed, and \a newState is the
+ new, current state.
+*/
+
+/*!
+ \fn QMdiSubWindow::aboutToActivate()
+
+ QMdiSubWindow emits this signal immediately before it is
+ activated. After the subwindow has been activated, the QMdiArea that
+ manages the subwindow will also emit the
+ \l{QMdiArea::}{subWindowActivated()} signal.
+
+ \sa QMdiArea::subWindowActivated()
+*/
+
+#include "qmdisubwindow_p.h"
+
+#ifndef QT_NO_MDIAREA
+
+#include <QApplication>
+#include <QStylePainter>
+#include <QVBoxLayout>
+#include <QMouseEvent>
+#include <QWhatsThis>
+#include <QToolTip>
+#include <QMainWindow>
+#include <QScrollBar>
+#include <QDebug>
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+#include <QMacStyle>
+#endif
+#include <QMdiArea>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QMdi;
+
+static const QStyle::SubControl SubControls[] =
+{
+ QStyle::SC_TitleBarLabel, // 1
+ QStyle::SC_TitleBarSysMenu, // 2
+ QStyle::SC_TitleBarMinButton, // 3
+ QStyle::SC_TitleBarMaxButton, // 4
+ QStyle::SC_TitleBarShadeButton, // 5
+ QStyle::SC_TitleBarCloseButton, // 6
+ QStyle::SC_TitleBarNormalButton, // 7
+ QStyle::SC_TitleBarUnshadeButton, // 8
+ QStyle::SC_TitleBarContextHelpButton // 9
+};
+static const int NumSubControls = sizeof(SubControls) / sizeof(SubControls[0]);
+
+static const QStyle::StandardPixmap ButtonPixmaps[] =
+{
+ QStyle::SP_TitleBarMinButton,
+ QStyle::SP_TitleBarNormalButton,
+ QStyle::SP_TitleBarCloseButton
+};
+static const int NumButtonPixmaps = sizeof(ButtonPixmaps) / sizeof(ButtonPixmaps[0]);
+
+static const Qt::WindowFlags CustomizeWindowFlags =
+ Qt::FramelessWindowHint
+ | Qt::CustomizeWindowHint
+ | Qt::WindowTitleHint
+ | Qt::WindowSystemMenuHint
+ | Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowMinMaxButtonsHint;
+
+
+static const int BoundaryMargin = 5;
+
+static inline int getMoveDeltaComponent(uint cflags, uint moveFlag, uint resizeFlag,
+ int delta, int maxDelta, int minDelta)
+{
+ if (cflags & moveFlag) {
+ if (delta > 0)
+ return (cflags & resizeFlag) ? qMin(delta, maxDelta) : delta;
+ return (cflags & resizeFlag) ? qMax(delta, minDelta) : delta;
+ }
+ return 0;
+}
+
+static inline int getResizeDeltaComponent(uint cflags, uint resizeFlag,
+ uint resizeReverseFlag, int delta)
+{
+ if (cflags & resizeFlag) {
+ if (cflags & resizeReverseFlag)
+ return -delta;
+ return delta;
+ }
+ return 0;
+}
+
+static inline bool isChildOfQMdiSubWindow(const QWidget *child)
+{
+ Q_ASSERT(child);
+ QWidget *parent = child->parentWidget();
+ while (parent) {
+ if (qobject_cast<QMdiSubWindow *>(parent))
+ return true;
+ parent = parent->parentWidget();
+ }
+ return false;
+}
+
+static inline bool isChildOfTabbedQMdiArea(const QMdiSubWindow *child)
+{
+ Q_ASSERT(child);
+ if (QMdiArea *mdiArea = child->mdiArea()) {
+ if (mdiArea->viewMode() == QMdiArea::TabbedView)
+ return true;
+ }
+ return false;
+}
+
+template<typename T>
+static inline ControlElement<T> *ptr(QWidget *widget)
+{
+ if (widget && widget->qt_metacast("ControlElement")
+ && strcmp(widget->metaObject()->className(), T::staticMetaObject.className()) == 0) {
+ return static_cast<ControlElement<T> *>(widget);
+ }
+ return 0;
+}
+
+QString QMdiSubWindowPrivate::originalWindowTitle()
+{
+ Q_Q(QMdiSubWindow);
+ if (originalTitle.isNull()) {
+ originalTitle = q->window()->windowTitle();
+ if (originalTitle.isNull())
+ originalTitle = QLatin1String("");
+ }
+ return originalTitle;
+}
+
+void QMdiSubWindowPrivate::setNewWindowTitle()
+{
+ Q_Q(QMdiSubWindow);
+ QString childTitle = q->windowTitle();
+ if (childTitle.isEmpty())
+ return;
+ QString original = originalWindowTitle();
+ if (!original.isEmpty()) {
+ if (!original.contains(QMdiSubWindow::tr("- [%1]").arg(childTitle)))
+ q->window()->setWindowTitle(QMdiSubWindow::tr("%1 - [%2]").arg(original, childTitle));
+
+ } else {
+ q->window()->setWindowTitle(childTitle);
+ }
+}
+
+static inline bool isHoverControl(QStyle::SubControl control)
+{
+ return control != QStyle::SC_None && control != QStyle::SC_TitleBarLabel;
+}
+
+#if defined(Q_WS_WIN)
+static inline QRgb colorref2qrgb(COLORREF col)
+{
+ return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
+}
+#endif
+
+#ifndef QT_NO_TOOLTIP
+static void showToolTip(QHelpEvent *helpEvent, QWidget *widget, const QStyleOptionComplex &opt,
+ QStyle::ComplexControl complexControl, QStyle::SubControl subControl)
+{
+ Q_ASSERT(helpEvent);
+ Q_ASSERT(helpEvent->type() == QEvent::ToolTip);
+ Q_ASSERT(widget);
+
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ // Native Mac windows don't show tool tip.
+ if (qobject_cast<QMacStyle *>(widget->style()))
+ return;
+#endif
+
+ // Convert CC_MdiControls to CC_TitleBar. Sub controls of different complex
+ // controls cannot be in the same switch as they might have the same value.
+ if (complexControl == QStyle::CC_MdiControls) {
+ if (subControl == QStyle::SC_MdiMinButton)
+ subControl = QStyle::SC_TitleBarMinButton;
+ else if (subControl == QStyle::SC_MdiCloseButton)
+ subControl = QStyle::SC_TitleBarCloseButton;
+ else if (subControl == QStyle::SC_MdiNormalButton)
+ subControl = QStyle::SC_TitleBarNormalButton;
+ else
+ subControl = QStyle::SC_None;
+ }
+
+ // Don't change the tooltip for the base widget itself.
+ if (subControl == QStyle::SC_None)
+ return;
+
+ QString toolTip;
+
+ switch (subControl) {
+ case QStyle::SC_TitleBarMinButton:
+ toolTip = QMdiSubWindow::tr("Minimize");
+ break;
+ case QStyle::SC_TitleBarMaxButton:
+ toolTip = QMdiSubWindow::tr("Maximize");
+ break;
+ case QStyle::SC_TitleBarUnshadeButton:
+ toolTip = QMdiSubWindow::tr("Unshade");
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ toolTip = QMdiSubWindow::tr("Shade");
+ break;
+ case QStyle::SC_TitleBarNormalButton:
+ if (widget->isMaximized() || !qobject_cast<QMdiSubWindow *>(widget))
+ toolTip = QMdiSubWindow::tr("Restore Down");
+ else
+ toolTip = QMdiSubWindow::tr("Restore");
+ break;
+ case QStyle::SC_TitleBarCloseButton:
+ toolTip = QMdiSubWindow::tr("Close");
+ break;
+ case QStyle::SC_TitleBarContextHelpButton:
+ toolTip = QMdiSubWindow::tr("Help");
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ toolTip = QMdiSubWindow::tr("Menu");
+ break;
+ default:
+ break;
+ }
+
+ const QRect rect = widget->style()->subControlRect(complexControl, &opt, subControl, widget);
+ QToolTip::showText(helpEvent->globalPos(), toolTip, widget, rect);
+}
+#endif // QT_NO_TOOLTIP
+
+namespace QMdi {
+/*
+ \class ControlLabel
+ \internal
+*/
+class ControlLabel : public QWidget
+{
+ Q_OBJECT
+public:
+ ControlLabel(QMdiSubWindow *subWindow, QWidget *parent = 0);
+
+ QSize sizeHint() const;
+
+signals:
+ void _q_clicked();
+ void _q_doubleClicked();
+
+protected:
+ bool event(QEvent *event);
+ void paintEvent(QPaintEvent *paintEvent);
+ void mousePressEvent(QMouseEvent *mouseEvent);
+ void mouseDoubleClickEvent(QMouseEvent *mouseEvent);
+ void mouseReleaseEvent(QMouseEvent *mouseEvent);
+
+private:
+ QPixmap label;
+ bool isPressed;
+ void updateWindowIcon();
+};
+} // namespace QMdi
+
+ControlLabel::ControlLabel(QMdiSubWindow *subWindow, QWidget *parent)
+ : QWidget(parent), isPressed(false)
+{
+ Q_UNUSED(subWindow);
+ setFocusPolicy(Qt::NoFocus);
+ updateWindowIcon();
+ setFixedSize(label.size());
+}
+
+/*
+ \internal
+*/
+QSize ControlLabel::sizeHint() const
+{
+ return label.size();
+}
+
+/*
+ \internal
+*/
+bool ControlLabel::event(QEvent *event)
+{
+ if (event->type() == QEvent::WindowIconChange)
+ updateWindowIcon();
+#ifndef QT_NO_TOOLTIP
+ else if (event->type() == QEvent::ToolTip) {
+ QStyleOptionTitleBar options;
+ options.initFrom(this);
+ showToolTip(static_cast<QHelpEvent *>(event), this, options,
+ QStyle::CC_TitleBar, QStyle::SC_TitleBarSysMenu);
+ }
+#endif
+ return QWidget::event(event);
+}
+
+/*
+ \internal
+*/
+void ControlLabel::paintEvent(QPaintEvent * /*paintEvent*/)
+{
+ QPainter painter(this);
+ painter.drawPixmap(0, 0, label);
+}
+
+/*
+ \internal
+*/
+void ControlLabel::mousePressEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+ isPressed = true;
+}
+
+/*
+ \internal
+*/
+void ControlLabel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+ isPressed = false;
+ emit _q_doubleClicked();
+}
+
+/*
+ \internal
+*/
+void ControlLabel::mouseReleaseEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+ if (isPressed) {
+ isPressed = false;
+ emit _q_clicked();
+ }
+}
+
+/*
+ \internal
+*/
+void ControlLabel::updateWindowIcon()
+{
+ QIcon menuIcon = windowIcon();
+ if (menuIcon.isNull())
+ menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, parentWidget());
+ label = menuIcon.pixmap(16, 16);
+ update();
+}
+
+namespace QMdi {
+/*
+ \class ControllerWidget
+ \internal
+*/
+class ControllerWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent = 0);
+ QSize sizeHint() const;
+ void setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible);
+ inline bool hasVisibleControls() const
+ {
+ return (visibleControls & QStyle::SC_MdiMinButton)
+ || (visibleControls & QStyle::SC_MdiNormalButton)
+ || (visibleControls & QStyle::SC_MdiCloseButton);
+ }
+
+signals:
+ void _q_minimize();
+ void _q_restore();
+ void _q_close();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void leaveEvent(QEvent *event);
+ bool event(QEvent *event);
+
+private:
+ QStyle::SubControl activeControl;
+ QStyle::SubControl hoverControl;
+ QStyle::SubControls visibleControls;
+ void initStyleOption(QStyleOptionComplex *option) const;
+ QMdiArea *mdiArea;
+ inline QStyle::SubControl getSubControl(const QPoint &pos) const
+ {
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ return style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt, pos, mdiArea);
+ }
+};
+} // namespace QMdi
+
+/*
+ \internal
+*/
+ControllerWidget::ControllerWidget(QMdiSubWindow *subWindow, QWidget *parent)
+ : QWidget(parent),
+ activeControl(QStyle::SC_None),
+ hoverControl(QStyle::SC_None),
+ visibleControls(QStyle::SC_None),
+ mdiArea(0)
+{
+ if (subWindow->parentWidget())
+ mdiArea = qobject_cast<QMdiArea *>(subWindow->parentWidget()->parentWidget());
+ setFocusPolicy(Qt::NoFocus);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setMouseTracking(true);
+}
+
+/*
+ \internal
+*/
+QSize ControllerWidget::sizeHint() const
+{
+ ensurePolished();
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ QSize size(48, 16);
+ return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, mdiArea);
+}
+
+void ControllerWidget::setControlVisible(QMdiSubWindowPrivate::WindowStateAction action, bool visible)
+{
+ QStyle::SubControl subControl = QStyle::SC_None;
+
+ // Map action from QMdiSubWindowPrivate::WindowStateAction to QStyle::SubControl.
+ if (action == QMdiSubWindowPrivate::MaximizeAction)
+ subControl = QStyle::SC_MdiNormalButton;
+ else if (action == QMdiSubWindowPrivate::CloseAction)
+ subControl = QStyle::SC_MdiCloseButton;
+ else if (action == QMdiSubWindowPrivate::MinimizeAction)
+ subControl = QStyle::SC_MdiMinButton;
+
+ if (subControl == QStyle::SC_None)
+ return;
+
+ if (visible && !(visibleControls & subControl))
+ visibleControls |= subControl;
+ else if (!visible && (visibleControls & subControl))
+ visibleControls &= ~subControl;
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::paintEvent(QPaintEvent * /*paintEvent*/)
+{
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ if (activeControl == hoverControl) {
+ opt.activeSubControls = activeControl;
+ opt.state |= QStyle::State_Sunken;
+ } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
+ opt.activeSubControls = hoverControl;
+ opt.state |= QStyle::State_MouseOver;
+ }
+ QPainter painter(this);
+ style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &painter, mdiArea);
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+ activeControl = getSubControl(event->pos());
+ update();
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+
+ QStyle::SubControl under_mouse = getSubControl(event->pos());
+ if (under_mouse == activeControl) {
+ switch (activeControl) {
+ case QStyle::SC_MdiCloseButton:
+ emit _q_close();
+ break;
+ case QStyle::SC_MdiNormalButton:
+ emit _q_restore();
+ break;
+ case QStyle::SC_MdiMinButton:
+ emit _q_minimize();
+ break;
+ default:
+ break;
+ }
+ }
+
+ activeControl = QStyle::SC_None;
+ update();
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ QStyle::SubControl under_mouse = getSubControl(event->pos());
+ //test if hover state changes
+ if (hoverControl != under_mouse) {
+ hoverControl = under_mouse;
+ update();
+ }
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::leaveEvent(QEvent * /*event*/)
+{
+ hoverControl = QStyle::SC_None;
+ update();
+}
+
+/*
+ \internal
+*/
+bool ControllerWidget::event(QEvent *event)
+{
+#ifndef QT_NO_TOOLTIP
+ if (event->type() == QEvent::ToolTip) {
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+ showToolTip(helpEvent, this, opt, QStyle::CC_MdiControls, getSubControl(helpEvent->pos()));
+ }
+#endif // QT_NO_TOOLTIP
+ return QWidget::event(event);
+}
+
+/*
+ \internal
+*/
+void ControllerWidget::initStyleOption(QStyleOptionComplex *option) const
+{
+ option->initFrom(this);
+ option->subControls = visibleControls;
+ option->activeSubControls = QStyle::SC_None;
+}
+
+/*
+ \internal
+*/
+ControlContainer::ControlContainer(QMdiSubWindow *mdiChild)
+ : QObject(mdiChild),
+ previousLeft(0),
+ previousRight(0),
+#ifndef QT_NO_MENUBAR
+ m_menuBar(0),
+#endif
+ mdiChild(mdiChild)
+{
+ Q_ASSERT(mdiChild);
+
+ m_controllerWidget = new ControlElement<ControllerWidget>(mdiChild);
+ connect(m_controllerWidget, SIGNAL(_q_close()), mdiChild, SLOT(close()));
+ connect(m_controllerWidget, SIGNAL(_q_restore()), mdiChild, SLOT(showNormal()));
+ connect(m_controllerWidget, SIGNAL(_q_minimize()), mdiChild, SLOT(showMinimized()));
+
+ m_menuLabel = new ControlElement<ControlLabel>(mdiChild);
+ m_menuLabel->setWindowIcon(mdiChild->windowIcon());
+#ifndef QT_NO_MENU
+ connect(m_menuLabel, SIGNAL(_q_clicked()), mdiChild, SLOT(showSystemMenu()));
+#endif
+ connect(m_menuLabel, SIGNAL(_q_doubleClicked()), mdiChild, SLOT(close()));
+}
+
+ControlContainer::~ControlContainer()
+{
+#ifndef QT_NO_MENUBAR
+ removeButtonsFromMenuBar();
+#endif
+ delete m_menuLabel;
+ m_menuLabel = 0;
+ delete m_controllerWidget;
+ m_controllerWidget = 0;
+}
+
+#ifndef QT_NO_MENUBAR
+/*
+ \internal
+*/
+QMenuBar *QMdiSubWindowPrivate::menuBar() const
+{
+#if defined(QT_NO_MAINWINDOW)
+ return 0;
+#else
+ Q_Q(const QMdiSubWindow);
+ if (!q->isMaximized() || drawTitleBarWhenMaximized() || isChildOfTabbedQMdiArea(q))
+ return 0;
+
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window()))
+ return mainWindow->menuBar();
+
+ return 0;
+#endif
+}
+
+/*
+ \internal
+*/
+void ControlContainer::showButtonsInMenuBar(QMenuBar *menuBar)
+{
+ if (!menuBar || !mdiChild || mdiChild->windowFlags() & Qt::FramelessWindowHint)
+ return;
+ m_menuBar = menuBar;
+
+ if (m_menuLabel && mdiChild->windowFlags() & Qt::WindowSystemMenuHint) {
+ QWidget *currentLeft = menuBar->cornerWidget(Qt::TopLeftCorner);
+ if (currentLeft)
+ currentLeft->hide();
+ if (currentLeft != m_menuLabel) {
+ menuBar->setCornerWidget(m_menuLabel, Qt::TopLeftCorner);
+ previousLeft = currentLeft;
+ }
+ m_menuLabel->show();
+ }
+ ControllerWidget *controllerWidget = qobject_cast<ControllerWidget *>(m_controllerWidget);
+ if (controllerWidget && controllerWidget->hasVisibleControls()) {
+ QWidget *currentRight = menuBar->cornerWidget(Qt::TopRightCorner);
+ if (currentRight)
+ currentRight->hide();
+ if (currentRight != m_controllerWidget) {
+ menuBar->setCornerWidget(m_controllerWidget, Qt::TopRightCorner);
+ previousRight = currentRight;
+ }
+ m_controllerWidget->show();
+ }
+ mdiChild->d_func()->setNewWindowTitle();
+}
+
+/*
+ \internal
+*/
+void ControlContainer::removeButtonsFromMenuBar(QMenuBar *menuBar)
+{
+ if (menuBar && menuBar != m_menuBar) {
+ // m_menubar was deleted while sub-window was maximized
+ previousRight = 0;
+ previousLeft = 0;
+ m_menuBar = menuBar;
+ }
+
+ if (!m_menuBar || !mdiChild || qt_widget_private(mdiChild->window())->data.in_destructor)
+ return;
+
+ QMdiSubWindow *child = 0;
+ if (m_controllerWidget) {
+ QWidget *currentRight = m_menuBar->cornerWidget(Qt::TopRightCorner);
+ if (currentRight == m_controllerWidget) {
+ if (ControlElement<ControllerWidget> *ce = ptr<ControllerWidget>(previousRight)) {
+ if (!ce->mdiChild || !ce->mdiChild->isMaximized())
+ previousRight = 0;
+ else
+ child = ce->mdiChild;
+ }
+ m_menuBar->setCornerWidget(previousRight, Qt::TopRightCorner);
+ if (previousRight) {
+ previousRight->show();
+ previousRight = 0;
+ }
+ }
+ m_controllerWidget->hide();
+ m_controllerWidget->setParent(0);
+ }
+ if (m_menuLabel) {
+ QWidget *currentLeft = m_menuBar->cornerWidget(Qt::TopLeftCorner);
+ if (currentLeft == m_menuLabel) {
+ if (ControlElement<ControlLabel> *ce = ptr<ControlLabel>(previousLeft)) {
+ if (!ce->mdiChild || !ce->mdiChild->isMaximized())
+ previousLeft = 0;
+ else if (!child)
+ child = mdiChild;
+ }
+ m_menuBar->setCornerWidget(previousLeft, Qt::TopLeftCorner);
+ if (previousLeft) {
+ previousLeft->show();
+ previousLeft = 0;
+ }
+ }
+ m_menuLabel->hide();
+ m_menuLabel->setParent(0);
+ }
+ m_menuBar->update();
+ if (child)
+ child->d_func()->setNewWindowTitle();
+ else if (mdiChild)
+ mdiChild->window()->setWindowTitle(mdiChild->d_func()->originalWindowTitle());
+}
+
+#endif // QT_NO_MENUBAR
+
+void ControlContainer::updateWindowIcon(const QIcon &windowIcon)
+{
+ if (m_menuLabel)
+ m_menuLabel->setWindowIcon(windowIcon);
+}
+
+/*!
+ \internal
+*/
+QMdiSubWindowPrivate::QMdiSubWindowPrivate()
+ : baseWidget(0),
+ restoreFocusWidget(0),
+ controlContainer(0),
+#ifndef QT_NO_SIZEGRIP
+ sizeGrip(0),
+#endif
+#ifndef QT_NO_RUBBERBAND
+ rubberBand(0),
+#endif
+ userMinimumSize(0,0),
+ resizeEnabled(true),
+ moveEnabled(true),
+ isInInteractiveMode(false),
+#ifndef QT_NO_RUBBERBAND
+ isInRubberBandMode(false),
+#endif
+ isShadeMode(false),
+ ignoreWindowTitleChange(false),
+ ignoreNextActivationEvent(false),
+ activationEnabled(true),
+ isShadeRequestFromMinimizeMode(false),
+ isMaximizeMode(false),
+ isWidgetHiddenByUs(false),
+ isActive(false),
+ isExplicitlyDeactivated(false),
+ keyboardSingleStep(5),
+ keyboardPageStep(20),
+ resizeTimerId(-1),
+ currentOperation(None),
+ hoveredSubControl(QStyle::SC_None),
+ activeSubControl(QStyle::SC_None),
+ focusInReason(Qt::ActiveWindowFocusReason)
+{
+ initOperationMap();
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::_q_updateStaysOnTopHint()
+{
+#ifndef QT_NO_ACTION
+ Q_Q(QMdiSubWindow);
+ if (QAction *senderAction = qobject_cast<QAction *>(q->sender())) {
+ if (senderAction->isChecked()) {
+ q->setWindowFlags(q->windowFlags() | Qt::WindowStaysOnTopHint);
+ q->raise();
+ } else {
+ q->setWindowFlags(q->windowFlags() & ~Qt::WindowStaysOnTopHint);
+ q->lower();
+ }
+ }
+#endif // QT_NO_ACTION
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::_q_enterInteractiveMode()
+{
+#ifndef QT_NO_ACTION
+ Q_Q(QMdiSubWindow);
+ QAction *action = qobject_cast<QAction *>(q->sender());
+ if (!action)
+ return;
+
+ QPoint pressPos;
+ if (actions[MoveAction] && actions[MoveAction] == action) {
+ currentOperation = Move;
+ pressPos = QPoint(q->width() / 2, titleBarHeight() - 1);
+ } else if (actions[ResizeAction] && actions[ResizeAction] == action) {
+ currentOperation = q->isLeftToRight() ? BottomRightResize : BottomLeftResize;
+ int offset = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q) / 2;
+ int x = q->isLeftToRight() ? q->width() - offset : offset;
+ pressPos = QPoint(x, q->height() - offset);
+ } else {
+ return;
+ }
+
+ updateCursor();
+#ifndef QT_NO_CURSOR
+ q->cursor().setPos(q->mapToGlobal(pressPos));
+#endif
+ mousePressPosition = q->mapToParent(pressPos);
+ oldGeometry = q->geometry();
+ isInInteractiveMode = true;
+ q->setFocus();
+#ifndef QT_NO_RUBBERBAND
+ if ((q->testOption(QMdiSubWindow::RubberBandResize)
+ && (currentOperation == BottomRightResize || currentOperation == BottomLeftResize))
+ || (q->testOption(QMdiSubWindow::RubberBandMove) && currentOperation == Move)) {
+ enterRubberBandMode();
+ } else
+#endif // QT_NO_RUBBERBAND
+ {
+ q->grabMouse();
+ }
+#endif // QT_NO_ACTION
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::_q_processFocusChanged(QWidget *old, QWidget *now)
+{
+ Q_UNUSED(old);
+ Q_Q(QMdiSubWindow);
+ if (now && (now == q || q->isAncestorOf(now))) {
+ if (now == q && !isInInteractiveMode)
+ setFocusWidget();
+ setActive(true);
+ }
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::leaveInteractiveMode()
+{
+ Q_Q(QMdiSubWindow);
+#ifndef QT_NO_RUBBERBAND
+ if (isInRubberBandMode)
+ leaveRubberBandMode();
+ else
+#endif
+ q->releaseMouse();
+ isInInteractiveMode = false;
+ currentOperation = None;
+ updateDirtyRegions();
+ updateCursor();
+ if (baseWidget && baseWidget->focusWidget())
+ baseWidget->focusWidget()->setFocus();
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::removeBaseWidget()
+{
+ if (!baseWidget)
+ return;
+
+ Q_Q(QMdiSubWindow);
+ baseWidget->removeEventFilter(q);
+ if (layout)
+ layout->removeWidget(baseWidget);
+ if (baseWidget->windowTitle() == q->windowTitle()) {
+ ignoreWindowTitleChange = true;
+ q->setWindowTitle(QString());
+ ignoreWindowTitleChange = false;
+ q->setWindowModified(false);
+ }
+ lastChildWindowTitle.clear();
+ baseWidget->setParent(0);
+ baseWidget = 0;
+ isWidgetHiddenByUs = false;
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::initOperationMap()
+{
+ operationMap.insert(Move, OperationInfo(HMove | VMove, Qt::ArrowCursor, false));
+ operationMap.insert(TopResize, OperationInfo(VMove | VResize | VResizeReverse, Qt::SizeVerCursor));
+ operationMap.insert(BottomResize, OperationInfo(VResize, Qt::SizeVerCursor));
+ operationMap.insert(LeftResize, OperationInfo(HMove | HResize | HResizeReverse, Qt::SizeHorCursor));
+ operationMap.insert(RightResize, OperationInfo(HResize, Qt::SizeHorCursor));
+ operationMap.insert(TopLeftResize, OperationInfo(HMove | VMove | HResize | VResize | VResizeReverse
+ | HResizeReverse, Qt::SizeFDiagCursor));
+ operationMap.insert(TopRightResize, OperationInfo(VMove | HResize | VResize
+ | VResizeReverse, Qt::SizeBDiagCursor));
+ operationMap.insert(BottomLeftResize, OperationInfo(HMove | HResize | VResize | HResizeReverse,
+ Qt::SizeBDiagCursor));
+ operationMap.insert(BottomRightResize, OperationInfo(HResize | VResize, Qt::SizeFDiagCursor));
+}
+
+#ifndef QT_NO_MENU
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::createSystemMenu()
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT_X(q, "QMdiSubWindowPrivate::createSystemMenu",
+ "You can NOT call this function before QMdiSubWindow's ctor");
+ systemMenu = new QMenu(q);
+ const QStyle *style = q->style();
+ addToSystemMenu(RestoreAction, QMdiSubWindow::tr("&Restore"), SLOT(showNormal()));
+ actions[RestoreAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q));
+ actions[RestoreAction]->setEnabled(false);
+ addToSystemMenu(MoveAction, QMdiSubWindow::tr("&Move"), SLOT(_q_enterInteractiveMode()));
+ addToSystemMenu(ResizeAction, QMdiSubWindow::tr("&Size"), SLOT(_q_enterInteractiveMode()));
+ addToSystemMenu(MinimizeAction, QMdiSubWindow::tr("Mi&nimize"), SLOT(showMinimized()));
+ actions[MinimizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMinButton, 0, q));
+ addToSystemMenu(MaximizeAction, QMdiSubWindow::tr("Ma&ximize"), SLOT(showMaximized()));
+ actions[MaximizeAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarMaxButton, 0, q));
+ addToSystemMenu(StayOnTopAction, QMdiSubWindow::tr("Stay on &Top"), SLOT(_q_updateStaysOnTopHint()));
+ actions[StayOnTopAction]->setCheckable(true);
+ systemMenu->addSeparator();
+ addToSystemMenu(CloseAction, QMdiSubWindow::tr("&Close"), SLOT(close()));
+ actions[CloseAction]->setIcon(style->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q));
+#if !defined(QT_NO_SHORTCUT)
+ actions[CloseAction]->setShortcuts(QKeySequence::Close);
+#endif
+ updateActions();
+}
+#endif
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::updateCursor()
+{
+#ifndef QT_NO_CURSOR
+ Q_Q(QMdiSubWindow);
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(q->style()))
+ return;
+#endif
+
+ if (currentOperation == None) {
+ q->unsetCursor();
+ return;
+ }
+
+ if (currentOperation == Move || operationMap.find(currentOperation).value().hover) {
+ q->setCursor(operationMap.find(currentOperation).value().cursorShape);
+ return;
+ }
+#endif
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::updateDirtyRegions()
+{
+ // No update necessary
+ if (!parent)
+ return;
+
+ foreach (Operation operation, operationMap.keys())
+ operationMap.find(operation).value().region = getRegion(operation);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::updateGeometryConstraints()
+{
+ Q_Q(QMdiSubWindow);
+ if (!parent)
+ return;
+
+ internalMinimumSize = (!q->isMinimized() && !q->minimumSize().isNull())
+ ? q->minimumSize() : q->minimumSizeHint();
+ int margin, minWidth;
+ sizeParameters(&margin, &minWidth);
+ q->setContentsMargins(margin, titleBarHeight(), margin, margin);
+ if (q->isMaximized() || (q->isMinimized() && !q->isShaded())) {
+ moveEnabled = false;
+ resizeEnabled = false;
+ } else {
+ moveEnabled = true;
+ if ((q->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || q->isShaded())
+ resizeEnabled = false;
+ else
+ resizeEnabled = true;
+ }
+ updateDirtyRegions();
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::updateMask()
+{
+ Q_Q(QMdiSubWindow);
+ if (!q->mask().isEmpty())
+ q->clearMask();
+
+ if (!parent)
+ return;
+
+ if ((q->isMaximized() && !drawTitleBarWhenMaximized())
+ || q->windowFlags() & Qt::FramelessWindowHint)
+ return;
+
+ if (resizeTimerId == -1)
+ cachedStyleOptions = titleBarOptions();
+ cachedStyleOptions.rect = q->rect();
+ QStyleHintReturnMask frameMask;
+ q->style()->styleHint(QStyle::SH_WindowFrame_Mask, &cachedStyleOptions, q, &frameMask);
+ if (!frameMask.region.isEmpty())
+ q->setMask(frameMask.region);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setNewGeometry(const QPoint &pos)
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(currentOperation != None);
+ Q_ASSERT(parent);
+
+ uint cflags = operationMap.find(currentOperation).value().changeFlags;
+ int posX = pos.x();
+ int posY = pos.y();
+
+ const bool restrictHorizontal = !q->testOption(QMdiSubWindow::AllowOutsideAreaHorizontally);
+ const bool restrictVertical = !q->testOption(QMdiSubWindow::AllowOutsideAreaVertically);
+
+ if (restrictHorizontal || restrictVertical) {
+ QRect parentRect = q->parentWidget()->rect();
+ if (restrictVertical && (cflags & VResizeReverse || currentOperation == Move)) {
+ posY = qMin(qMax(mousePressPosition.y() - oldGeometry.y(), posY),
+ parentRect.height() - BoundaryMargin);
+ }
+ if (currentOperation == Move) {
+ if (restrictHorizontal)
+ posX = qMin(qMax(BoundaryMargin, posX), parentRect.width() - BoundaryMargin);
+ if (restrictVertical)
+ posY = qMin(posY, parentRect.height() - BoundaryMargin);
+ } else {
+ if (restrictHorizontal) {
+ if (cflags & HResizeReverse)
+ posX = qMax(mousePressPosition.x() - oldGeometry.x(), posX);
+ else
+ posX = qMin(parentRect.width() - (oldGeometry.x() + oldGeometry.width()
+ - mousePressPosition.x()), posX);
+ }
+ if (restrictVertical && !(cflags & VResizeReverse)) {
+ posY = qMin(parentRect.height() - (oldGeometry.y() + oldGeometry.height()
+ - mousePressPosition.y()), posY);
+ }
+ }
+ }
+
+ QRect geometry;
+ if (cflags & (HMove | VMove)) {
+ int dx = getMoveDeltaComponent(cflags, HMove, HResize, posX - mousePressPosition.x(),
+ oldGeometry.width() - internalMinimumSize.width(),
+ oldGeometry.width() - q->maximumWidth());
+ int dy = getMoveDeltaComponent(cflags, VMove, VResize, posY - mousePressPosition.y(),
+ oldGeometry.height() - internalMinimumSize.height(),
+ oldGeometry.height() - q->maximumHeight());
+ geometry.setTopLeft(oldGeometry.topLeft() + QPoint(dx, dy));
+ } else {
+ geometry.setTopLeft(q->geometry().topLeft());
+ }
+
+ if (cflags & (HResize | VResize)) {
+ int dx = getResizeDeltaComponent(cflags, HResize, HResizeReverse,
+ posX - mousePressPosition.x());
+ int dy = getResizeDeltaComponent(cflags, VResize, VResizeReverse,
+ posY - mousePressPosition.y());
+ geometry.setSize(oldGeometry.size() + QSize(dx, dy));
+ } else {
+ geometry.setSize(q->geometry().size());
+ }
+
+ setNewGeometry(&geometry);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setMinimizeMode()
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(parent);
+
+ ensureWindowState(Qt::WindowMinimized);
+ isShadeRequestFromMinimizeMode = true;
+ q->showShaded();
+ isShadeRequestFromMinimizeMode = false;
+
+ moveEnabled = false;
+#ifndef QT_NO_ACTION
+ setEnabled(MoveAction, moveEnabled);
+#endif
+
+ Q_ASSERT(q->windowState() & Qt::WindowMinimized);
+ Q_ASSERT(!(q->windowState() & Qt::WindowMaximized));
+ // This should be a valid assert, but people can actually re-implement
+ // setVisible and do crazy stuff, so we're not guaranteed that
+ // the widget is hidden after calling hide().
+ // Q_ASSERT(baseWidget ? baseWidget->isHidden() : true);
+
+ setActive(true);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setNormalMode()
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(parent);
+
+ isShadeMode = false;
+ isMaximizeMode = false;
+
+ ensureWindowState(Qt::WindowNoState);
+#ifndef QT_NO_MENUBAR
+ removeButtonsFromMenuBar();
+#endif
+
+ // Hide the window before we change the geometry to avoid multiple resize
+ // events and wrong window state.
+ const bool wasVisible = q->isVisible();
+ if (wasVisible)
+ q->setVisible(false);
+
+ // Restore minimum size if set by user.
+ if (!userMinimumSize.isNull()) {
+ q->setMinimumSize(userMinimumSize);
+ userMinimumSize = QSize(0, 0);
+ }
+
+ // Show the internal widget if it was hidden by us,
+ if (baseWidget && isWidgetHiddenByUs) {
+ baseWidget->show();
+ isWidgetHiddenByUs = false;
+ }
+
+ updateGeometryConstraints();
+ QRect newGeometry = oldGeometry;
+ newGeometry.setSize(restoreSize.expandedTo(internalMinimumSize));
+ q->setGeometry(newGeometry);
+
+ if (wasVisible)
+ q->setVisible(true);
+
+ // Invalidate the restore size.
+ restoreSize.setWidth(-1);
+ restoreSize.setHeight(-1);
+
+#ifndef QT_NO_SIZEGRIP
+ setSizeGripVisible(true);
+#endif
+
+#ifndef QT_NO_ACTION
+ setEnabled(MoveAction, true);
+ setEnabled(MaximizeAction, true);
+ setEnabled(MinimizeAction, true);
+ setEnabled(RestoreAction, false);
+ setEnabled(ResizeAction, resizeEnabled);
+#endif // QT_NO_ACTION
+
+ Q_ASSERT(!(q_func()->windowState() & Qt::WindowMinimized));
+ // This sub-window can be maximized when shown above if not the
+ // QMdiArea::DontMaximizeSubWindowOnActionvation is set. Make sure
+ // the Qt::WindowMaximized flag is set accordingly.
+ Q_ASSERT((isMaximizeMode && q_func()->windowState() & Qt::WindowMaximized)
+ || (!isMaximizeMode && !(q_func()->windowState() & Qt::WindowMaximized)));
+ Q_ASSERT(!isShadeMode);
+
+ setActive(true);
+ restoreFocus();
+ updateMask();
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setMaximizeMode()
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(parent);
+
+ ensureWindowState(Qt::WindowMaximized);
+ isShadeMode = false;
+ isMaximizeMode = true;
+
+ if (!restoreFocusWidget && q->isAncestorOf(QApplication::focusWidget()))
+ restoreFocusWidget = QApplication::focusWidget();
+
+#ifndef QT_NO_SIZEGRIP
+ setSizeGripVisible(false);
+#endif
+
+ // Store old geometry and set restore size if not already set.
+ if (!restoreSize.isValid()) {
+ oldGeometry = q->geometry();
+ restoreSize.setWidth(oldGeometry.width());
+ restoreSize.setHeight(oldGeometry.height());
+ }
+
+ // Hide the window before we change the geometry to avoid multiple resize
+ // events and wrong window state.
+ const bool wasVisible = q->isVisible();
+ if (wasVisible)
+ q->setVisible(false);
+
+ // Show the internal widget if it was hidden by us.
+ if (baseWidget && isWidgetHiddenByUs) {
+ baseWidget->show();
+ isWidgetHiddenByUs = false;
+ }
+
+ updateGeometryConstraints();
+
+ if (wasVisible) {
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mBar = menuBar())
+ showButtonsInMenuBar(mBar);
+ else
+#endif
+ if (!controlContainer)
+ controlContainer = new ControlContainer(q);
+ }
+
+ QWidget *parent = q->parentWidget();
+ QRect availableRect = parent->contentsRect();
+
+ // Adjust geometry if the sub-window is inside a scroll area.
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent->parentWidget());
+ if (scrollArea && scrollArea->viewport() == parent) {
+ QScrollBar *hbar = scrollArea->horizontalScrollBar();
+ QScrollBar *vbar = scrollArea->verticalScrollBar();
+ const int xOffset = hbar ? hbar->value() : 0;
+ const int yOffset = vbar ? vbar->value() : 0;
+ availableRect.adjust(-xOffset, -yOffset, -xOffset, -yOffset);
+ oldGeometry.adjust(xOffset, yOffset, xOffset, yOffset);
+ }
+
+ setNewGeometry(&availableRect);
+ // QWidget::setGeometry will reset Qt::WindowMaximized so we have to update it here.
+ ensureWindowState(Qt::WindowMaximized);
+
+ if (wasVisible)
+ q->setVisible(true);
+
+ resizeEnabled = false;
+ moveEnabled = false;
+
+#ifndef QT_NO_ACTION
+ setEnabled(MoveAction, moveEnabled);
+ setEnabled(MaximizeAction, false);
+ setEnabled(MinimizeAction, true);
+ setEnabled(RestoreAction, true);
+ setEnabled(ResizeAction, resizeEnabled);
+#endif // QT_NO_ACTION
+
+ Q_ASSERT(q->windowState() & Qt::WindowMaximized);
+ Q_ASSERT(!(q->windowState() & Qt::WindowMinimized));
+
+ restoreFocus();
+ updateMask();
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setActive(bool activate, bool changeFocus)
+{
+ Q_Q(QMdiSubWindow);
+ if (!parent || !activationEnabled)
+ return;
+
+ if (activate && !isActive && q->isEnabled()) {
+ isActive = true;
+ isExplicitlyDeactivated = false;
+ Qt::WindowStates oldWindowState = q->windowState();
+ ensureWindowState(Qt::WindowActive);
+ emit q->aboutToActivate();
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mBar = menuBar())
+ showButtonsInMenuBar(mBar);
+#endif
+ Q_ASSERT(isActive);
+ emit q->windowStateChanged(oldWindowState, q->windowState());
+ } else if (!activate && isActive) {
+ isActive = false;
+ Qt::WindowStates oldWindowState = q->windowState();
+ q->overrideWindowState(q->windowState() & ~Qt::WindowActive);
+ if (changeFocus) {
+ QWidget *focusWidget = QApplication::focusWidget();
+ if (focusWidget && (focusWidget == q || q->isAncestorOf(focusWidget)))
+ focusWidget->clearFocus();
+ }
+ if (baseWidget)
+ baseWidget->overrideWindowState(baseWidget->windowState() & ~Qt::WindowActive);
+ Q_ASSERT(!isActive);
+ emit q->windowStateChanged(oldWindowState, q->windowState());
+ }
+
+ if (activate && isActive && q->isEnabled() && !q->hasFocus()
+ && !q->isAncestorOf(QApplication::focusWidget())) {
+ if (changeFocus)
+ setFocusWidget();
+ ensureWindowState(Qt::WindowActive);
+ }
+
+ int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
+ int titleBarHeight = this->titleBarHeight();
+ QRegion windowDecoration = QRegion(0, 0, q->width(), q->height());
+ windowDecoration -= QRegion(frameWidth, titleBarHeight, q->width() - 2 * frameWidth,
+ q->height() - titleBarHeight - frameWidth);
+
+ // Make sure we don't use cached style options if we get
+ // resize events right before activation/deactivation.
+ if (resizeTimerId != -1) {
+ q->killTimer(resizeTimerId);
+ resizeTimerId = -1;
+ updateDirtyRegions();
+ }
+
+ q->update(windowDecoration);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::processClickedSubControl()
+{
+ Q_Q(QMdiSubWindow);
+ switch (activeSubControl) {
+ case QStyle::SC_TitleBarContextHelpButton:
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::enterWhatsThisMode();
+#endif
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ q->showShaded();
+ hoveredSubControl = QStyle::SC_TitleBarUnshadeButton;
+ break;
+ case QStyle::SC_TitleBarUnshadeButton:
+ if (q->isShaded())
+ hoveredSubControl = QStyle::SC_TitleBarShadeButton;
+ q->showNormal();
+ break;
+ case QStyle::SC_TitleBarMinButton:
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(q->style())) {
+ if (q->isMinimized())
+ q->showNormal();
+ else
+ q->showMinimized();
+ break;
+ }
+#endif
+ q->showMinimized();
+ break;
+ case QStyle::SC_TitleBarNormalButton:
+ if (q->isShaded())
+ hoveredSubControl = QStyle::SC_TitleBarMinButton;
+ q->showNormal();
+ break;
+ case QStyle::SC_TitleBarMaxButton:
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(q->style())) {
+ if (q->isMaximized())
+ q->showNormal();
+ else
+ q->showMaximized();
+ break;
+ }
+#endif
+ q->showMaximized();
+ break;
+ case QStyle::SC_TitleBarCloseButton:
+ q->close();
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+QRegion QMdiSubWindowPrivate::getRegion(Operation operation) const
+{
+ Q_Q(const QMdiSubWindow);
+ int width = q->width();
+ int height = q->height();
+ int titleBarHeight = this->titleBarHeight();
+ int frameWidth = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
+ int cornerConst = titleBarHeight - frameWidth;
+ int titleBarConst = 2 * titleBarHeight;
+
+ if (operation == Move) {
+ QStyleOptionTitleBar titleBarOptions = this->titleBarOptions();
+ QRegion move(frameWidth, frameWidth, width - 2 * frameWidth, cornerConst);
+ // Depending on which window flags are set, activated sub controllers will
+ // be subtracted from the 'move' region.
+ for (int i = 0; i < NumSubControls; ++i) {
+ if (SubControls[i] == QStyle::SC_TitleBarLabel)
+ continue;
+ move -= QRegion(q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
+ SubControls[i]));
+ }
+ return move;
+ }
+
+ QRegion region;
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(q->style()))
+ return region;
+#endif
+
+ switch (operation) {
+ case TopResize:
+ region = QRegion(titleBarHeight, 0, width - titleBarConst, frameWidth);
+ break;
+ case BottomResize:
+ region = QRegion(titleBarHeight, height - frameWidth, width - titleBarConst, frameWidth);
+ break;
+ case LeftResize:
+ region = QRegion(0, titleBarHeight, frameWidth, height - titleBarConst);
+ break;
+ case RightResize:
+ region = QRegion(width - frameWidth, titleBarHeight, frameWidth, height - titleBarConst);
+ break;
+ case TopLeftResize:
+ region = QRegion(0, 0, titleBarHeight, titleBarHeight)
+ - QRegion(frameWidth, frameWidth, cornerConst, cornerConst);
+ break;
+ case TopRightResize:
+ region = QRegion(width - titleBarHeight, 0, titleBarHeight, titleBarHeight)
+ - QRegion(width - titleBarHeight, frameWidth, cornerConst, cornerConst);
+ break;
+ case BottomLeftResize:
+ region = QRegion(0, height - titleBarHeight, titleBarHeight, titleBarHeight)
+ - QRegion(frameWidth, height - titleBarHeight, cornerConst, cornerConst);
+ break;
+ case BottomRightResize:
+ region = QRegion(width - titleBarHeight, height - titleBarHeight, titleBarHeight, titleBarHeight)
+ - QRegion(width - titleBarHeight, height - titleBarHeight, cornerConst, cornerConst);
+ break;
+ default:
+ break;
+ }
+
+ return region;
+}
+
+/*!
+ \internal
+*/
+QMdiSubWindowPrivate::Operation QMdiSubWindowPrivate::getOperation(const QPoint &pos) const
+{
+ OperationInfoMap::const_iterator it;
+ for (it = operationMap.constBegin(); it != operationMap.constEnd(); ++it)
+ if (it.value().region.contains(pos))
+ return it.key();
+ return None;
+}
+
+extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*);
+
+/*!
+ \internal
+*/
+QStyleOptionTitleBar QMdiSubWindowPrivate::titleBarOptions() const
+{
+ Q_Q(const QMdiSubWindow);
+ QStyleOptionTitleBar titleBarOptions;
+ titleBarOptions.initFrom(q);
+ if (activeSubControl != QStyle::SC_None) {
+ if (hoveredSubControl == activeSubControl) {
+ titleBarOptions.state |= QStyle::State_Sunken;
+ titleBarOptions.activeSubControls = activeSubControl;
+ }
+ } else if (autoRaise() && hoveredSubControl != QStyle::SC_None
+ && hoveredSubControl != QStyle::SC_TitleBarLabel) {
+ titleBarOptions.state |= QStyle::State_MouseOver;
+ titleBarOptions.activeSubControls = hoveredSubControl;
+ } else {
+ titleBarOptions.state &= ~QStyle::State_MouseOver;
+ titleBarOptions.activeSubControls = QStyle::SC_None;
+ }
+
+ titleBarOptions.subControls = QStyle::SC_All;
+ titleBarOptions.titleBarFlags = q->windowFlags();
+ titleBarOptions.titleBarState = q->windowState();
+ titleBarOptions.palette = titleBarPalette;
+ titleBarOptions.icon = menuIcon;
+
+ if (isActive) {
+ titleBarOptions.state |= QStyle::State_Active;
+ titleBarOptions.titleBarState |= QStyle::State_Active;
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
+ } else {
+ titleBarOptions.state &= ~QStyle::State_Active;
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
+ }
+
+ int border = hasBorder(titleBarOptions) ? 4 : 0;
+ int paintHeight = titleBarHeight(titleBarOptions);
+ paintHeight -= q->isMinimized() ? 2 * border : border;
+ titleBarOptions.rect = QRect(border, border, q->width() - 2 * border, paintHeight);
+
+ if (!windowTitle.isEmpty()) {
+ // Set the text here before asking for the width of the title bar label
+ // in case people uses the actual text to calculate the width.
+ titleBarOptions.text = windowTitle;
+ titleBarOptions.fontMetrics = QFontMetrics(font);
+ int width = q->style()->subControlRect(QStyle::CC_TitleBar, &titleBarOptions,
+ QStyle::SC_TitleBarLabel, q).width();
+ // Set elided text if we don't have enough space for the entire title.
+ titleBarOptions.text = titleBarOptions.fontMetrics.elidedText(windowTitle, Qt::ElideRight, width);
+ }
+ return titleBarOptions;
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::ensureWindowState(Qt::WindowState state)
+{
+ Q_Q(QMdiSubWindow);
+ Qt::WindowStates windowStates = q->windowState() | state;
+ switch (state) {
+ case Qt::WindowMinimized:
+ windowStates &= ~Qt::WindowMaximized;
+ windowStates &= ~Qt::WindowNoState;
+ break;
+ case Qt::WindowMaximized:
+ windowStates &= ~Qt::WindowMinimized;
+ windowStates &= ~Qt::WindowNoState;
+ break;
+ case Qt::WindowNoState:
+ windowStates &= ~Qt::WindowMinimized;
+ windowStates &= ~Qt::WindowMaximized;
+ break;
+ default:
+ break;
+ }
+ if (baseWidget) {
+ if (!(baseWidget->windowState() & Qt::WindowActive) && windowStates & Qt::WindowActive)
+ baseWidget->overrideWindowState(windowStates & ~Qt::WindowActive);
+ else
+ baseWidget->overrideWindowState(windowStates);
+ }
+ q->overrideWindowState(windowStates);
+}
+
+/*!
+ \internal
+*/
+int QMdiSubWindowPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
+{
+ Q_Q(const QMdiSubWindow);
+ if (!parent || q->windowFlags() & Qt::FramelessWindowHint
+ || (q->isMaximized() && !drawTitleBarWhenMaximized())) {
+ return 0;
+ }
+
+ int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options, q);
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ // ### Fix mac style, the +4 pixels hack is not necessary anymore
+ if (qobject_cast<QMacStyle *>(q->style()))
+ height -= 4;
+#endif
+ if (hasBorder(options))
+ height += q->isMinimized() ? 8 : 4;
+ return height;
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::sizeParameters(int *margin, int *minWidth) const
+{
+ Q_Q(const QMdiSubWindow);
+ Qt::WindowFlags flags = q->windowFlags();
+ if (!parent || flags & Qt::FramelessWindowHint) {
+ *margin = 0;
+ *minWidth = 0;
+ return;
+ }
+
+ if (q->isMaximized() && !drawTitleBarWhenMaximized())
+ *margin = 0;
+ else
+ *margin = q->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, q);
+
+ QStyleOptionTitleBar opt = this->titleBarOptions();
+ int tempWidth = 0;
+ for (int i = 0; i < NumSubControls; ++i) {
+ if (SubControls[i] == QStyle::SC_TitleBarLabel) {
+ tempWidth += 30;
+ continue;
+ }
+ QRect rect = q->style()->subControlRect(QStyle::CC_TitleBar, &opt, SubControls[i], q);
+ if (!rect.isValid())
+ continue;
+ tempWidth += rect.width();
+ }
+ *minWidth = tempWidth;
+}
+
+/*!
+ \internal
+*/
+bool QMdiSubWindowPrivate::drawTitleBarWhenMaximized() const
+{
+ Q_Q(const QMdiSubWindow);
+ if (q->window()->testAttribute(Qt::WA_CanHostQMdiSubWindowTitleBar))
+ return false;
+
+ if (isChildOfTabbedQMdiArea(q))
+ return false;
+
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) || defined(Q_WS_WINCE_WM)
+ return true;
+#else
+ if (q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q))
+ return true;
+#if defined(QT_NO_MENUBAR) || defined(QT_NO_MAINWINDOW)
+ return true;
+#else
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window());
+ if (!mainWindow || !qobject_cast<QMenuBar *>(mainWindow->menuWidget())
+ || mainWindow->menuWidget()->isHidden())
+ return true;
+
+ return isChildOfQMdiSubWindow(q);
+#endif
+#endif
+}
+
+#ifndef QT_NO_MENUBAR
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::showButtonsInMenuBar(QMenuBar *menuBar)
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(q->isMaximized() && !drawTitleBarWhenMaximized());
+
+ if (isChildOfTabbedQMdiArea(q))
+ return;
+
+ removeButtonsFromMenuBar();
+ if (!controlContainer)
+ controlContainer = new ControlContainer(q);
+
+ ignoreWindowTitleChange = true;
+ controlContainer->showButtonsInMenuBar(menuBar);
+ ignoreWindowTitleChange = false;
+
+ QWidget *topLevelWindow = q->window();
+ topLevelWindow->setWindowModified(q->isWindowModified());
+ topLevelWindow->installEventFilter(q);
+
+ int buttonHeight = 0;
+ if (controlContainer->controllerWidget())
+ buttonHeight = controlContainer->controllerWidget()->height();
+ else if (controlContainer->systemMenuLabel())
+ buttonHeight = controlContainer->systemMenuLabel()->height();
+
+ // This will rarely happen.
+ if (menuBar && menuBar->height() < buttonHeight
+ && topLevelWindow->layout()) {
+ // Make sure topLevelWindow->contentsRect returns correct geometry.
+ // topLevelWidget->updateGeoemtry will not do the trick here since it will post the event.
+ QEvent event(QEvent::LayoutRequest);
+ QApplication::sendEvent(topLevelWindow, &event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::removeButtonsFromMenuBar()
+{
+ Q_Q(QMdiSubWindow);
+
+ if (!controlContainer || isChildOfTabbedQMdiArea(q))
+ return;
+
+ QMenuBar *currentMenuBar = 0;
+#ifndef QT_NO_MAINWINDOW
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q->window())) {
+ // NB! We can't use menuBar() here because that one will actually create
+ // a menubar for us if not set. That's not what we want :-)
+ currentMenuBar = qobject_cast<QMenuBar *>(mainWindow->menuWidget());
+ }
+#endif
+
+ ignoreWindowTitleChange = true;
+ controlContainer->removeButtonsFromMenuBar(currentMenuBar);
+ ignoreWindowTitleChange = false;
+
+ QWidget *topLevelWindow = q->window();
+ topLevelWindow->removeEventFilter(q);
+ if (baseWidget && !drawTitleBarWhenMaximized())
+ topLevelWindow->setWindowModified(false);
+ originalTitle = QString::null;
+}
+
+#endif // QT_NO_MENUBAR
+
+void QMdiSubWindowPrivate::updateWindowTitle(bool isRequestFromChild)
+{
+ Q_Q(QMdiSubWindow);
+ if (isRequestFromChild && !q->windowTitle().isEmpty() && !lastChildWindowTitle.isEmpty()
+ && lastChildWindowTitle != q->windowTitle()) {
+ return;
+ }
+
+ QWidget *titleWidget = 0;
+ if (isRequestFromChild)
+ titleWidget = baseWidget;
+ else
+ titleWidget = q;
+ if (!titleWidget || titleWidget->windowTitle().isEmpty())
+ return;
+
+ ignoreWindowTitleChange = true;
+ q->setWindowTitle(titleWidget->windowTitle());
+ if (q->maximizedButtonsWidget())
+ setNewWindowTitle();
+ ignoreWindowTitleChange = false;
+}
+
+#ifndef QT_NO_RUBBERBAND
+void QMdiSubWindowPrivate::enterRubberBandMode()
+{
+ Q_Q(QMdiSubWindow);
+ if (q->isMaximized())
+ return;
+ Q_ASSERT(oldGeometry.isValid());
+ Q_ASSERT(parent);
+ if (!rubberBand) {
+ rubberBand = new QRubberBand(QRubberBand::Rectangle, q->parentWidget());
+ // For accessibility to identify this special widget.
+ rubberBand->setObjectName(QLatin1String("qt_rubberband"));
+ }
+ QPoint rubberBandPos = q->mapToParent(QPoint(0, 0));
+ rubberBand->setGeometry(rubberBandPos.x(), rubberBandPos.y(),
+ oldGeometry.width(), oldGeometry.height());
+ rubberBand->show();
+ isInRubberBandMode = true;
+ q->grabMouse();
+}
+
+void QMdiSubWindowPrivate::leaveRubberBandMode()
+{
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(rubberBand);
+ Q_ASSERT(isInRubberBandMode);
+ q->releaseMouse();
+ isInRubberBandMode = false;
+ q->setGeometry(rubberBand->geometry());
+ rubberBand->hide();
+ currentOperation = None;
+}
+#endif // QT_NO_RUBBERBAND
+
+// Taken from the old QWorkspace (::readColors())
+QPalette QMdiSubWindowPrivate::desktopPalette() const
+{
+ Q_Q(const QMdiSubWindow);
+ QPalette newPalette = q->palette();
+
+ bool colorsInitialized = false;
+#ifdef Q_WS_WIN // ask system properties on windows
+#ifndef SPI_GETGRADIENTCAPTIONS
+#define SPI_GETGRADIENTCAPTIONS 0x1008
+#endif
+#ifndef COLOR_GRADIENTACTIVECAPTION
+#define COLOR_GRADIENTACTIVECAPTION 27
+#endif
+#ifndef COLOR_GRADIENTINACTIVECAPTION
+#define COLOR_GRADIENTINACTIVECAPTION 28
+#endif
+ if (QApplication::desktopSettingsAware()) {
+ newPalette.setColor(QPalette::Active, QPalette::Highlight,
+ colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
+ newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
+ colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
+ newPalette.setColor(QPalette::Active, QPalette::HighlightedText,
+ colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
+ newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
+
+ colorsInitialized = true;
+ BOOL hasGradient = false;
+ SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &hasGradient, 0);
+
+ if (hasGradient) {
+ newPalette.setColor(QPalette::Active, QPalette::Base,
+ colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
+ newPalette.setColor(QPalette::Inactive, QPalette::Base,
+ colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
+ } else {
+ newPalette.setColor(QPalette::Active, QPalette::Base,
+ newPalette.color(QPalette::Active, QPalette::Highlight));
+ newPalette.setColor(QPalette::Inactive, QPalette::Base,
+ newPalette.color(QPalette::Inactive, QPalette::Highlight));
+ }
+ }
+#endif // Q_WS_WIN
+ if (!colorsInitialized) {
+ newPalette.setColor(QPalette::Active, QPalette::Highlight,
+ newPalette.color(QPalette::Active, QPalette::Highlight));
+ newPalette.setColor(QPalette::Active, QPalette::Base,
+ newPalette.color(QPalette::Active, QPalette::Highlight));
+ newPalette.setColor(QPalette::Inactive, QPalette::Highlight,
+ newPalette.color(QPalette::Inactive, QPalette::Dark));
+ newPalette.setColor(QPalette::Inactive, QPalette::Base,
+ newPalette.color(QPalette::Inactive, QPalette::Dark));
+ newPalette.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ newPalette.color(QPalette::Inactive, QPalette::Window));
+ }
+
+ return newPalette;
+}
+
+void QMdiSubWindowPrivate::updateActions()
+{
+ Qt::WindowFlags windowFlags = q_func()->windowFlags();
+ // Hide all
+ for (int i = 0; i < NumWindowStateActions; ++i)
+ setVisible(WindowStateAction(i), false);
+
+ if (windowFlags & Qt::FramelessWindowHint)
+ return;
+
+ setVisible(StayOnTopAction, true);
+ setVisible(MoveAction, moveEnabled);
+ setVisible(ResizeAction, resizeEnabled);
+
+ // CloseAction
+ if (windowFlags & Qt::WindowSystemMenuHint)
+ setVisible(CloseAction, true);
+
+ // RestoreAction
+ if (windowFlags & (Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint))
+ setVisible(RestoreAction, true);
+
+ // MinimizeAction
+ if (windowFlags & Qt::WindowMinimizeButtonHint)
+ setVisible(MinimizeAction, true);
+
+ // MaximizeAction
+ if (windowFlags & Qt::WindowMaximizeButtonHint)
+ setVisible(MaximizeAction, true);
+}
+
+void QMdiSubWindowPrivate::setFocusWidget()
+{
+ Q_Q(QMdiSubWindow);
+ if (!baseWidget) {
+ q->setFocus();
+ return;
+ }
+
+ // This will give focus to the next child if possible, otherwise
+ // do nothing, hence it's not possible to tab between windows with
+ // just hitting tab (unless Qt::TabFocus is removed from the focus policy).
+ if (focusInReason == Qt::TabFocusReason) {
+ q->focusNextChild();
+ return;
+ }
+
+ // Same as above, but gives focus to the previous child.
+ if (focusInReason == Qt::BacktabFocusReason) {
+ q->focusPreviousChild();
+ return;
+ }
+
+ if (QWidget *focusWidget = baseWidget->focusWidget()) {
+ if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget)
+ && focusWidget->isVisible() && !q->isMinimized()
+ && focusWidget->focusPolicy() != Qt::NoFocus) {
+ focusWidget->setFocus();
+ } else {
+ q->setFocus();
+ }
+ return;
+ }
+
+ QWidget *focusWidget = q->nextInFocusChain();
+ while (focusWidget && focusWidget != q && focusWidget->focusPolicy() == Qt::NoFocus)
+ focusWidget = focusWidget->nextInFocusChain();
+ if (focusWidget && q->isAncestorOf(focusWidget))
+ focusWidget->setFocus();
+ else if (baseWidget->focusPolicy() != Qt::NoFocus)
+ baseWidget->setFocus();
+ else if (!q->hasFocus())
+ q->setFocus();
+}
+
+void QMdiSubWindowPrivate::restoreFocus()
+{
+ if (!restoreFocusWidget)
+ return;
+ if (!restoreFocusWidget->hasFocus() && q_func()->isAncestorOf(restoreFocusWidget)
+ && restoreFocusWidget->isVisible()
+ && restoreFocusWidget->focusPolicy() != Qt::NoFocus) {
+ restoreFocusWidget->setFocus();
+ }
+ restoreFocusWidget = 0;
+}
+
+/*!
+ \internal
+ ### Please add QEvent::WindowFlagsChange event
+*/
+void QMdiSubWindowPrivate::setWindowFlags(Qt::WindowFlags windowFlags)
+{
+ Q_Q(QMdiSubWindow);
+ if (!parent) {
+ q->setWindowFlags(windowFlags);
+ return;
+ }
+
+ Qt::WindowFlags windowType = windowFlags & Qt::WindowType_Mask;
+ if (windowType == Qt::Dialog || windowFlags & Qt::MSWindowsFixedSizeDialogHint)
+ windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
+
+ // Set standard flags if none of the customize flags are set
+ if (!(windowFlags & CustomizeWindowFlags))
+ windowFlags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
+ else if (windowFlags & Qt::FramelessWindowHint && windowFlags & Qt::WindowStaysOnTopHint)
+ windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
+ else if (windowFlags & Qt::FramelessWindowHint)
+ windowFlags = Qt::FramelessWindowHint;
+
+ windowFlags &= ~windowType;
+ windowFlags |= Qt::SubWindow;
+
+#ifndef QT_NO_ACTION
+ if (QAction *stayOnTopAction = actions[QMdiSubWindowPrivate::StayOnTopAction]) {
+ if (windowFlags & Qt::WindowStaysOnTopHint)
+ stayOnTopAction->setChecked(true);
+ else
+ stayOnTopAction->setChecked(false);
+ }
+#endif
+
+#ifndef QT_NO_SIZEGRIP
+ if ((windowFlags & Qt::FramelessWindowHint) && sizeGrip)
+ delete sizeGrip;
+#endif
+
+ q->setWindowFlags(windowFlags);
+ updateGeometryConstraints();
+ updateActions();
+ QSize currentSize = q->size();
+ if (q->isVisible() && (currentSize.width() < internalMinimumSize.width()
+ || currentSize.height() < internalMinimumSize.height())) {
+ q->resize(currentSize.expandedTo(internalMinimumSize));
+ }
+}
+
+void QMdiSubWindowPrivate::setVisible(WindowStateAction action, bool visible)
+{
+#ifndef QT_NO_ACTION
+ if (actions[action])
+ actions[action]->setVisible(visible);
+#endif
+
+ Q_Q(QMdiSubWindow);
+ if (!controlContainer)
+ controlContainer = new ControlContainer(q);
+
+ if (ControllerWidget *ctrlWidget = qobject_cast<ControllerWidget *>
+ (controlContainer->controllerWidget())) {
+ ctrlWidget->setControlVisible(action, visible);
+ }
+}
+
+#ifndef QT_NO_ACTION
+void QMdiSubWindowPrivate::setEnabled(WindowStateAction action, bool enable)
+{
+ if (actions[action])
+ actions[action]->setEnabled(enable);
+}
+
+#ifndef QT_NO_MENU
+void QMdiSubWindowPrivate::addToSystemMenu(WindowStateAction action, const QString &text,
+ const char *slot)
+{
+ if (!systemMenu)
+ return;
+ actions[action] = systemMenu->addAction(text, q_func(), slot);
+}
+#endif
+#endif // QT_NO_ACTION
+
+/*!
+ \internal
+*/
+QSize QMdiSubWindowPrivate::iconSize() const
+{
+ Q_Q(const QMdiSubWindow);
+ if (!parent || q->windowFlags() & Qt::FramelessWindowHint)
+ return QSize(-1, -1);
+ return QSize(q->style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, q), titleBarHeight());
+}
+
+#ifndef QT_NO_SIZEGRIP
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setSizeGrip(QSizeGrip *newSizeGrip)
+{
+ Q_Q(QMdiSubWindow);
+ if (!newSizeGrip || sizeGrip || q->windowFlags() & Qt::FramelessWindowHint)
+ return;
+
+ if (layout && layout->indexOf(newSizeGrip) != -1)
+ return;
+ newSizeGrip->setFixedSize(newSizeGrip->sizeHint());
+ bool putSizeGripInLayout = layout ? true : false;
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(q->style()))
+ putSizeGripInLayout = false;
+#endif
+ if (putSizeGripInLayout) {
+ layout->addWidget(newSizeGrip);
+ layout->setAlignment(newSizeGrip, Qt::AlignBottom | Qt::AlignRight);
+ } else {
+ newSizeGrip->setParent(q);
+ newSizeGrip->move(q->isLeftToRight() ? q->width() - newSizeGrip->width() : 0,
+ q->height() - newSizeGrip->height());
+ sizeGrip = newSizeGrip;
+ }
+ newSizeGrip->raise();
+ updateGeometryConstraints();
+ newSizeGrip->installEventFilter(q);
+}
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::setSizeGripVisible(bool visible) const
+{
+ // See if we can find any size grips
+ QList<QSizeGrip *> sizeGrips = q_func()->findChildren<QSizeGrip *>();
+ foreach (QSizeGrip *grip, sizeGrips)
+ grip->setVisible(visible);
+}
+
+#endif // QT_NO_SIZEGRIP
+
+/*!
+ \internal
+*/
+void QMdiSubWindowPrivate::updateInternalWindowTitle()
+{
+ Q_Q(QMdiSubWindow);
+ if (q->isWindowModified()) {
+ windowTitle = q->windowTitle();
+ windowTitle.replace(QLatin1String("[*]"), QLatin1String("*"));
+ } else {
+ windowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
+ }
+ q->update(0, 0, q->width(), titleBarHeight());
+}
+
+/*!
+ Constructs a new QMdiSubWindow widget. The \a parent and \a
+ flags arguments are passed to QWidget's constructor.
+
+ Instead of using addSubWindow(), it is also simply possible to
+ use setParent() when you add the subwindow to a QMdiArea.
+
+ Note that only \l{QMdiSubWindow}s can be set as children of
+ QMdiArea; you cannot, for instance, write:
+
+ \badcode
+ QMdiArea mdiArea;
+ QTextEdit editor(&mdiArea); // invalid child widget
+ \endcode
+
+ \sa QMdiArea::addSubWindow()
+*/
+QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*new QMdiSubWindowPrivate, parent, 0)
+{
+ Q_D(QMdiSubWindow);
+#ifndef QT_NO_MENU
+ d->createSystemMenu();
+ addActions(d->systemMenu->actions());
+#endif
+ d->setWindowFlags(flags);
+ setBackgroundRole(QPalette::Window);
+ setAutoFillBackground(true);
+ setMouseTracking(true);
+ setLayout(new QVBoxLayout);
+ setFocusPolicy(Qt::StrongFocus);
+ layout()->setMargin(0);
+ d->updateGeometryConstraints();
+ setAttribute(Qt::WA_Resized, false);
+ d->titleBarPalette = d->desktopPalette();
+ d->font = QApplication::font("QWorkspaceTitleBar");
+ // We don't want the menu icon by default on mac.
+#ifndef Q_WS_MAC
+ if (windowIcon().isNull())
+ d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
+ else
+ d->menuIcon = windowIcon();
+#endif
+ connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),
+ this, SLOT(_q_processFocusChanged(QWidget*,QWidget*)));
+}
+
+/*!
+ Destroys the subwindow.
+
+ \sa QMdiArea::removeSubWindow()
+*/
+QMdiSubWindow::~QMdiSubWindow()
+{
+ Q_D(QMdiSubWindow);
+#ifndef QT_NO_MENUBAR
+ d->removeButtonsFromMenuBar();
+#endif
+ d->setActive(false);
+}
+
+/*!
+ Sets \a widget as the internal widget of this subwindow. The
+ internal widget is displayed in the center of the subwindow
+ beneath the title bar.
+
+ QMdiSubWindow takes temporary ownership of \a widget; you do
+ not have to delete it. Any existing internal widget will be
+ removed and reparented to the root window.
+
+ \sa widget()
+*/
+void QMdiSubWindow::setWidget(QWidget *widget)
+{
+ Q_D(QMdiSubWindow);
+ if (!widget) {
+ d->removeBaseWidget();
+ return;
+ }
+
+ if (widget == d->baseWidget) {
+ qWarning("QMdiSubWindow::setWidget: widget is already set");
+ return;
+ }
+
+ bool wasResized = testAttribute(Qt::WA_Resized);
+ d->removeBaseWidget();
+
+ if (QLayout *layout = this->layout())
+ layout->addWidget(widget);
+ else
+ widget->setParent(this);
+
+#ifndef QT_NO_SIZEGRIP
+ QSizeGrip *sizeGrip = widget->findChild<QSizeGrip *>();
+ if (sizeGrip)
+ sizeGrip->installEventFilter(this);
+ if (d->sizeGrip)
+ d->sizeGrip->raise();
+#endif
+
+ d->baseWidget = widget;
+ d->baseWidget->installEventFilter(this);
+
+ d->ignoreWindowTitleChange = true;
+ bool isWindowModified = this->isWindowModified();
+ if (windowTitle().isEmpty()) {
+ d->updateWindowTitle(true);
+ isWindowModified = d->baseWidget->isWindowModified();
+ }
+ if (!this->isWindowModified() && isWindowModified
+ && windowTitle().contains(QLatin1String("[*]"))) {
+ setWindowModified(isWindowModified);
+ }
+ d->lastChildWindowTitle = d->baseWidget->windowTitle();
+ d->ignoreWindowTitleChange = false;
+
+ if (windowIcon().isNull() && !d->baseWidget->windowIcon().isNull())
+ setWindowIcon(d->baseWidget->windowIcon());
+
+ d->updateGeometryConstraints();
+ if (!wasResized && testAttribute(Qt::WA_Resized))
+ setAttribute(Qt::WA_Resized, false);
+}
+
+/*!
+ Returns the current internal widget.
+
+ \sa setWidget()
+*/
+QWidget *QMdiSubWindow::widget() const
+{
+ return d_func()->baseWidget;
+}
+
+
+/*!
+ \internal
+*/
+QWidget *QMdiSubWindow::maximizedButtonsWidget() const
+{
+ Q_D(const QMdiSubWindow);
+ if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
+ && !isChildOfTabbedQMdiArea(this)) {
+ return d->controlContainer->controllerWidget();
+ }
+ return 0;
+}
+
+/*!
+ \internal
+*/
+QWidget *QMdiSubWindow::maximizedSystemMenuIconWidget() const
+{
+ Q_D(const QMdiSubWindow);
+ if (isVisible() && d->controlContainer && isMaximized() && !d->drawTitleBarWhenMaximized()
+ && !isChildOfTabbedQMdiArea(this)) {
+ return d->controlContainer->systemMenuLabel();
+ }
+ return 0;
+}
+
+/*!
+ Returns true if this window is shaded; otherwise returns false.
+
+ A window is shaded if it is collapsed so that only the title bar is
+ visible.
+*/
+bool QMdiSubWindow::isShaded() const
+{
+ return d_func()->isShadeMode;
+}
+
+/*!
+ If \a on is true, \a option is enabled on the subwindow; otherwise it is
+ disabled. See SubWindowOption for the effect of each option.
+
+ \sa SubWindowOption, testOption()
+*/
+void QMdiSubWindow::setOption(SubWindowOption option, bool on)
+{
+ Q_D(QMdiSubWindow);
+ if (on && !(d->options & option))
+ d->options |= option;
+ else if (!on && (d->options & option))
+ d->options &= ~option;
+
+#ifndef QT_NO_RUBBERBAND
+ if ((option & (RubberBandResize | RubberBandMove)) && !on && d->isInRubberBandMode)
+ d->leaveRubberBandMode();
+#endif
+}
+
+/*!
+ Returns true if \a option is enabled; otherwise returns false.
+
+ \sa SubWindowOption, setOption()
+*/
+bool QMdiSubWindow::testOption(SubWindowOption option) const
+{
+ return d_func()->options & option;
+}
+
+/*!
+ \property QMdiSubWindow::keyboardSingleStep
+ \brief sets how far a widget should move or resize when using the
+ keyboard arrow keys.
+
+ When in keyboard-interactive mode, you can use the arrow and page keys to
+ either move or resize the window. This property controls the arrow keys.
+ The common way to enter keyboard interactive mode is to enter the
+ subwindow menu, and select either "resize" or "move".
+
+ The default keyboard single step value is 5 pixels.
+
+ \sa keyboardPageStep
+*/
+int QMdiSubWindow::keyboardSingleStep() const
+{
+ return d_func()->keyboardSingleStep;
+}
+
+void QMdiSubWindow::setKeyboardSingleStep(int step)
+{
+ // Haven't done any boundary check here since negative step only
+ // means inverted behavior, which is OK if the user want it.
+ // A step equal to zero means "do nothing".
+ d_func()->keyboardSingleStep = step;
+}
+
+/*!
+ \property QMdiSubWindow::keyboardPageStep
+ \brief sets how far a widget should move or resize when using the
+ keyboard page keys.
+
+ When in keyboard-interactive mode, you can use the arrow and page keys to
+ either move or resize the window. This property controls the page
+ keys. The common way to enter keyboard interactive mode is to enter the
+ subwindow menu, and select either "resize" or "move".
+
+ The default keyboard page step value is 20 pixels.
+
+ \sa keyboardSingleStep
+*/
+int QMdiSubWindow::keyboardPageStep() const
+{
+ return d_func()->keyboardPageStep;
+}
+
+void QMdiSubWindow::setKeyboardPageStep(int step)
+{
+ // Haven't done any boundary check here since negative step only
+ // means inverted behavior, which is OK if the user want it.
+ // A step equal to zero means "do nothing".
+ d_func()->keyboardPageStep = step;
+}
+
+#ifndef QT_NO_MENU
+/*!
+ Sets \a systemMenu as the current system menu for this subwindow.
+
+ By default, each QMdiSubWindow has a standard system menu.
+
+ QActions for the system menu created by QMdiSubWindow will
+ automatically be updated depending on the current window state;
+ e.g., the minimize action will be disabled after the window is
+ minimized.
+
+ QActions added by the user are not updated by QMdiSubWindow.
+
+ QMdiSubWindow takes ownership of \a systemMenu; you do not have to
+ delete it. Any existing menus will be deleted.
+
+ \sa systemMenu(), showSystemMenu()
+*/
+void QMdiSubWindow::setSystemMenu(QMenu *systemMenu)
+{
+ Q_D(QMdiSubWindow);
+ if (systemMenu && systemMenu == d->systemMenu) {
+ qWarning("QMdiSubWindow::setSystemMenu: system menu is already set");
+ return;
+ }
+
+ if (d->systemMenu) {
+ delete d->systemMenu;
+ d->systemMenu = 0;
+ }
+
+ if (!systemMenu)
+ return;
+
+ if (systemMenu->parent() != this)
+ systemMenu->setParent(this);
+ d->systemMenu = systemMenu;
+}
+
+/*!
+ Returns a pointer to the current system menu, or zero if no system
+ menu is set. QMdiSubWindow provides a default system menu, but you can
+ also set the menu with setSystemMenu().
+
+ \sa setSystemMenu(), showSystemMenu()
+*/
+QMenu *QMdiSubWindow::systemMenu() const
+{
+ return d_func()->systemMenu;
+}
+
+/*!
+ Shows the system menu below the system menu icon in the title bar.
+
+ \sa setSystemMenu(), systemMenu()
+*/
+void QMdiSubWindow::showSystemMenu()
+{
+ Q_D(QMdiSubWindow);
+ if (!d->systemMenu)
+ return;
+
+ QPoint globalPopupPos;
+ if (QWidget *icon = maximizedSystemMenuIconWidget()) {
+ if (isLeftToRight())
+ globalPopupPos = icon->mapToGlobal(QPoint(0, icon->y() + icon->height()));
+ else
+ globalPopupPos = icon->mapToGlobal(QPoint(icon->width(), icon->y() + icon->height()));
+ } else {
+ if (isLeftToRight())
+ globalPopupPos = mapToGlobal(contentsRect().topLeft());
+ else // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top())
+ globalPopupPos = mapToGlobal(contentsRect().topRight()) + QPoint(1, 0);
+ }
+
+ // Adjust x() with -menuwidth in reverse mode.
+ if (isRightToLeft())
+ globalPopupPos -= QPoint(d->systemMenu->sizeHint().width(), 0);
+ d->systemMenu->installEventFilter(this);
+ d->systemMenu->popup(globalPopupPos);
+}
+#endif // QT_NO_MENU
+
+/*!
+ \since 4.4
+
+ Returns the area containing this sub-window, or 0 if there is none.
+
+ \sa QMdiArea::addSubWindow()
+*/
+QMdiArea *QMdiSubWindow::mdiArea() const
+{
+ QWidget *parent = parentWidget();
+ while (parent) {
+ if (QMdiArea *area = qobject_cast<QMdiArea *>(parent)) {
+ if (area->viewport() == parentWidget())
+ return area;
+ }
+ parent = parent->parentWidget();
+ }
+ return 0;
+}
+
+/*!
+ Calling this function makes the subwindow enter the shaded mode.
+ When the subwindow is shaded, only the title bar is visible.
+
+ Although shading is not supported by all styles, this function will
+ still show the subwindow as shaded, regardless of whether support
+ for shading is available. However, when used with styles without
+ shading support, the user will be unable to return from shaded mode
+ through the user interface (e.g., through a shade button in the title
+ bar).
+
+ \sa isShaded()
+*/
+void QMdiSubWindow::showShaded()
+{
+ if (!parent())
+ return;
+
+ Q_D(QMdiSubWindow);
+ // setMinimizeMode uses this function.
+ if (!d->isShadeRequestFromMinimizeMode && isShaded())
+ return;
+
+ d->isMaximizeMode = false;
+
+ QWidget *currentFocusWidget = QApplication::focusWidget();
+ if (!d->restoreFocusWidget && isAncestorOf(currentFocusWidget))
+ d->restoreFocusWidget = currentFocusWidget;
+
+ if (!d->isShadeRequestFromMinimizeMode) {
+ d->isShadeMode = true;
+ d->ensureWindowState(Qt::WindowMinimized);
+ }
+
+#ifndef QT_NO_MENUBAR
+ d->removeButtonsFromMenuBar();
+#endif
+
+ // showMinimized() will reset Qt::WindowActive, which makes sense
+ // for top level widgets, but in MDI it makes sense to have an
+ // active window which is minimized.
+ if (hasFocus() || isAncestorOf(currentFocusWidget))
+ d->ensureWindowState(Qt::WindowActive);
+
+#ifndef QT_NO_SIZEGRIP
+ d->setSizeGripVisible(false);
+#endif
+
+ if (!d->restoreSize.isValid() || d->isShadeMode) {
+ d->oldGeometry = geometry();
+ d->restoreSize.setWidth(d->oldGeometry.width());
+ d->restoreSize.setHeight(d->oldGeometry.height());
+ }
+
+ // Hide the window before we change the geometry to avoid multiple resize
+ // events and wrong window state.
+ const bool wasVisible = isVisible();
+ if (wasVisible)
+ setVisible(false);
+
+ d->updateGeometryConstraints();
+ // Update minimum size to internalMinimumSize if set by user.
+ if (!minimumSize().isNull()) {
+ d->userMinimumSize = minimumSize();
+ setMinimumSize(d->internalMinimumSize);
+ }
+ resize(d->internalMinimumSize);
+
+ // Hide the internal widget if not already hidden by the user.
+ if (d->baseWidget && !d->baseWidget->isHidden()) {
+ d->baseWidget->hide();
+ d->isWidgetHiddenByUs = true;
+ }
+
+ if (wasVisible)
+ setVisible(true);
+
+ d->setFocusWidget();
+ d->resizeEnabled = false;
+ d->moveEnabled = true;
+ d->updateDirtyRegions();
+ d->updateMask();
+
+#ifndef QT_NO_ACTION
+ d->setEnabled(QMdiSubWindowPrivate::MinimizeAction, false);
+ d->setEnabled(QMdiSubWindowPrivate::ResizeAction, d->resizeEnabled);
+ d->setEnabled(QMdiSubWindowPrivate::MaximizeAction, true);
+ d->setEnabled(QMdiSubWindowPrivate::RestoreAction, true);
+ d->setEnabled(QMdiSubWindowPrivate::MoveAction, d->moveEnabled);
+#endif
+}
+
+/*!
+ \reimp
+*/
+bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QMdiSubWindow);
+ if (!object)
+ return QWidget::eventFilter(object, event);
+
+#ifndef QT_NO_MENU
+ // System menu events.
+ if (d->systemMenu && d->systemMenu == object) {
+ if (event->type() == QEvent::MouseButtonDblClick) {
+ close();
+ } else if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ d->hoveredSubControl = d->getSubControl(mapFromGlobal(mouseEvent->globalPos()));
+ } else if (event->type() == QEvent::Hide) {
+ d->systemMenu->removeEventFilter(this);
+ d->activeSubControl = QStyle::SC_None;
+ update(QRegion(0, 0, width(), d->titleBarHeight()));
+ }
+ return QWidget::eventFilter(object, event);
+ }
+#endif
+
+#ifndef QT_NO_SIZEGRIP
+ if (object != d->baseWidget && parent() && qobject_cast<QSizeGrip *>(object)) {
+ if (event->type() != QEvent::MouseButtonPress || !testOption(QMdiSubWindow::RubberBandResize))
+ return QWidget::eventFilter(object, event);
+ const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ d->mousePressPosition = parentWidget()->mapFromGlobal(mouseEvent->globalPos());
+ d->oldGeometry = geometry();
+ d->currentOperation = isLeftToRight() ? QMdiSubWindowPrivate::BottomRightResize
+ : QMdiSubWindowPrivate::BottomLeftResize;
+#ifndef QT_NO_RUBBERBAND
+ d->enterRubberBandMode();
+#endif
+ return true;
+ }
+#endif
+
+ if (object != d->baseWidget && event->type() != QEvent::WindowTitleChange)
+ return QWidget::eventFilter(object, event);
+
+ switch (event->type()) {
+ case QEvent::Show:
+ d->setActive(true);
+ break;
+ case QEvent::ShowToParent:
+ if (!d->isWidgetHiddenByUs)
+ show();
+ break;
+ case QEvent::WindowStateChange: {
+ QWindowStateChangeEvent *changeEvent = static_cast<QWindowStateChangeEvent*>(event);
+ if (changeEvent->isOverride())
+ break;
+ Qt::WindowStates oldState = changeEvent->oldState();
+ Qt::WindowStates newState = d->baseWidget->windowState();
+ if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
+ showMinimized();
+ else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
+ showMaximized();
+ else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
+ showNormal();
+ break;
+ }
+ case QEvent::Enter:
+ d->currentOperation = QMdiSubWindowPrivate::None;
+ d->updateCursor();
+ break;
+ case QEvent::LayoutRequest:
+ d->updateGeometryConstraints();
+ break;
+ case QEvent::WindowTitleChange:
+ if (d->ignoreWindowTitleChange)
+ break;
+ if (object == d->baseWidget) {
+ d->updateWindowTitle(true);
+ d->lastChildWindowTitle = d->baseWidget->windowTitle();
+#ifndef QT_NO_MENUBAR
+ } else if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
+ ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
+ d->originalTitle = QString::null;
+ if (d->baseWidget && d->baseWidget->windowTitle() == windowTitle())
+ d->updateWindowTitle(true);
+ else
+ d->updateWindowTitle(false);
+#endif
+ }
+ break;
+ case QEvent::ModifiedChange: {
+ if (object != d->baseWidget)
+ break;
+ bool windowModified = d->baseWidget->isWindowModified();
+ if (!windowModified && d->baseWidget->windowTitle() != windowTitle())
+ break;
+ if (windowTitle().contains(QLatin1String("[*]")))
+ setWindowModified(windowModified);
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::eventFilter(object, event);
+}
+
+/*!
+ \reimp
+*/
+bool QMdiSubWindow::event(QEvent *event)
+{
+ Q_D(QMdiSubWindow);
+ switch (event->type()) {
+ case QEvent::StyleChange: {
+ bool wasShaded = isShaded();
+ bool wasMinimized = isMinimized();
+ bool wasMaximized = isMaximized();
+ ensurePolished();
+ setContentsMargins(0, 0, 0, 0);
+ if (wasMinimized || wasMaximized || wasShaded)
+ showNormal();
+ d->updateGeometryConstraints();
+ resize(d->internalMinimumSize.expandedTo(size()));
+ d->updateMask();
+ d->updateDirtyRegions();
+ if (wasShaded)
+ showShaded();
+ else if (wasMinimized)
+ showMinimized();
+ else if (wasMaximized)
+ showMaximized();
+ break;
+ }
+ case QEvent::ParentAboutToChange:
+ d->setActive(false);
+ break;
+ case QEvent::ParentChange: {
+ bool wasResized = testAttribute(Qt::WA_Resized);
+#ifndef QT_NO_MENUBAR
+ d->removeButtonsFromMenuBar();
+#endif
+ d->currentOperation = QMdiSubWindowPrivate::None;
+ d->activeSubControl = QStyle::SC_None;
+ d->hoveredSubControl = QStyle::SC_None;
+#ifndef QT_NO_RUBBERBAND
+ if (d->isInRubberBandMode)
+ d->leaveRubberBandMode();
+#endif
+ d->isShadeMode = false;
+ d->isMaximizeMode = false;
+ d->isWidgetHiddenByUs = false;
+ if (!parent()) {
+#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(style()))
+ delete d->sizeGrip;
+#endif
+ setOption(RubberBandResize, false);
+ setOption(RubberBandMove, false);
+ } else {
+ d->setWindowFlags(windowFlags());
+ }
+ setContentsMargins(0, 0, 0, 0);
+ d->updateGeometryConstraints();
+ d->updateCursor();
+ d->updateMask();
+ d->updateDirtyRegions();
+ d->updateActions();
+ if (!wasResized && testAttribute(Qt::WA_Resized))
+ setAttribute(Qt::WA_Resized, false);
+ break;
+ }
+ case QEvent::WindowActivate:
+ if (d->ignoreNextActivationEvent) {
+ d->ignoreNextActivationEvent = false;
+ break;
+ }
+ d->isExplicitlyDeactivated = false;
+ d->setActive(true);
+ break;
+ case QEvent::WindowDeactivate:
+ if (d->ignoreNextActivationEvent) {
+ d->ignoreNextActivationEvent = false;
+ break;
+ }
+ d->isExplicitlyDeactivated = true;
+ d->setActive(false);
+ break;
+ case QEvent::WindowTitleChange:
+ if (!d->ignoreWindowTitleChange)
+ d->updateWindowTitle(false);
+ d->updateInternalWindowTitle();
+ break;
+ case QEvent::ModifiedChange:
+ if (!windowTitle().contains(QLatin1String("[*]")))
+ break;
+#ifndef QT_NO_MENUBAR
+ if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
+ ->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
+ window()->setWindowModified(isWindowModified());
+ }
+#endif // QT_NO_MENUBAR
+ d->updateInternalWindowTitle();
+ break;
+ case QEvent::LayoutDirectionChange:
+ d->updateDirtyRegions();
+ break;
+ case QEvent::LayoutRequest:
+ d->updateGeometryConstraints();
+ break;
+ case QEvent::WindowIconChange:
+ d->menuIcon = windowIcon();
+ if (d->menuIcon.isNull())
+ d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, 0, this);
+ if (d->controlContainer)
+ d->controlContainer->updateWindowIcon(d->menuIcon);
+ if (!maximizedSystemMenuIconWidget())
+ update(0, 0, width(), d->titleBarHeight());
+ break;
+ case QEvent::PaletteChange:
+ d->titleBarPalette = d->desktopPalette();
+ break;
+ case QEvent::FontChange:
+ d->font = font();
+ break;
+#ifndef QT_NO_TOOLTIP
+ case QEvent::ToolTip:
+ showToolTip(static_cast<QHelpEvent *>(event), this, d->titleBarOptions(),
+ QStyle::CC_TitleBar, d->hoveredSubControl);
+ break;
+#endif
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::showEvent(QShowEvent *showEvent)
+{
+ Q_D(QMdiSubWindow);
+ if (!parent()) {
+ QWidget::showEvent(showEvent);
+ return;
+ }
+
+#if !defined(QT_NO_SIZEGRIP) && defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(style()) && !d->sizeGrip
+ && !(windowFlags() & Qt::FramelessWindowHint)) {
+ d->setSizeGrip(new QSizeGrip(0));
+ Q_ASSERT(d->sizeGrip);
+ if (isMinimized())
+ d->setSizeGripVisible(false);
+ else
+ d->setSizeGripVisible(true);
+ resize(size().expandedTo(d->internalMinimumSize));
+ }
+#endif
+
+ d->updateDirtyRegions();
+ // Show buttons in the menu bar if they're already not there.
+ // We want to do this when QMdiSubWindow becomes visible after being hidden.
+#ifndef QT_NO_MENUBAR
+ if (d->controlContainer) {
+ if (QMenuBar *menuBar = d->menuBar()) {
+ if (menuBar->cornerWidget(Qt::TopRightCorner) != maximizedButtonsWidget())
+ d->showButtonsInMenuBar(menuBar);
+ }
+ }
+#endif
+ d->setActive(true);
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::hideEvent(QHideEvent * /*hideEvent*/)
+{
+#ifndef QT_NO_MENUBAR
+ d_func()->removeButtonsFromMenuBar();
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::changeEvent(QEvent *changeEvent)
+{
+ if (!parent()) {
+ QWidget::changeEvent(changeEvent);
+ return;
+ }
+
+ if (changeEvent->type() != QEvent::WindowStateChange) {
+ QWidget::changeEvent(changeEvent);
+ return;
+ }
+
+ QWindowStateChangeEvent *event = static_cast<QWindowStateChangeEvent *>(changeEvent);
+ if (event->isOverride()) {
+ event->ignore();
+ return;
+ }
+
+ Qt::WindowStates oldState = event->oldState();
+ Qt::WindowStates newState = windowState();
+ if (oldState == newState) {
+ changeEvent->ignore();
+ return;
+ }
+
+ // QWidget ensures that the widget is visible _after_ setWindowState(),
+ // but we need to ensure that the widget is visible _before_
+ // setWindowState() returns.
+ Q_D(QMdiSubWindow);
+ if (!isVisible()) {
+ d->ensureWindowState(Qt::WindowNoState);
+ setVisible(true);
+ }
+
+ if (!d->oldGeometry.isValid())
+ d->oldGeometry = geometry();
+
+ if ((oldState & Qt::WindowActive) && (newState & Qt::WindowActive))
+ d->currentOperation = QMdiSubWindowPrivate::None;
+
+ if (!(oldState & Qt::WindowMinimized) && (newState & Qt::WindowMinimized))
+ d->setMinimizeMode();
+ else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized))
+ d->setMaximizeMode();
+ else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized)))
+ d->setNormalMode();
+
+ if (d->isActive)
+ d->ensureWindowState(Qt::WindowActive);
+ emit windowStateChanged(oldState, windowState());
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::closeEvent(QCloseEvent *closeEvent)
+{
+ Q_D(QMdiSubWindow);
+ bool acceptClose = true;
+ if (d->baseWidget)
+ acceptClose = d->baseWidget->close();
+ if (!acceptClose) {
+ closeEvent->ignore();
+ return;
+ }
+#ifndef QT_NO_MENUBAR
+ d->removeButtonsFromMenuBar();
+#endif
+ d->setActive(false);
+ if (parentWidget() && testAttribute(Qt::WA_DeleteOnClose)) {
+ QChildEvent childRemoved(QEvent::ChildRemoved, this);
+ QApplication::sendEvent(parentWidget(), &childRemoved);
+ }
+ closeEvent->accept();
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::leaveEvent(QEvent * /*leaveEvent*/)
+{
+ Q_D(QMdiSubWindow);
+ if (d->hoveredSubControl != QStyle::SC_None) {
+ d->hoveredSubControl = QStyle::SC_None;
+ update(QRegion(0, 0, width(), d->titleBarHeight()));
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::resizeEvent(QResizeEvent *resizeEvent)
+{
+ Q_D(QMdiSubWindow);
+#ifndef QT_NO_SIZEGRIP
+ if (d->sizeGrip) {
+ d->sizeGrip->move(isLeftToRight() ? width() - d->sizeGrip->width() : 0,
+ height() - d->sizeGrip->height());
+ }
+#endif
+
+ if (!parent()) {
+ QWidget::resizeEvent(resizeEvent);
+ return;
+ }
+
+ if (d->isMaximizeMode)
+ d->ensureWindowState(Qt::WindowMaximized);
+
+ d->updateMask();
+ if (!isVisible())
+ return;
+
+ if (d->resizeTimerId <= 0)
+ d->cachedStyleOptions = d->titleBarOptions();
+ else
+ killTimer(d->resizeTimerId);
+ d->resizeTimerId = startTimer(200);
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::timerEvent(QTimerEvent *timerEvent)
+{
+ Q_D(QMdiSubWindow);
+ if (timerEvent->timerId() == d->resizeTimerId) {
+ killTimer(d->resizeTimerId);
+ d->resizeTimerId = -1;
+ d->updateDirtyRegions();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::moveEvent(QMoveEvent *moveEvent)
+{
+ if (!parent()) {
+ QWidget::moveEvent(moveEvent);
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ if (d->isMaximizeMode)
+ d->ensureWindowState(Qt::WindowMaximized);
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::paintEvent(QPaintEvent *paintEvent)
+{
+ if (!parent() || (windowFlags() & Qt::FramelessWindowHint)) {
+ QWidget::paintEvent(paintEvent);
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ if (isMaximized() && !d->drawTitleBarWhenMaximized())
+ return;
+
+ if (d->resizeTimerId != -1) {
+ // Only update the style option rect and the window title.
+ int border = d->hasBorder(d->cachedStyleOptions) ? 4 : 0;
+ int titleBarHeight = d->titleBarHeight(d->cachedStyleOptions);
+ titleBarHeight -= isMinimized() ? 2 * border : border;
+ d->cachedStyleOptions.rect = QRect(border, border, width() - 2 * border, titleBarHeight);
+ if (!d->windowTitle.isEmpty()) {
+ int width = style()->subControlRect(QStyle::CC_TitleBar, &d->cachedStyleOptions,
+ QStyle::SC_TitleBarLabel, this).width();
+ d->cachedStyleOptions.text = d->cachedStyleOptions.fontMetrics
+ .elidedText(d->windowTitle, Qt::ElideRight, width);
+ }
+ } else {
+ // Force full update.
+ d->cachedStyleOptions = d->titleBarOptions();
+ }
+
+ QStylePainter painter(this);
+ if (!d->windowTitle.isEmpty())
+ painter.setFont(d->font);
+ painter.drawComplexControl(QStyle::CC_TitleBar, d->cachedStyleOptions);
+
+ if (isMinimized() && !d->hasBorder(d->cachedStyleOptions))
+ return;
+
+ QStyleOptionFrame frameOptions;
+ frameOptions.initFrom(this);
+ frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
+ if (d->isActive)
+ frameOptions.state |= QStyle::State_Active;
+ else
+ frameOptions.state &= ~QStyle::State_Active;
+
+ // ### Ensure that we do not require setting the cliprect for 4.4
+ if (!isMinimized() && !d->hasBorder(d->cachedStyleOptions))
+ painter.setClipRect(rect().adjusted(0, d->titleBarHeight(d->cachedStyleOptions), 0, 0));
+ if (!isMinimized() || d->hasBorder(d->cachedStyleOptions))
+ painter.drawPrimitive(QStyle::PE_FrameWindow, frameOptions);
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::mousePressEvent(QMouseEvent *mouseEvent)
+{
+ if (!parent()) {
+ QWidget::mousePressEvent(mouseEvent);
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ if (d->isInInteractiveMode)
+ d->leaveInteractiveMode();
+#ifndef QT_NO_RUBBERBAND
+ if (d->isInRubberBandMode)
+ d->leaveRubberBandMode();
+#endif
+
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+
+ if (d->currentOperation != QMdiSubWindowPrivate::None) {
+ d->updateCursor();
+ d->mousePressPosition = mapToParent(mouseEvent->pos());
+ if (d->resizeEnabled || d->moveEnabled)
+ d->oldGeometry = geometry();
+#ifndef QT_NO_RUBBERBAND
+ if ((testOption(QMdiSubWindow::RubberBandResize) && d->isResizeOperation())
+ || (testOption(QMdiSubWindow::RubberBandMove) && d->isMoveOperation())) {
+ d->enterRubberBandMode();
+ }
+#endif
+ return;
+ }
+
+ d->activeSubControl = d->hoveredSubControl;
+#ifndef QT_NO_MENU
+ if (d->activeSubControl == QStyle::SC_TitleBarSysMenu)
+ showSystemMenu();
+ else
+#endif
+ update(QRegion(0, 0, width(), d->titleBarHeight()));
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
+{
+ if (!parent()) {
+ QWidget::mouseDoubleClickEvent(mouseEvent);
+ return;
+ }
+
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ if (!d->isMoveOperation()) {
+#ifndef QT_NO_MENU
+ if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu)
+ close();
+#endif
+ return;
+ }
+
+ Qt::WindowFlags flags = windowFlags();
+ if (isMinimized()) {
+ if ((isShaded() && (flags & Qt::WindowShadeButtonHint))
+ || (flags & Qt::WindowMinimizeButtonHint)) {
+ showNormal();
+ }
+ return;
+ }
+
+ if (isMaximized()) {
+ if (flags & Qt::WindowMaximizeButtonHint)
+ showNormal();
+ return;
+ }
+
+ if (flags & Qt::WindowShadeButtonHint)
+ showShaded();
+ else if (flags & Qt::WindowMaximizeButtonHint)
+ showMaximized();
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
+{
+ if (!parent()) {
+ QWidget::mouseReleaseEvent(mouseEvent);
+ return;
+ }
+
+ if (mouseEvent->button() != Qt::LeftButton) {
+ mouseEvent->ignore();
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ if (d->currentOperation != QMdiSubWindowPrivate::None) {
+#ifndef QT_NO_RUBBERBAND
+ if (d->isInRubberBandMode && !d->isInInteractiveMode)
+ d->leaveRubberBandMode();
+#endif
+ if (d->resizeEnabled || d->moveEnabled)
+ d->oldGeometry = geometry();
+ }
+
+ d->currentOperation = d->getOperation(mouseEvent->pos());
+ d->updateCursor();
+
+ d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
+ if (d->activeSubControl != QStyle::SC_None
+ && d->activeSubControl == d->hoveredSubControl) {
+ d->processClickedSubControl();
+ }
+ d->activeSubControl = QStyle::SC_None;
+ update(QRegion(0, 0, width(), d->titleBarHeight()));
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::mouseMoveEvent(QMouseEvent *mouseEvent)
+{
+ if (!parent()) {
+ QWidget::mouseMoveEvent(mouseEvent);
+ return;
+ }
+
+ Q_D(QMdiSubWindow);
+ // No update needed if we're in a move/resize operation.
+ if (!d->isMoveOperation() && !d->isResizeOperation()) {
+ // Find previous and current hover region.
+ const QStyleOptionTitleBar options = d->titleBarOptions();
+ QStyle::SubControl oldHover = d->hoveredSubControl;
+ d->hoveredSubControl = d->getSubControl(mouseEvent->pos());
+ QRegion hoverRegion;
+ if (isHoverControl(oldHover) && oldHover != d->hoveredSubControl)
+ hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options, oldHover, this);
+ if (isHoverControl(d->hoveredSubControl) && d->hoveredSubControl != oldHover) {
+ hoverRegion += style()->subControlRect(QStyle::CC_TitleBar, &options,
+ d->hoveredSubControl, this);
+ }
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ if (qobject_cast<QMacStyle *>(style()) && !hoverRegion.isEmpty())
+ hoverRegion += QRegion(0, 0, width(), d->titleBarHeight(options));
+#endif
+ if (!hoverRegion.isEmpty())
+ update(hoverRegion);
+ }
+
+ if ((mouseEvent->buttons() & Qt::LeftButton) || d->isInInteractiveMode) {
+ if ((d->isResizeOperation() && d->resizeEnabled) || (d->isMoveOperation() && d->moveEnabled))
+ d->setNewGeometry(mapToParent(mouseEvent->pos()));
+ return;
+ }
+
+ // Do not resize/move if not allowed.
+ d->currentOperation = d->getOperation(mouseEvent->pos());
+ if ((d->isResizeOperation() && !d->resizeEnabled) || (d->isMoveOperation() && !d->moveEnabled))
+ d->currentOperation = QMdiSubWindowPrivate::None;
+ d->updateCursor();
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::keyPressEvent(QKeyEvent *keyEvent)
+{
+ Q_D(QMdiSubWindow);
+ if (!d->isInInteractiveMode || !parent()) {
+ keyEvent->ignore();
+ return;
+ }
+
+ QPoint delta;
+ switch (keyEvent->key()) {
+ case Qt::Key_Right:
+ if (keyEvent->modifiers() & Qt::ShiftModifier)
+ delta = QPoint(d->keyboardPageStep, 0);
+ else
+ delta = QPoint(d->keyboardSingleStep, 0);
+ break;
+ case Qt::Key_Up:
+ if (keyEvent->modifiers() & Qt::ShiftModifier)
+ delta = QPoint(0, -d->keyboardPageStep);
+ else
+ delta = QPoint(0, -d->keyboardSingleStep);
+ break;
+ case Qt::Key_Left:
+ if (keyEvent->modifiers() & Qt::ShiftModifier)
+ delta = QPoint(-d->keyboardPageStep, 0);
+ else
+ delta = QPoint(-d->keyboardSingleStep, 0);
+ break;
+ case Qt::Key_Down:
+ if (keyEvent->modifiers() & Qt::ShiftModifier)
+ delta = QPoint(0, d->keyboardPageStep);
+ else
+ delta = QPoint(0, d->keyboardSingleStep);
+ break;
+ case Qt::Key_Escape:
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ d->leaveInteractiveMode();
+ return;
+ default:
+ keyEvent->ignore();
+ return;
+ }
+
+#ifndef QT_NO_CURSOR
+ QPoint newPosition = parentWidget()->mapFromGlobal(cursor().pos() + delta);
+ QRect oldGeometry =
+#ifndef QT_NO_RUBBERBAND
+ d->isInRubberBandMode ? d->rubberBand->geometry() :
+#endif
+ geometry();
+ d->setNewGeometry(newPosition);
+ QRect currentGeometry =
+#ifndef QT_NO_RUBBERBAND
+ d->isInRubberBandMode ? d->rubberBand->geometry() :
+#endif
+ geometry();
+ if (currentGeometry == oldGeometry)
+ return;
+
+ // Update cursor position
+
+ QPoint actualDelta;
+ if (d->isMoveOperation()) {
+ actualDelta = QPoint(currentGeometry.x() - oldGeometry.x(),
+ currentGeometry.y() - oldGeometry.y());
+ } else {
+ int dx = isLeftToRight() ? currentGeometry.width() - oldGeometry.width()
+ : currentGeometry.x() - oldGeometry.x();
+ actualDelta = QPoint(dx, currentGeometry.height() - oldGeometry.height());
+ }
+
+ // Adjust in case we weren't able to move as long as wanted.
+ if (actualDelta != delta)
+ newPosition += (actualDelta - delta);
+ cursor().setPos(parentWidget()->mapToGlobal(newPosition));
+#endif
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \reimp
+*/
+void QMdiSubWindow::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
+{
+ Q_D(QMdiSubWindow);
+ if (!d->systemMenu) {
+ contextMenuEvent->ignore();
+ return;
+ }
+
+ if (d->hoveredSubControl == QStyle::SC_TitleBarSysMenu
+ || d->getRegion(QMdiSubWindowPrivate::Move).contains(contextMenuEvent->pos())) {
+ d->systemMenu->exec(contextMenuEvent->globalPos());
+ } else {
+ contextMenuEvent->ignore();
+ }
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::focusInEvent(QFocusEvent *focusInEvent)
+{
+ d_func()->focusInReason = focusInEvent->reason();
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::focusOutEvent(QFocusEvent * /*focusOutEvent*/)
+{
+ // To avoid update() in QWidget::focusOutEvent.
+}
+
+/*!
+ \reimp
+*/
+void QMdiSubWindow::childEvent(QChildEvent *childEvent)
+{
+ if (childEvent->type() != QEvent::ChildPolished)
+ return;
+#ifndef QT_NO_SIZEGRIP
+ if (QSizeGrip *sizeGrip = qobject_cast<QSizeGrip *>(childEvent->child()))
+ d_func()->setSizeGrip(sizeGrip);
+#endif
+}
+
+/*!
+ \reimp
+*/
+QSize QMdiSubWindow::sizeHint() const
+{
+ Q_D(const QMdiSubWindow);
+ int margin, minWidth;
+ d->sizeParameters(&margin, &minWidth);
+ QSize size(2 * margin, d->titleBarHeight() + margin);
+ if (d->baseWidget && d->baseWidget->sizeHint().isValid())
+ size += d->baseWidget->sizeHint();
+ return size.expandedTo(minimumSizeHint());
+}
+
+/*!
+ \reimp
+*/
+QSize QMdiSubWindow::minimumSizeHint() const
+{
+ Q_D(const QMdiSubWindow);
+ if (isVisible())
+ ensurePolished();
+
+ // Minimized window.
+ if (parent() && isMinimized() && !isShaded())
+ return d->iconSize();
+
+ // Calculate window decoration.
+ int margin, minWidth;
+ d->sizeParameters(&margin, &minWidth);
+ int decorationHeight = margin + d->titleBarHeight();
+ int minHeight = decorationHeight;
+
+ // Shaded window.
+ if (parent() && isShaded())
+ return QSize(qMax(minWidth, width()), d->titleBarHeight());
+
+ // Content
+ if (layout()) {
+ QSize minLayoutSize = layout()->minimumSize();
+ if (minLayoutSize.isValid()) {
+ minWidth = qMax(minWidth, minLayoutSize.width() + 2 * margin);
+ minHeight += minLayoutSize.height();
+ }
+ } else if (d->baseWidget && d->baseWidget->isVisible()) {
+ QSize minBaseWidgetSize = d->baseWidget->minimumSizeHint();
+ if (minBaseWidgetSize.isValid()) {
+ minWidth = qMax(minWidth, minBaseWidgetSize.width() + 2 * margin);
+ minHeight += minBaseWidgetSize.height();
+ }
+ }
+
+#ifndef QT_NO_SIZEGRIP
+ // SizeGrip
+ int sizeGripHeight = 0;
+ if (d->sizeGrip && d->sizeGrip->isVisibleTo(const_cast<QMdiSubWindow *>(this)))
+ sizeGripHeight = d->sizeGrip->height();
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+ else if (parent() && qobject_cast<QMacStyle *>(style()) && !d->sizeGrip)
+ sizeGripHeight = style()->pixelMetric(QStyle::PM_SizeGripSize, 0, this);
+#endif
+ minHeight = qMax(minHeight, decorationHeight + sizeGripHeight);
+#endif
+
+ return QSize(minWidth, minHeight).expandedTo(QApplication::globalStrut());
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmdisubwindow.cpp"
+#include "qmdisubwindow.moc"
+
+#endif //QT_NO_MDIAREA
diff --git a/src/widgets/widgets/qmdisubwindow.h b/src/widgets/widgets/qmdisubwindow.h
new file mode 100644
index 0000000000..88074c7ca5
--- /dev/null
+++ b/src/widgets/widgets/qmdisubwindow.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMDISUBWINDOW_H
+#define QMDISUBWINDOW_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MDIAREA
+
+class QMenu;
+class QMdiArea;
+
+namespace QMdi { class ControlContainer; }
+class QMdiSubWindowPrivate;
+class Q_WIDGETS_EXPORT QMdiSubWindow : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(int keyboardSingleStep READ keyboardSingleStep WRITE setKeyboardSingleStep)
+ Q_PROPERTY(int keyboardPageStep READ keyboardPageStep WRITE setKeyboardPageStep)
+public:
+ enum SubWindowOption {
+ AllowOutsideAreaHorizontally = 0x1, // internal
+ AllowOutsideAreaVertically = 0x2, // internal
+ RubberBandResize = 0x4,
+ RubberBandMove = 0x8
+ };
+ Q_DECLARE_FLAGS(SubWindowOptions, SubWindowOption)
+
+ QMdiSubWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QMdiSubWindow();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setWidget(QWidget *widget);
+ QWidget *widget() const;
+
+ QWidget *maximizedButtonsWidget() const; // internal
+ QWidget *maximizedSystemMenuIconWidget() const; // internal
+
+ bool isShaded() const;
+
+ void setOption(SubWindowOption option, bool on = true);
+ bool testOption(SubWindowOption) const;
+
+ void setKeyboardSingleStep(int step);
+ int keyboardSingleStep() const;
+
+ void setKeyboardPageStep(int step);
+ int keyboardPageStep() const;
+
+#ifndef QT_NO_MENU
+ void setSystemMenu(QMenu *systemMenu);
+ QMenu *systemMenu() const;
+#endif
+
+ QMdiArea *mdiArea() const;
+
+Q_SIGNALS:
+ void windowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState);
+ void aboutToActivate();
+
+public Q_SLOTS:
+#ifndef QT_NO_MENU
+ void showSystemMenu();
+#endif
+ void showShaded();
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event);
+ bool event(QEvent *event);
+ void showEvent(QShowEvent *showEvent);
+ void hideEvent(QHideEvent *hideEvent);
+ void changeEvent(QEvent *changeEvent);
+ void closeEvent(QCloseEvent *closeEvent);
+ void leaveEvent(QEvent *leaveEvent);
+ void resizeEvent(QResizeEvent *resizeEvent);
+ void timerEvent(QTimerEvent *timerEvent);
+ void moveEvent(QMoveEvent *moveEvent);
+ void paintEvent(QPaintEvent *paintEvent);
+ void mousePressEvent(QMouseEvent *mouseEvent);
+ void mouseDoubleClickEvent(QMouseEvent *mouseEvent);
+ void mouseReleaseEvent(QMouseEvent *mouseEvent);
+ void mouseMoveEvent(QMouseEvent *mouseEvent);
+ void keyPressEvent(QKeyEvent *keyEvent);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *contextMenuEvent);
+#endif
+ void focusInEvent(QFocusEvent *focusInEvent);
+ void focusOutEvent(QFocusEvent *focusOutEvent);
+ void childEvent(QChildEvent *childEvent);
+
+private:
+ Q_DISABLE_COPY(QMdiSubWindow)
+ Q_DECLARE_PRIVATE(QMdiSubWindow)
+ Q_PRIVATE_SLOT(d_func(), void _q_updateStaysOnTopHint())
+ Q_PRIVATE_SLOT(d_func(), void _q_enterInteractiveMode())
+ Q_PRIVATE_SLOT(d_func(), void _q_processFocusChanged(QWidget *, QWidget *))
+ friend class QMdiAreaPrivate;
+#ifndef QT_NO_TABBAR
+ friend class QMdiAreaTabBar;
+#endif
+ friend class QMdi::ControlContainer;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMdiSubWindow::SubWindowOptions)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_MDIAREA
+
+#endif // QMDISUBWINDOW_H
diff --git a/src/widgets/widgets/qmdisubwindow_p.h b/src/widgets/widgets/qmdisubwindow_p.h
new file mode 100644
index 0000000000..d04a7d4b75
--- /dev/null
+++ b/src/widgets/widgets/qmdisubwindow_p.h
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMDISUBWINDOW_P_H
+#define QMDISUBWINDOW_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 "qmdisubwindow.h"
+
+#ifndef QT_NO_MDIAREA
+
+#include <QStyle>
+#include <QStyleOptionTitleBar>
+#include <QMenuBar>
+#include <QSizeGrip>
+#include <QPointer>
+#include <QDebug>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVBoxLayout;
+class QMouseEvent;
+
+namespace QMdi {
+template<typename T>
+class ControlElement : public T
+{
+public:
+ ControlElement(QMdiSubWindow *child) : T(child, 0)
+ {
+ Q_ASSERT(child);
+ mdiChild = child;
+ }
+
+ void *qt_metacast(const char *classname)
+ {
+ if (classname && strcmp(classname, "ControlElement") == 0)
+ return this;
+ return 0;
+ }
+
+ QPointer<QMdiSubWindow> mdiChild;
+};
+
+class ControlContainer : public QObject
+{
+public:
+ ControlContainer(QMdiSubWindow *mdiChild);
+ ~ControlContainer();
+
+#ifndef QT_NO_MENUBAR
+ void showButtonsInMenuBar(QMenuBar *menuBar);
+ void removeButtonsFromMenuBar(QMenuBar *menuBar = 0);
+ QMenuBar *menuBar() const { return m_menuBar; }
+#endif
+ void updateWindowIcon(const QIcon &windowIcon);
+ QWidget *controllerWidget() const { return m_controllerWidget; }
+ QWidget *systemMenuLabel() const { return m_menuLabel; }
+
+private:
+ QPointer<QWidget> previousLeft;
+ QPointer<QWidget> previousRight;
+#ifndef QT_NO_MENUBAR
+ QPointer<QMenuBar> m_menuBar;
+#endif
+ QPointer<QWidget> m_controllerWidget;
+ QPointer<QWidget> m_menuLabel;
+ QPointer<QMdiSubWindow> mdiChild;
+};
+} // namespace QMdi
+
+class QMdiSubWindowPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QMdiSubWindow)
+public:
+ // Enums and typedefs.
+ enum Operation {
+ None,
+ Move,
+ TopResize,
+ BottomResize,
+ LeftResize,
+ RightResize,
+ TopLeftResize,
+ TopRightResize,
+ BottomLeftResize,
+ BottomRightResize
+ };
+
+ enum ChangeFlag {
+ HMove = 0x01,
+ VMove = 0x02,
+ HResize = 0x04,
+ VResize = 0x08,
+ HResizeReverse = 0x10,
+ VResizeReverse = 0x20
+ };
+
+ enum WindowStateAction {
+ RestoreAction,
+ MoveAction,
+ ResizeAction,
+ MinimizeAction,
+ MaximizeAction,
+ StayOnTopAction,
+ CloseAction,
+ /* Add new states _above_ this line! */
+ NumWindowStateActions
+ };
+
+ struct OperationInfo {
+ uint changeFlags;
+ Qt::CursorShape cursorShape;
+ QRegion region;
+ bool hover;
+ OperationInfo(uint changeFlags, Qt::CursorShape cursorShape, bool hover = true)
+ : changeFlags(changeFlags),
+ cursorShape(cursorShape),
+ hover(hover)
+ {}
+ };
+
+ typedef QMap<Operation, OperationInfo> OperationInfoMap;
+
+ QMdiSubWindowPrivate();
+
+ // Variables.
+ QPointer<QWidget> baseWidget;
+ QPointer<QWidget> restoreFocusWidget;
+ QPointer<QMdi::ControlContainer> controlContainer;
+#ifndef QT_NO_SIZEGRIP
+ QPointer<QSizeGrip> sizeGrip;
+#endif
+#ifndef QT_NO_RUBBERBAND
+ QRubberBand *rubberBand;
+#endif
+ QPoint mousePressPosition;
+ QRect oldGeometry;
+ QSize internalMinimumSize;
+ QSize userMinimumSize;
+ QSize restoreSize;
+ bool resizeEnabled;
+ bool moveEnabled;
+ bool isInInteractiveMode;
+#ifndef QT_NO_RUBBERBAND
+ bool isInRubberBandMode;
+#endif
+ bool isShadeMode;
+ bool ignoreWindowTitleChange;
+ bool ignoreNextActivationEvent;
+ bool activationEnabled;
+ bool isShadeRequestFromMinimizeMode;
+ bool isMaximizeMode;
+ bool isWidgetHiddenByUs;
+ bool isActive;
+ bool isExplicitlyDeactivated;
+ int keyboardSingleStep;
+ int keyboardPageStep;
+ int resizeTimerId;
+ Operation currentOperation;
+ QStyle::SubControl hoveredSubControl;
+ QStyle::SubControl activeSubControl;
+ Qt::FocusReason focusInReason;
+ OperationInfoMap operationMap;
+ QPointer<QMenu> systemMenu;
+#ifndef QT_NO_ACTIONS
+ QPointer<QAction> actions[NumWindowStateActions];
+#endif
+ QMdiSubWindow::SubWindowOptions options;
+ QString lastChildWindowTitle;
+ QPalette titleBarPalette;
+ QString windowTitle;
+ QFont font;
+ QIcon menuIcon;
+ QStyleOptionTitleBar cachedStyleOptions;
+ QString originalTitle;
+
+ // Slots.
+ void _q_updateStaysOnTopHint();
+ void _q_enterInteractiveMode();
+ void _q_processFocusChanged(QWidget *old, QWidget *now);
+
+ // Functions.
+ void leaveInteractiveMode();
+ void removeBaseWidget();
+ void initOperationMap();
+#ifndef QT_NO_MENU
+ void createSystemMenu();
+#endif
+ void updateCursor();
+ void updateDirtyRegions();
+ void updateGeometryConstraints();
+ void updateMask();
+ void setNewGeometry(const QPoint &pos);
+ void setMinimizeMode();
+ void setNormalMode();
+ void setMaximizeMode();
+ void setActive(bool activate, bool changeFocus = true);
+ void processClickedSubControl();
+ QRegion getRegion(Operation operation) const;
+ Operation getOperation(const QPoint &pos) const;
+ QStyleOptionTitleBar titleBarOptions() const;
+ void ensureWindowState(Qt::WindowState state);
+ int titleBarHeight(const QStyleOptionTitleBar &options) const;
+ void sizeParameters(int *margin, int *minWidth) const;
+ bool drawTitleBarWhenMaximized() const;
+#ifndef QT_NO_MENUBAR
+ QMenuBar *menuBar() const;
+ void showButtonsInMenuBar(QMenuBar *menuBar);
+ void removeButtonsFromMenuBar();
+#endif
+ void updateWindowTitle(bool requestFromChild);
+#ifndef QT_NO_RUBBERBAND
+ void enterRubberBandMode();
+ void leaveRubberBandMode();
+#endif
+ QPalette desktopPalette() const;
+ void updateActions();
+ void setFocusWidget();
+ void restoreFocus();
+ void setWindowFlags(Qt::WindowFlags windowFlags);
+ void setVisible(WindowStateAction, bool visible = true);
+#ifndef QT_NO_ACTION
+ void setEnabled(WindowStateAction, bool enable = true);
+#ifndef QT_NO_MENU
+ void addToSystemMenu(WindowStateAction, const QString &text, const char *slot);
+#endif
+#endif // QT_NO_ACTION
+ QSize iconSize() const;
+#ifndef QT_NO_SIZEGRIP
+ void setSizeGrip(QSizeGrip *sizeGrip);
+ void setSizeGripVisible(bool visible = true) const;
+#endif
+ void updateInternalWindowTitle();
+ QString originalWindowTitle();
+ void setNewWindowTitle();
+
+ inline int titleBarHeight() const
+ {
+ Q_Q(const QMdiSubWindow);
+ if (!parent || q->windowFlags() & Qt::FramelessWindowHint
+ || (q->isMaximized() && !drawTitleBarWhenMaximized())) {
+ return 0;
+ }
+ QStyleOptionTitleBar options = titleBarOptions();
+ int height = options.rect.height();
+ if (hasBorder(options))
+ height += q->isMinimized() ? 8 : 4;
+ return height;
+ }
+
+ inline QStyle::SubControl getSubControl(const QPoint &pos) const
+ {
+ Q_Q(const QMdiSubWindow);
+ QStyleOptionTitleBar titleBarOptions = this->titleBarOptions();
+ return q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &titleBarOptions, pos, q);
+ }
+
+ inline void setNewGeometry(QRect *geometry)
+ {
+ Q_Q(QMdiSubWindow);
+ Q_ASSERT(parent);
+ geometry->setSize(geometry->size().expandedTo(internalMinimumSize));
+#ifndef QT_NO_RUBBERBAND
+ if (isInRubberBandMode)
+ rubberBand->setGeometry(*geometry);
+ else
+#endif
+ q->setGeometry(*geometry);
+ }
+
+ inline bool hasBorder(const QStyleOptionTitleBar &options) const
+ {
+ Q_Q(const QMdiSubWindow);
+ return !q->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, q);
+ }
+
+ inline bool autoRaise() const
+ {
+ Q_Q(const QMdiSubWindow);
+ return q->style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, q);
+ }
+
+ inline bool isResizeOperation() const
+ {
+ return currentOperation != None && currentOperation != Move;
+ }
+
+ inline bool isMoveOperation() const
+ {
+ return currentOperation == Move;
+ }
+};
+
+#endif // QT_NO_MDIAREA
+
+QT_END_NAMESPACE
+
+#endif // QMDISUBWINDOW_P_H
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
new file mode 100644
index 0000000000..67dbd7e265
--- /dev/null
+++ b/src/widgets/widgets/qmenu.cpp
@@ -0,0 +1,3100 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmenu.h"
+
+#ifndef QT_NO_MENU
+
+#include "qdebug.h"
+#include "qstyle.h"
+#include "qevent.h"
+#include "qtimer.h"
+#include "qlayout.h"
+#include "qpainter.h"
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#ifndef QT_NO_ACCESSIBILITY
+# include "qaccessible.h"
+#endif
+#ifndef QT_NO_EFFECTS
+# include <private/qeffects_p.h>
+#endif
+#ifndef QT_NO_WHATSTHIS
+# include <qwhatsthis.h>
+#endif
+
+#include "qmenu_p.h"
+#include "qmenubar_p.h"
+#include "qwidgetaction.h"
+#include "qtoolbutton.h"
+#include "qpushbutton.h"
+#include <private/qpushbutton_p.h>
+#include <private/qaction_p.h>
+#include <private/qsoftkeymanager_p.h>
+
+#ifdef Q_WS_X11
+# include <private/qt_x11_p.h>
+#endif
+
+#if defined(Q_OS_MAC) && !defined(QT_NO_EFFECTS)
+# include <private/qcore_mac_p.h>
+# include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+QMenu *QMenuPrivate::mouseDown = 0;
+int QMenuPrivate::sloppyDelayTimer = 0;
+
+/* QMenu code */
+// internal class used for the torn off popup
+class QTornOffMenu : public QMenu
+{
+ Q_OBJECT
+ class QTornOffMenuPrivate : public QMenuPrivate
+ {
+ Q_DECLARE_PUBLIC(QMenu)
+ public:
+ QTornOffMenuPrivate(QMenu *p) : causedMenu(p) {
+ tornoff = 1;
+ causedPopup.widget = 0;
+ causedPopup.action = ((QTornOffMenu*)p)->d_func()->causedPopup.action;
+ causedStack = ((QTornOffMenu*)p)->d_func()->calcCausedStack();
+ }
+ QList<QPointer<QWidget> > calcCausedStack() const { return causedStack; }
+ QPointer<QMenu> causedMenu;
+ QList<QPointer<QWidget> > causedStack;
+ };
+public:
+ QTornOffMenu(QMenu *p) : QMenu(*(new QTornOffMenuPrivate(p)))
+ {
+ Q_D(QTornOffMenu);
+ // make the torn-off menu a sibling of p (instead of a child)
+ QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.last();
+ if (parentWidget->parentWidget())
+ parentWidget = parentWidget->parentWidget();
+ setParent(parentWidget, Qt::Window | Qt::Tool);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ setAttribute(Qt::WA_X11NetWmWindowTypeMenu, true);
+ setWindowTitle(p->windowTitle());
+ setEnabled(p->isEnabled());
+ //QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(onTrigger(QAction*)));
+ //QObject::connect(this, SIGNAL(hovered(QAction*)), this, SLOT(onHovered(QAction*)));
+ QList<QAction*> items = p->actions();
+ for(int i = 0; i < items.count(); i++)
+ addAction(items.at(i));
+ }
+ void syncWithMenu(QMenu *menu, QActionEvent *act)
+ {
+ Q_D(QTornOffMenu);
+ if(menu != d->causedMenu)
+ return;
+ if (act->type() == QEvent::ActionAdded) {
+ insertAction(act->before(), act->action());
+ } else if (act->type() == QEvent::ActionRemoved)
+ removeAction(act->action());
+ }
+ void actionEvent(QActionEvent *e)
+ {
+ QMenu::actionEvent(e);
+ setFixedSize(sizeHint());
+ }
+public slots:
+ void onTrigger(QAction *action) { d_func()->activateAction(action, QAction::Trigger, false); }
+ void onHovered(QAction *action) { d_func()->activateAction(action, QAction::Hover, false); }
+private:
+ Q_DECLARE_PRIVATE(QTornOffMenu)
+ friend class QMenuPrivate;
+};
+
+void QMenuPrivate::init()
+{
+ Q_Q(QMenu);
+#ifndef QT_NO_WHATSTHIS
+ q->setAttribute(Qt::WA_CustomWhatsThis);
+#endif
+ q->setAttribute(Qt::WA_X11NetWmWindowTypePopupMenu);
+ defaultMenuAction = menuAction = new QAction(q);
+ menuAction->d_func()->menu = q;
+ q->setMouseTracking(q->style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, q));
+ if (q->style()->styleHint(QStyle::SH_Menu_Scrollable, 0, q)) {
+ scroll = new QMenuPrivate::QMenuScroller;
+ scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
+ }
+
+ platformMenu = QGuiApplicationPrivate::platformIntegration()->createPlatformMenu(q);
+
+#ifdef QT_SOFTKEYS_ENABLED
+ selectAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::SelectSoftKey, Qt::Key_Select, q);
+ cancelAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::CancelSoftKey, Qt::Key_Back, q);
+ selectAction->setPriority(QAction::HighPriority);
+ cancelAction->setPriority(QAction::HighPriority);
+ q->addAction(selectAction);
+ q->addAction(cancelAction);
+#endif
+}
+
+int QMenuPrivate::scrollerHeight() const
+{
+ Q_Q(const QMenu);
+ return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
+}
+
+//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
+QRect QMenuPrivate::popupGeometry(const QWidget *widget) const
+{
+#ifdef Q_WS_WIN
+ return QApplication::desktop()->screenGeometry(widget);
+#elif defined Q_WS_X11
+ if (X11->desktopEnvironment == DE_KDE)
+ return QApplication::desktop()->screenGeometry(widget);
+ else
+ return QApplication::desktop()->availableGeometry(widget);
+#else
+ return QApplication::desktop()->availableGeometry(widget);
+#endif
+}
+
+//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
+QRect QMenuPrivate::popupGeometry(int screen) const
+{
+#ifdef Q_WS_WIN
+ return QApplication::desktop()->screenGeometry(screen);
+#elif defined Q_WS_X11
+ if (X11->desktopEnvironment == DE_KDE)
+ return QApplication::desktop()->screenGeometry(screen);
+ else
+ return QApplication::desktop()->availableGeometry(screen);
+#else
+ return QApplication::desktop()->availableGeometry(screen);
+#endif
+}
+
+QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
+{
+ QList<QPointer<QWidget> > ret;
+ for(QWidget *widget = causedPopup.widget; widget; ) {
+ ret.append(widget);
+ if (QTornOffMenu *qtmenu = qobject_cast<QTornOffMenu*>(widget))
+ ret += qtmenu->d_func()->causedStack;
+ if (QMenu *qmenu = qobject_cast<QMenu*>(widget))
+ widget = qmenu->d_func()->causedPopup.widget;
+ else
+ break;
+ }
+ return ret;
+}
+
+void QMenuPrivate::updateActionRects() const
+{
+ Q_Q(const QMenu);
+ updateActionRects(popupGeometry(q));
+}
+
+void QMenuPrivate::updateActionRects(const QRect &screen) const
+{
+ Q_Q(const QMenu);
+ if (!itemsDirty)
+ return;
+
+ q->ensurePolished();
+
+ //let's reinitialize the buffer
+ actionRects.resize(actions.count());
+ actionRects.fill(QRect());
+
+ int lastVisibleAction = getLastVisibleAction();
+
+ int max_column_width = 0,
+ dh = screen.height(),
+ y = 0;
+ QStyle *style = q->style();
+ QStyleOption opt;
+ opt.init(q);
+ const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
+ vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
+ icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
+ const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
+ const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q);
+ const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0;
+
+ //for compatibility now - will have to refactor this away
+ tabWidth = 0;
+ maxIconWidth = 0;
+ hasCheckableItems = false;
+ ncols = 1;
+ sloppyAction = 0;
+
+ for (int i = 0; i < actions.count(); ++i) {
+ QAction *action = actions.at(i);
+ if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action))
+ continue;
+ //..and some members
+ hasCheckableItems |= action->isCheckable();
+ QIcon is = action->icon();
+ if (!is.isNull()) {
+ maxIconWidth = qMax<uint>(maxIconWidth, icone + 4);
+ }
+ }
+
+ //calculate size
+ QFontMetrics qfm = q->fontMetrics();
+ bool previousWasSeparator = true; // this is true to allow removing the leading separators
+ for(int i = 0; i <= lastVisibleAction; i++) {
+ QAction *action = actions.at(i);
+
+ if (!action->isVisible() ||
+ (collapsibleSeparators && previousWasSeparator && action->isSeparator()))
+ continue; // we continue, this action will get an empty QRect
+
+ previousWasSeparator = action->isSeparator();
+
+ //let the style modify the above size..
+ QStyleOptionMenuItem opt;
+ q->initStyleOption(&opt, action);
+ const QFontMetrics &fm = opt.fontMetrics;
+
+ QSize sz;
+ if (QWidget *w = widgetItems.value(action)) {
+ sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());
+ } else {
+ //calc what I think the size is..
+ if (action->isSeparator()) {
+ sz = QSize(2, 2);
+ } else {
+ QString s = action->text();
+ int t = s.indexOf(QLatin1Char('\t'));
+ if (t != -1) {
+ tabWidth = qMax(int(tabWidth), qfm.width(s.mid(t+1)));
+ s = s.left(t);
+ #ifndef QT_NO_SHORTCUT
+ } else {
+ QKeySequence seq = action->shortcut();
+ if (!seq.isEmpty())
+ tabWidth = qMax(int(tabWidth), qfm.width(seq));
+ #endif
+ }
+ sz.setWidth(fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, s).width());
+ sz.setHeight(qMax(fm.height(), qfm.height()));
+
+ QIcon is = action->icon();
+ if (!is.isNull()) {
+ QSize is_sz = QSize(icone, icone);
+ if (is_sz.height() > sz.height())
+ sz.setHeight(is_sz.height());
+ }
+ }
+ sz = style->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);
+ }
+
+
+ if (!sz.isEmpty()) {
+ max_column_width = qMax(max_column_width, sz.width());
+ //wrapping
+ if (!scroll &&
+ y+sz.height()+vmargin > dh - (deskFw * 2)) {
+ ncols++;
+ y = vmargin;
+ }
+ y += sz.height();
+ //update the item
+ actionRects[i] = QRect(0, 0, sz.width(), sz.height());
+ }
+ }
+
+ max_column_width += tabWidth; //finally add in the tab width
+ const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
+ const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
+ max_column_width = qMax(min_column_width, max_column_width);
+
+ //calculate position
+ const int base_y = vmargin + fw + topmargin +
+ (scroll ? scroll->scrollOffset : 0) +
+ tearoffHeight;
+ int x = hmargin + fw + leftmargin;
+ y = base_y;
+
+ for(int i = 0; i < actions.count(); i++) {
+ QRect &rect = actionRects[i];
+ if (rect.isNull())
+ continue;
+ if (!scroll &&
+ y+rect.height() > dh - deskFw * 2) {
+ x += max_column_width + hmargin;
+ y = base_y;
+ }
+ rect.translate(x, y); //move
+ rect.setWidth(max_column_width); //uniform width
+
+ //we need to update the widgets geometry
+ if (QWidget *widget = widgetItems.value(actions.at(i))) {
+ widget->setGeometry(rect);
+ widget->setVisible(actions.at(i)->isVisible());
+ }
+
+ y += rect.height();
+ }
+ itemsDirty = 0;
+}
+
+QSize QMenuPrivate::adjustMenuSizeForScreen(const QRect &screen)
+{
+ Q_Q(QMenu);
+ QSize ret = screen.size();
+ itemsDirty = true;
+ updateActionRects(screen);
+ const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
+ ret.setWidth(actionRects.at(getLastVisibleAction()).right() + fw);
+ return ret;
+}
+
+int QMenuPrivate::getLastVisibleAction() const
+{
+ //let's try to get the last visible action
+ int lastVisibleAction = actions.count() - 1;
+ for (;lastVisibleAction >= 0; --lastVisibleAction) {
+ const QAction *action = actions.at(lastVisibleAction);
+ if (action->isVisible()) {
+ //removing trailing separators
+ if (action->isSeparator() && collapsibleSeparators)
+ continue;
+ break;
+ }
+ }
+ return lastVisibleAction;
+}
+
+
+QRect QMenuPrivate::actionRect(QAction *act) const
+{
+ int index = actions.indexOf(act);
+ if (index == -1)
+ return QRect();
+
+ updateActionRects();
+
+ //we found the action
+ return actionRects.at(index);
+}
+
+#if defined(Q_OS_MAC)
+static const qreal MenuFadeTimeInSec = 0.150;
+#endif
+
+void QMenuPrivate::hideUpToMenuBar()
+{
+ Q_Q(QMenu);
+ bool fadeMenus = q->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
+ if (!tornoff) {
+ QWidget *caused = causedPopup.widget;
+ hideMenu(q); //hide after getting causedPopup
+ while(caused) {
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
+ mb->d_func()->setCurrentAction(0);
+ mb->d_func()->setKeyboardMode(false);
+ caused = 0;
+ } else
+#endif
+ if (QMenu *m = qobject_cast<QMenu*>(caused)) {
+ caused = m->d_func()->causedPopup.widget;
+ if (!m->d_func()->tornoff)
+ hideMenu(m, fadeMenus);
+ if (!fadeMenus) // Mac doesn't clear the action until after hidden.
+ m->d_func()->setCurrentAction(0);
+ } else { caused = 0;
+ }
+ }
+#if defined(Q_WS_MAC)
+ if (fadeMenus) {
+ QEventLoop eventLoop;
+ QTimer::singleShot(int(MenuFadeTimeInSec * 1000), &eventLoop, SLOT(quit()));
+ QMacWindowFader::currentFader()->performFade();
+ eventLoop.exec();
+ }
+#endif
+ }
+ setCurrentAction(0);
+}
+
+void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister)
+{
+ if (!menu)
+ return;
+#if !defined(QT_NO_EFFECTS)
+ menu->blockSignals(true);
+ aboutToHide = true;
+ // Flash item which is about to trigger (if any).
+ if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
+ && currentAction && currentAction == actionAboutToTrigger
+ && menu->actions().contains(currentAction)) {
+ QEventLoop eventLoop;
+ QAction *activeAction = currentAction;
+
+ menu->setActiveAction(0);
+ QTimer::singleShot(60, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+
+ // Select and wait 20 ms.
+ menu->setActiveAction(activeAction);
+ QTimer::singleShot(20, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+ }
+
+ // Fade out.
+ if (menu->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide)) {
+ // ### Qt 4.4:
+ // Should be something like: q->transitionWindow(Qt::FadeOutTransition, MenuFadeTimeInSec);
+ // Hopefully we'll integrate qt/research/windowtransitions into main before 4.4.
+ // Talk to Richard, Trenton or Bjoern.
+#if defined(Q_WS_MAC)
+ if (justRegister) {
+ QMacWindowFader::currentFader()->setFadeDuration(MenuFadeTimeInSec);
+ QMacWindowFader::currentFader()->registerWindowToFade(menu);
+ } else {
+ macWindowFade(qt_mac_window_for(menu), MenuFadeTimeInSec);
+ }
+
+#endif // Q_WS_MAC
+ }
+ aboutToHide = false;
+ menu->blockSignals(false);
+#endif // QT_NO_EFFECTS
+ if (!justRegister)
+ menu->hide();
+}
+
+void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
+{
+ Q_Q(QMenu);
+ if (action && action->isEnabled()) {
+ if (!delay)
+ q->internalDelayedPopup();
+ else if (!menuDelayTimer.isActive() && (!action->menu() || !action->menu()->isVisible()))
+ menuDelayTimer.start(delay, q);
+ if (activateFirst && action->menu())
+ action->menu()->d_func()->setFirstActionActive();
+ } else if (QMenu *menu = activeMenu) { //hide the current item
+ activeMenu = 0;
+ hideMenu(menu);
+ }
+}
+
+void QMenuPrivate::setSyncAction()
+{
+ Q_Q(QMenu);
+ QAction *current = currentAction;
+ if(current && (!current->isEnabled() || current->menu() || current->isSeparator()))
+ current = 0;
+ for(QWidget *caused = q; caused;) {
+ if (QMenu *m = qobject_cast<QMenu*>(caused)) {
+ caused = m->d_func()->causedPopup.widget;
+ if (m->d_func()->eventLoop)
+ m->d_func()->syncAction = current; // synchronous operation
+ } else {
+ break;
+ }
+ }
+}
+
+
+void QMenuPrivate::setFirstActionActive()
+{
+ Q_Q(QMenu);
+ updateActionRects();
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ const QRect &rect = actionRects.at(i);
+ if (rect.isNull())
+ continue;
+ if (scroll && scroll->scrollFlags & QMenuScroller::ScrollUp) {
+ saccum -= rect.height();
+ if (saccum > scroll->scrollOffset - scrollerHeight())
+ continue;
+ }
+ QAction *act = actions.at(i);
+ if (!act->isSeparator() &&
+ (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
+ || act->isEnabled())) {
+ setCurrentAction(act);
+ break;
+ }
+ }
+}
+
+// popup == -1 means do not popup, 0 means immediately, others mean use a timer
+void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst)
+{
+ Q_Q(QMenu);
+ tearoffHighlighted = 0;
+ if (currentAction)
+ q->update(actionRect(currentAction));
+
+ sloppyAction = 0;
+ if (!sloppyRegion.isEmpty())
+ sloppyRegion = QRegion();
+ QMenu *hideActiveMenu = activeMenu;
+#ifndef QT_NO_STATUSTIP
+ QAction *previousAction = currentAction;
+#endif
+
+ currentAction = action;
+ if (action) {
+ if (!action->isSeparator()) {
+ activateAction(action, QAction::Hover);
+ if (popup != -1) {
+ hideActiveMenu = 0; //will be done "later"
+ // if the menu is visible then activate the required action,
+ // otherwise we just mark the action as currentAction
+ // and activate it when the menu will be popuped.
+ if (q->isVisible())
+ popupAction(currentAction, popup, activateFirst);
+ }
+ q->update(actionRect(action));
+
+ if (reason == SelectedFromKeyboard) {
+ QWidget *widget = widgetItems.value(action);
+ if (widget) {
+ if (widget->focusPolicy() != Qt::NoFocus)
+ widget->setFocus(Qt::TabFocusReason);
+ } else {
+ //when the action has no QWidget, the QMenu itself should
+ // get the focus
+ // Since the menu is a pop-up, it uses the popup reason.
+ if (!q->hasFocus()) {
+ q->setFocus(Qt::PopupFocusReason);
+ }
+ }
+ }
+ } else { //action is a separator
+ if (popup != -1)
+ hideActiveMenu = 0; //will be done "later"
+ }
+#ifndef QT_NO_STATUSTIP
+ } else if (previousAction) {
+ previousAction->d_func()->showStatusText(topCausedWidget(), QString());
+#endif
+ }
+ if (hideActiveMenu) {
+ activeMenu = 0;
+#ifndef QT_NO_EFFECTS
+ // kill any running effect
+ qFadeEffect(0);
+ qScrollEffect(0);
+#endif
+ hideMenu(hideActiveMenu);
+ }
+}
+
+//return the top causedPopup.widget that is not a QMenu
+QWidget *QMenuPrivate::topCausedWidget() const
+{
+ QWidget* top = causedPopup.widget;
+ while (QMenu* m = qobject_cast<QMenu *>(top))
+ top = m->d_func()->causedPopup.widget;
+ return top;
+}
+
+QAction *QMenuPrivate::actionAt(QPoint p) const
+{
+ if (!q_func()->rect().contains(p)) //sanity check
+ return 0;
+
+ for(int i = 0; i < actionRects.count(); i++) {
+ if (actionRects.at(i).contains(p))
+ return actions.at(i);
+ }
+ return 0;
+}
+
+void QMenuPrivate::setOverrideMenuAction(QAction *a)
+{
+ Q_Q(QMenu);
+ QObject::disconnect(menuAction, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
+ if (a) {
+ menuAction = a;
+ QObject::connect(a, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
+ } else { //we revert back to the default action created by the QMenu itself
+ menuAction = defaultMenuAction;
+ }
+}
+
+void QMenuPrivate::_q_overrideMenuActionDestroyed()
+{
+ menuAction=defaultMenuAction;
+}
+
+
+void QMenuPrivate::updateLayoutDirection()
+{
+ Q_Q(QMenu);
+ //we need to mimic the cause of the popup's layout direction
+ //to allow setting it on a mainwindow for example
+ //we call setLayoutDirection_helper to not overwrite a user-defined value
+ if (!q->testAttribute(Qt::WA_SetLayoutDirection)) {
+ if (QWidget *w = causedPopup.widget)
+ setLayoutDirection_helper(w->layoutDirection());
+ else if (QWidget *w = q->parentWidget())
+ setLayoutDirection_helper(w->layoutDirection());
+ else
+ setLayoutDirection_helper(QApplication::layoutDirection());
+ }
+}
+
+
+/*!
+ Returns the action associated with this menu.
+*/
+QAction *QMenu::menuAction() const
+{
+ return d_func()->menuAction;
+}
+
+/*!
+ \property QMenu::title
+ \brief The title of the menu
+
+ This is equivalent to the QAction::text property of the menuAction().
+
+ By default, this property contains an empty string.
+*/
+QString QMenu::title() const
+{
+ return d_func()->menuAction->text();
+}
+
+void QMenu::setTitle(const QString &text)
+{
+ d_func()->menuAction->setText(text);
+}
+
+/*!
+ \property QMenu::icon
+
+ \brief The icon of the menu
+
+ This is equivalent to the QAction::icon property of the menuAction().
+
+ By default, if no icon is explicitly set, this property contains a null icon.
+*/
+QIcon QMenu::icon() const
+{
+ return d_func()->menuAction->icon();
+}
+
+void QMenu::setIcon(const QIcon &icon)
+{
+ d_func()->menuAction->setIcon(icon);
+}
+
+
+//actually performs the scrolling
+void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active)
+{
+ Q_Q(QMenu);
+ if (!scroll || !scroll->scrollFlags)
+ return;
+ updateActionRects();
+ int newOffset = 0;
+ const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
+ const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
+ const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
+ const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
+
+ if (location == QMenuScroller::ScrollTop) {
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ if (actions.at(i) == action) {
+ newOffset = topScroll - saccum;
+ break;
+ }
+ saccum += actionRects.at(i).height();
+ }
+ } else {
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ saccum += actionRects.at(i).height();
+ if (actions.at(i) == action) {
+ if (location == QMenuScroller::ScrollCenter)
+ newOffset = ((q->height() / 2) - botScroll) - (saccum - topScroll);
+ else
+ newOffset = (q->height() - botScroll) - saccum;
+ break;
+ }
+ }
+ if(newOffset)
+ newOffset -= fw * 2;
+ }
+
+ //figure out which scroll flags
+ uint newScrollFlags = QMenuScroller::ScrollNone;
+ if (newOffset < 0) //easy and cheap one
+ newScrollFlags |= QMenuScroller::ScrollUp;
+ int saccum = newOffset;
+ for(int i = 0; i < actionRects.count(); i++) {
+ saccum += actionRects.at(i).height();
+ if (saccum > q->height()) {
+ newScrollFlags |= QMenuScroller::ScrollDown;
+ break;
+ }
+ }
+
+ if (!(newScrollFlags & QMenuScroller::ScrollDown) && (scroll->scrollFlags & QMenuScroller::ScrollDown)) {
+ newOffset = q->height() - (saccum - newOffset) - fw*2 - vmargin; //last item at bottom
+ }
+
+ if (!(newScrollFlags & QMenuScroller::ScrollUp) && (scroll->scrollFlags & QMenuScroller::ScrollUp)) {
+ newOffset = 0; //first item at top
+ }
+
+ if (newScrollFlags & QMenuScroller::ScrollUp)
+ newOffset -= vmargin;
+
+ QRect screen = popupGeometry(q);
+ const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q);
+ if (q->height() < screen.height()-(desktopFrame*2)-1) {
+ QRect geom = q->geometry();
+ if (newOffset > scroll->scrollOffset && (scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollUp)) { //scroll up
+ const int newHeight = geom.height()-(newOffset-scroll->scrollOffset);
+ if(newHeight > geom.height())
+ geom.setHeight(newHeight);
+ } else if(scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollDown) {
+ int newTop = geom.top() + (newOffset-scroll->scrollOffset);
+ if (newTop < desktopFrame+screen.top())
+ newTop = desktopFrame+screen.top();
+ if (newTop < geom.top()) {
+ geom.setTop(newTop);
+ newOffset = 0;
+ newScrollFlags &= ~QMenuScroller::ScrollUp;
+ }
+ }
+ if (geom.bottom() > screen.bottom() - desktopFrame)
+ geom.setBottom(screen.bottom() - desktopFrame);
+ if (geom.top() < desktopFrame+screen.top())
+ geom.setTop(desktopFrame+screen.top());
+ if (geom != q->geometry()) {
+#if 0
+ if (newScrollFlags & QMenuScroller::ScrollDown &&
+ q->geometry().top() - geom.top() >= -newOffset)
+ newScrollFlags &= ~QMenuScroller::ScrollDown;
+#endif
+ q->setGeometry(geom);
+ }
+ }
+
+ //actually update flags
+ const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative
+ if (!itemsDirty && delta) {
+ //we've scrolled so we need to update the action rects
+ for (int i = 0; i < actionRects.count(); ++i) {
+ QRect &current = actionRects[i];
+ current.moveTop(current.top() + delta);
+
+ //we need to update the widgets geometry
+ if (QWidget *w = widgetItems.value(actions.at(i)))
+ w->setGeometry(current);
+ }
+ }
+ scroll->scrollOffset += delta;
+ scroll->scrollFlags = newScrollFlags;
+ if (active)
+ setCurrentAction(action);
+
+ q->update(); //issue an update so we see all the new state..
+}
+
+void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool active)
+{
+ Q_Q(QMenu);
+ updateActionRects();
+ if(location == QMenuScroller::ScrollBottom) {
+ for(int i = actions.size()-1; i >= 0; --i) {
+ QAction *act = actions.at(i);
+ if (actionRects.at(i).isNull())
+ continue;
+ if (!act->isSeparator() &&
+ (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
+ || act->isEnabled())) {
+ if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
+ scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollBottom, active);
+ else if(active)
+ setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
+ break;
+ }
+ }
+ } else if(location == QMenuScroller::ScrollTop) {
+ for(int i = 0; i < actions.size(); ++i) {
+ QAction *act = actions.at(i);
+ if (actionRects.at(i).isNull())
+ continue;
+ if (!act->isSeparator() &&
+ (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
+ || act->isEnabled())) {
+ if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollTop, active);
+ else if(active)
+ setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
+ break;
+ }
+ }
+ }
+}
+
+//only directional
+void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool page, bool active)
+{
+ Q_Q(QMenu);
+ if (!scroll || !(scroll->scrollFlags & direction)) //not really possible...
+ return;
+ updateActionRects();
+ const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
+ const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
+ const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
+ const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
+ const int offset = topScroll ? topScroll-vmargin : 0;
+ if (direction == QMenuScroller::ScrollUp) {
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ saccum -= actionRects.at(i).height();
+ if (saccum <= scroll->scrollOffset-offset) {
+ scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);
+ break;
+ }
+ }
+ } else if (direction == QMenuScroller::ScrollDown) {
+ bool scrolled = false;
+ for(int i = 0, saccum = 0; i < actions.count(); i++) {
+ const int iHeight = actionRects.at(i).height();
+ saccum -= iHeight;
+ if (saccum <= scroll->scrollOffset-offset) {
+ const int scrollerArea = q->height() - botScroll - fw*2;
+ int visible = (scroll->scrollOffset-offset) - saccum;
+ for(i++ ; i < actions.count(); i++) {
+ visible += actionRects.at(i).height();
+ if (visible > scrollerArea - topScroll) {
+ scrolled = true;
+ scrollMenu(actions.at(i), page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if(!scrolled) {
+ scroll->scrollFlags &= ~QMenuScroller::ScrollDown;
+ q->update();
+ }
+ }
+}
+
+/* This is poor-mans eventfilters. This avoids the use of
+ eventFilter (which can be nasty for users of QMenuBar's). */
+bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
+{
+ Q_Q(QMenu);
+ QPoint pos = q->mapFromGlobal(e->globalPos());
+ if (scroll && !activeMenu) { //let the scroller "steal" the event
+ bool isScroll = false;
+ if (pos.x() >= 0 && pos.x() < q->width()) {
+ for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) {
+ if (scroll->scrollFlags & dir) {
+ if (dir == QMenuScroller::ScrollUp)
+ isScroll = (pos.y() <= scrollerHeight());
+ else if (dir == QMenuScroller::ScrollDown)
+ isScroll = (pos.y() >= q->height() - scrollerHeight());
+ if (isScroll) {
+ scroll->scrollDirection = dir;
+ break;
+ }
+ }
+ }
+ }
+ if (isScroll) {
+ scroll->scrollTimer.start(50, q);
+ return true;
+ } else {
+ scroll->scrollTimer.stop();
+ }
+ }
+
+ if (tearoff) { //let the tear off thingie "steal" the event..
+ QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q));
+ if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ tearRect.translate(0, scrollerHeight());
+ q->update(tearRect);
+ if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) {
+ setCurrentAction(0);
+ tearoffHighlighted = 1;
+ if (e->type() == QEvent::MouseButtonRelease) {
+ if (!tornPopup)
+ tornPopup = new QTornOffMenu(q);
+ tornPopup->setGeometry(q->geometry());
+ tornPopup->show();
+ hideUpToMenuBar();
+ }
+ return true;
+ }
+ tearoffHighlighted = 0;
+ }
+
+ if (q->frameGeometry().contains(e->globalPos())) //otherwise if the event is in our rect we want it..
+ return false;
+
+ for(QWidget *caused = causedPopup.widget; caused;) {
+ bool passOnEvent = false;
+ QWidget *next_widget = 0;
+ QPoint cpos = caused->mapFromGlobal(e->globalPos());
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
+ passOnEvent = mb->rect().contains(cpos);
+ } else
+#endif
+ if (QMenu *m = qobject_cast<QMenu*>(caused)) {
+ passOnEvent = m->rect().contains(cpos);
+ next_widget = m->d_func()->causedPopup.widget;
+ }
+ if (passOnEvent) {
+ if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) {
+ QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers());
+ QApplication::sendEvent(caused, &new_e);
+ return true;
+ }
+ }
+ if (!next_widget)
+ break;
+ caused = next_widget;
+ }
+ return false;
+}
+
+void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self)
+{
+ QBoolBlocker guard(activationRecursionGuard);
+ if(self)
+ action->activate(action_e);
+
+ for(int i = 0; i < causedStack.size(); ++i) {
+ QPointer<QWidget> widget = causedStack.at(i);
+ if (!widget)
+ continue;
+ //fire
+ if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
+ widget = qmenu->d_func()->causedPopup.widget;
+ if (action_e == QAction::Trigger) {
+ emit qmenu->triggered(action);
+ } else if (action_e == QAction::Hover) {
+ emit qmenu->hovered(action);
+ }
+#ifndef QT_NO_MENUBAR
+ } else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) {
+ if (action_e == QAction::Trigger) {
+ emit qmenubar->triggered(action);
+ } else if (action_e == QAction::Hover) {
+ emit qmenubar->hovered(action);
+ }
+ break; //nothing more..
+#endif
+ }
+ }
+}
+
+void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e, bool self)
+{
+ Q_Q(QMenu);
+#ifndef QT_NO_WHATSTHIS
+ bool inWhatsThisMode = QWhatsThis::inWhatsThisMode();
+#endif
+ if (!action || !q->isEnabled()
+ || (action_e == QAction::Trigger
+#ifndef QT_NO_WHATSTHIS
+ && !inWhatsThisMode
+#endif
+ && (action->isSeparator() ||!action->isEnabled())))
+ return;
+
+ /* I have to save the caused stack here because it will be undone after popup execution (ie in the hide).
+ Then I iterate over the list to actually send the events. --Sam
+ */
+ const QList<QPointer<QWidget> > causedStack = calcCausedStack();
+ if (action_e == QAction::Trigger) {
+#ifndef QT_NO_WHATSTHIS
+ if (!inWhatsThisMode)
+ actionAboutToTrigger = action;
+#endif
+
+ if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ hideUpToMenuBar();
+ } else {
+ for(QWidget *widget = QApplication::activePopupWidget(); widget; ) {
+ if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
+ if(qmenu == q)
+ hideUpToMenuBar();
+ widget = qmenu->d_func()->causedPopup.widget;
+ } else {
+ break;
+ }
+ }
+ }
+
+#ifndef QT_NO_WHATSTHIS
+ if (inWhatsThisMode) {
+ QString s = action->whatsThis();
+ if (s.isEmpty())
+ s = whatsThis;
+ QWhatsThis::showText(q->mapToGlobal(actionRect(action).center()), s, q);
+ return;
+ }
+#endif
+ }
+
+
+ activateCausedStack(causedStack, action, action_e, self);
+
+
+ if (action_e == QAction::Hover) {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QAccessible::isActive()) {
+ int actionIndex = indexOf(action) + 1;
+ QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus);
+ QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection);
+ }
+#endif
+ action->showStatusText(topCausedWidget());
+ } else {
+ actionAboutToTrigger = 0;
+ }
+}
+
+void QMenuPrivate::_q_actionTriggered()
+{
+ Q_Q(QMenu);
+ if (QAction *action = qobject_cast<QAction *>(q->sender())) {
+ QWeakPointer<QAction> actionGuard = action;
+ emit q->triggered(action);
+ if (!activationRecursionGuard && actionGuard) {
+ //in case the action has not been activated by the mouse
+ //we check the parent hierarchy
+ QList< QPointer<QWidget> > list;
+ for(QWidget *widget = q->parentWidget(); widget; ) {
+ if (qobject_cast<QMenu*>(widget)
+#ifndef QT_NO_MENUBAR
+ || qobject_cast<QMenuBar*>(widget)
+#endif
+ ) {
+ list.append(widget);
+ widget = widget->parentWidget();
+ } else {
+ break;
+ }
+ }
+ activateCausedStack(list, action, QAction::Trigger, false);
+ }
+ }
+}
+
+void QMenuPrivate::_q_actionHovered()
+{
+ Q_Q(QMenu);
+ if (QAction * action = qobject_cast<QAction *>(q->sender())) {
+ emit q->hovered(action);
+ }
+}
+
+bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos)
+{
+ //determines if the mouse has moved (ie its initial position has
+ //changed by more than QApplication::startDragDistance()
+ //or if there were at least 6 mouse motions)
+ return motions > 6 ||
+ QApplication::startDragDistance() < (mousePopupPos - globalPos).manhattanLength();
+}
+
+
+/*!
+ Initialize \a option with the values from this menu and information from \a action. This method
+ is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom() QMenuBar::initStyleOption()
+*/
+void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
+{
+ if (!option || !action)
+ return;
+
+ Q_D(const QMenu);
+ option->initFrom(this);
+ option->palette = palette();
+ option->state = QStyle::State_None;
+
+ if (window()->isActiveWindow())
+ option->state |= QStyle::State_Active;
+ if (isEnabled() && action->isEnabled()
+ && (!action->menu() || action->menu()->isEnabled()))
+ option->state |= QStyle::State_Enabled;
+ else
+ option->palette.setCurrentColorGroup(QPalette::Disabled);
+
+ option->font = action->font().resolve(font());
+ option->fontMetrics = QFontMetrics(option->font);
+
+ if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) {
+ option->state |= QStyle::State_Selected
+ | (d->mouseDown ? QStyle::State_Sunken : QStyle::State_None);
+ }
+
+ option->menuHasCheckableItems = d->hasCheckableItems;
+ if (!action->isCheckable()) {
+ option->checkType = QStyleOptionMenuItem::NotCheckable;
+ } else {
+ option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive())
+ ? QStyleOptionMenuItem::Exclusive : QStyleOptionMenuItem::NonExclusive;
+ option->checked = action->isChecked();
+ }
+ if (action->menu())
+ option->menuItemType = QStyleOptionMenuItem::SubMenu;
+ else if (action->isSeparator())
+ option->menuItemType = QStyleOptionMenuItem::Separator;
+ else if (d->defaultAction == action)
+ option->menuItemType = QStyleOptionMenuItem::DefaultItem;
+ else
+ option->menuItemType = QStyleOptionMenuItem::Normal;
+ if (action->isIconVisibleInMenu())
+ option->icon = action->icon();
+ QString textAndAccel = action->text();
+#ifndef QT_NO_SHORTCUT
+ if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) {
+ QKeySequence seq = action->shortcut();
+ if (!seq.isEmpty())
+ textAndAccel += QLatin1Char('\t') + QString(seq);
+ }
+#endif
+ option->text = textAndAccel;
+ option->tabWidth = d->tabWidth;
+ option->maxIconWidth = d->maxIconWidth;
+ option->menuRect = rect();
+}
+
+/*!
+ \class QMenu
+ \brief The QMenu class provides a menu widget for use in menu
+ bars, context menus, and other popup menus.
+
+ \ingroup mainwindow-classes
+ \ingroup basicwidgets
+
+
+ A menu widget is a selection menu. It can be either a pull-down
+ menu in a menu bar or a standalone context menu. Pull-down menus
+ are shown by the menu bar when the user clicks on the respective
+ item or presses the specified shortcut key. Use
+ QMenuBar::addMenu() to insert a menu into a menu bar. Context
+ menus are usually invoked by some special keyboard key or by
+ right-clicking. They can be executed either asynchronously with
+ popup() or synchronously with exec(). Menus can also be invoked in
+ response to button presses; these are just like context menus
+ except for how they are invoked.
+
+ \table 100%
+ \row
+ \o \inlineimage plastique-menu.png
+ \o \inlineimage windowsxp-menu.png
+ \o \inlineimage macintosh-menu.png
+ \endtable
+ \caption Fig. A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style},
+ \l{Windows XP Style Widget Gallery}{Windows XP widget style},
+ and \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+
+ \section1 Actions
+
+ A menu consists of a list of action items. Actions are added with
+ the addAction(), addActions() and insertAction() functions. An action
+ is represented vertically and rendered by QStyle. In addition, actions
+ can have a text label, an optional icon drawn on the very left side,
+ and shortcut key sequence such as "Ctrl+X".
+
+ The existing actions held by a menu can be found with actions().
+
+ There are four kinds of action items: separators, actions that
+ show a submenu, widgets, and actions that perform an action.
+ Separators are inserted with addSeparator(), submenus with addMenu(),
+ and all other items are considered action items.
+
+ When inserting action items you usually specify a receiver and a
+ slot. The receiver will be notifed whenever the item is
+ \l{QAction::triggered()}{triggered()}. In addition, QMenu provides
+ two signals, activated() and highlighted(), which signal the
+ QAction that was triggered from the menu.
+
+ You clear a menu with clear() and remove individual action items
+ with removeAction().
+
+ A QMenu can also provide a tear-off menu. A tear-off menu is a
+ top-level window that contains a copy of the menu. This makes it
+ possible for the user to "tear off" frequently used menus and
+ position them in a convenient place on the screen. If you want
+ this functionality for a particular menu, insert a tear-off handle
+ with setTearOffEnabled(). When using tear-off menus, bear in mind
+ that the concept isn't typically used on Microsoft Windows so
+ some users may not be familiar with it. Consider using a QToolBar
+ instead.
+
+ Widgets can be inserted into menus with the QWidgetAction class.
+ Instances of this class are used to hold widgets, and are inserted
+ into menus with the addAction() overload that takes a QAction.
+
+ Conversely, actions can be added to widgets with the addAction(),
+ addActions() and insertAction() functions.
+
+ \warning To make QMenu visible on the screen, exec() or popup() should be
+ used instead of show().
+
+ \section1 QMenu on Qt for Windows CE
+
+ If a menu is integrated into the native menubar on Windows Mobile we
+ do not support the signals: aboutToHide (), aboutToShow () and hovered ().
+ It is not possible to display an icon in a native menu on Windows Mobile.
+
+ \section1 QMenu on Mac OS X with Qt build against Cocoa
+
+ QMenu can be inserted only once in a menu/menubar. Subsequent insertions will
+ have no effect or will result in a disabled menu item.
+
+ See the \l{mainwindows/menus}{Menus} example for an example of how
+ to use QMenuBar and QMenu in your application.
+
+ \bold{Important inherited functions:} addAction(), removeAction(), clear(),
+ addSeparator(), and addMenu().
+
+ \sa QMenuBar, {fowler}{GUI Design Handbook: Menu, Drop-Down and Pop-Up},
+ {Application Example}, {Menus Example}, {Recent Files Example}
+*/
+
+
+/*!
+ Constructs a menu with parent \a parent.
+
+ Although a popup menu is always a top-level widget, if a parent is
+ passed the popup menu will be deleted when that parent is
+ destroyed (as with any other QObject).
+*/
+QMenu::QMenu(QWidget *parent)
+ : QWidget(*new QMenuPrivate, parent, Qt::Popup)
+{
+ Q_D(QMenu);
+ d->init();
+}
+
+/*!
+ Constructs a menu with a \a title and a \a parent.
+
+ Although a popup menu is always a top-level widget, if a parent is
+ passed the popup menu will be deleted when that parent is
+ destroyed (as with any other QObject).
+
+ \sa title
+*/
+QMenu::QMenu(const QString &title, QWidget *parent)
+ : QWidget(*new QMenuPrivate, parent, Qt::Popup)
+{
+ Q_D(QMenu);
+ d->init();
+ d->menuAction->setText(title);
+}
+
+/*! \internal
+ */
+QMenu::QMenu(QMenuPrivate &dd, QWidget *parent)
+ : QWidget(dd, parent, Qt::Popup)
+{
+ Q_D(QMenu);
+ d->init();
+}
+
+/*!
+ Destroys the menu.
+*/
+QMenu::~QMenu()
+{
+ Q_D(QMenu);
+ if (!d->widgetItems.isEmpty()) { // avoid detach on shared null hash
+ QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin();
+ for (; it != d->widgetItems.end(); ++it) {
+ if (QWidget *widget = it.value()) {
+ QWidgetAction *action = static_cast<QWidgetAction *>(it.key());
+ action->releaseWidget(widget);
+ *it = 0;
+ }
+ }
+ }
+
+ if (d->eventLoop)
+ d->eventLoop->exit();
+ hideTearOffMenu();
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with \a text.
+ The function adds the newly created action to the menu's
+ list of actions, and returns it.
+
+ \sa QWidget::addAction()
+*/
+QAction *QMenu::addAction(const QString &text)
+{
+ QAction *ret = new QAction(text, this);
+ addAction(ret);
+ return ret;
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with an \a icon
+ and some \a text. The function adds the newly created action to
+ the menu's list of actions, and returns it.
+
+ \sa QWidget::addAction()
+*/
+QAction *QMenu::addAction(const QIcon &icon, const QString &text)
+{
+ QAction *ret = new QAction(icon, text, this);
+ addAction(ret);
+ return ret;
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with the text \a
+ text and an optional shortcut \a shortcut. The action's
+ \l{QAction::triggered()}{triggered()} signal is connected to the
+ \a receiver's \a member slot. The function adds the newly created
+ action to the menu's list of actions and returns it.
+
+ \sa QWidget::addAction()
+*/
+QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
+{
+ QAction *action = new QAction(text, this);
+#ifdef QT_NO_SHORTCUT
+ Q_UNUSED(shortcut);
+#else
+ action->setShortcut(shortcut);
+#endif
+ QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
+ addAction(action);
+ return action;
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with an \a icon and
+ some \a text and an optional shortcut \a shortcut. The action's
+ \l{QAction::triggered()}{triggered()} signal is connected to the
+ \a member slot of the \a receiver object. The function adds the
+ newly created action to the menu's list of actions, and returns it.
+
+ \sa QWidget::addAction()
+*/
+QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver,
+ const char* member, const QKeySequence &shortcut)
+{
+ QAction *action = new QAction(icon, text, this);
+#ifdef QT_NO_SHORTCUT
+ Q_UNUSED(shortcut);
+#else
+ action->setShortcut(shortcut);
+#endif
+ QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
+ addAction(action);
+ return action;
+}
+
+/*!
+ This convenience function adds \a menu as a submenu to this menu.
+ It returns \a menu's menuAction(). This menu does not take
+ ownership of \a menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QAction *QMenu::addMenu(QMenu *menu)
+{
+ QAction *action = menu->menuAction();
+ addAction(action);
+ return action;
+}
+
+/*!
+ Appends a new QMenu with \a title to the menu. The menu
+ takes ownership of the menu. Returns the new menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QMenu *QMenu::addMenu(const QString &title)
+{
+ QMenu *menu = new QMenu(title, this);
+ addAction(menu->menuAction());
+ return menu;
+}
+
+/*!
+ Appends a new QMenu with \a icon and \a title to the menu. The menu
+ takes ownership of the menu. Returns the new menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QMenu *QMenu::addMenu(const QIcon &icon, const QString &title)
+{
+ QMenu *menu = new QMenu(title, this);
+ menu->setIcon(icon);
+ addAction(menu->menuAction());
+ return menu;
+}
+
+/*!
+ This convenience function creates a new separator action, i.e. an
+ action with QAction::isSeparator() returning true, and adds the new
+ action to this menu's list of actions. It returns the newly
+ created action.
+
+ \sa QWidget::addAction()
+*/
+QAction *QMenu::addSeparator()
+{
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ addAction(action);
+ return action;
+}
+
+/*!
+ This convenience function inserts \a menu before action \a before
+ and returns the menus menuAction().
+
+ \sa QWidget::insertAction(), addMenu()
+*/
+QAction *QMenu::insertMenu(QAction *before, QMenu *menu)
+{
+ QAction *action = menu->menuAction();
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ This convenience function creates a new separator action, i.e. an
+ action with QAction::isSeparator() returning true. The function inserts
+ the newly created action into this menu's list of actions before
+ action \a before and returns it.
+
+ \sa QWidget::insertAction(), addSeparator()
+*/
+QAction *QMenu::insertSeparator(QAction *before)
+{
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ This sets the default action to \a act. The default action may have
+ a visual cue, depending on the current QStyle. A default action
+ usually indicates what will happen by default when a drop occurs.
+
+ \sa defaultAction()
+*/
+void QMenu::setDefaultAction(QAction *act)
+{
+ d_func()->defaultAction = act;
+}
+
+/*!
+ Returns the current default action.
+
+ \sa setDefaultAction()
+*/
+QAction *QMenu::defaultAction() const
+{
+ return d_func()->defaultAction;
+}
+
+/*!
+ \property QMenu::tearOffEnabled
+ \brief whether the menu supports being torn off
+
+ When true, the menu contains a special tear-off item (often shown as a dashed
+ line at the top of the menu) that creates a copy of the menu when it is
+ triggered.
+
+ This "torn-off" copy lives in a separate window. It contains the same menu
+ items as the original menu, with the exception of the tear-off handle.
+
+ By default, this property is false.
+*/
+void QMenu::setTearOffEnabled(bool b)
+{
+ Q_D(QMenu);
+ if (d->tearoff == b)
+ return;
+ if (!b)
+ hideTearOffMenu();
+ d->tearoff = b;
+
+ d->itemsDirty = true;
+ if (isVisible())
+ resize(sizeHint());
+}
+
+bool QMenu::isTearOffEnabled() const
+{
+ return d_func()->tearoff;
+}
+
+/*!
+ When a menu is torn off a second menu is shown to display the menu
+ contents in a new window. When the menu is in this mode and the menu
+ is visible returns true; otherwise false.
+
+ \sa hideTearOffMenu() isTearOffEnabled()
+*/
+bool QMenu::isTearOffMenuVisible() const
+{
+ if (d_func()->tornPopup)
+ return d_func()->tornPopup->isVisible();
+ return false;
+}
+
+/*!
+ This function will forcibly hide the torn off menu making it
+ disappear from the users desktop.
+
+ \sa isTearOffMenuVisible() isTearOffEnabled()
+*/
+void QMenu::hideTearOffMenu()
+{
+ if (QWidget *w = d_func()->tornPopup)
+ w->close();
+}
+
+
+/*!
+ Sets the currently highlighted action to \a act.
+*/
+void QMenu::setActiveAction(QAction *act)
+{
+ Q_D(QMenu);
+ d->setCurrentAction(act, 0);
+ if (d->scroll)
+ d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter);
+}
+
+
+/*!
+ Returns the currently highlighted action, or 0 if no
+ action is currently highlighted.
+*/
+QAction *QMenu::activeAction() const
+{
+ return d_func()->currentAction;
+}
+
+/*!
+ \since 4.2
+
+ Returns true if there are no visible actions inserted into the menu, false
+ otherwise.
+
+ \sa QWidget::actions()
+*/
+
+bool QMenu::isEmpty() const
+{
+ bool ret = true;
+ for(int i = 0; ret && i < actions().count(); ++i) {
+ const QAction *action = actions().at(i);
+ if (!action->isSeparator() && action->isVisible()) {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+/*!
+ Removes all the menu's actions. Actions owned by the menu and not
+ shown in any other widget are deleted.
+
+ \sa removeAction()
+*/
+void QMenu::clear()
+{
+ QList<QAction*> acts = actions();
+
+ for(int i = 0; i < acts.size(); i++) {
+#ifdef QT_SOFTKEYS_ENABLED
+ Q_D(QMenu);
+ // Lets not touch to our internal softkey actions
+ if(acts[i] == d->selectAction || acts[i] == d->cancelAction)
+ continue;
+#endif
+ removeAction(acts[i]);
+ if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty())
+ delete acts[i];
+ }
+}
+
+/*!
+ If a menu does not fit on the screen it lays itself out so that it
+ does fit. It is style dependent what layout means (for example, on
+ Windows it will use multiple columns).
+
+ This functions returns the number of columns necessary.
+*/
+int QMenu::columnCount() const
+{
+ return d_func()->ncols;
+}
+
+/*!
+ Returns the item at \a pt; returns 0 if there is no item there.
+*/
+QAction *QMenu::actionAt(const QPoint &pt) const
+{
+ if (QAction *ret = d_func()->actionAt(pt))
+ return ret;
+ return 0;
+}
+
+/*!
+ Returns the geometry of action \a act.
+*/
+QRect QMenu::actionGeometry(QAction *act) const
+{
+ return d_func()->actionRect(act);
+}
+
+/*!
+ \reimp
+*/
+QSize QMenu::sizeHint() const
+{
+ Q_D(const QMenu);
+ d->updateActionRects();
+
+ QSize s;
+ for (int i = 0; i < d->actionRects.count(); ++i) {
+ const QRect &rect = d->actionRects.at(i);
+ if (rect.isNull())
+ continue;
+ if (rect.bottom() >= s.height())
+ s.setHeight(rect.y() + rect.height());
+ if (rect.right() >= s.width())
+ s.setWidth(rect.x() + rect.width());
+ }
+ // Note that the action rects calculated above already include
+ // the top and left margins, so we only need to add margins for
+ // the bottom and right.
+ QStyleOption opt(0);
+ opt.init(this);
+ const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
+ s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
+ s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
+
+ return style()->sizeFromContents(QStyle::CT_Menu, &opt,
+ s.expandedTo(QApplication::globalStrut()), this);
+}
+
+/*!
+ Displays the menu so that the action \a atAction will be at the
+ specified \e global position \a p. To translate a widget's local
+ coordinates into global coordinates, use QWidget::mapToGlobal().
+
+ When positioning a menu with exec() or popup(), bear in mind that
+ you cannot rely on the menu's current size(). For performance
+ reasons, the menu adapts its size only when necessary, so in many
+ cases, the size before and after the show is different. Instead,
+ use sizeHint() which calculates the proper size depending on the
+ menu's current contents.
+
+ \sa QWidget::mapToGlobal(), exec()
+*/
+void QMenu::popup(const QPoint &p, QAction *atAction)
+{
+ Q_D(QMenu);
+#ifndef Q_OS_SYMBIAN
+ if (d->scroll) { // reset scroll state from last popup
+ d->scroll->scrollOffset = 0;
+ d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
+ }
+#endif
+ d->tearoffHighlighted = 0;
+ d->motions = 0;
+ d->doChildEffects = true;
+ d->updateLayoutDirection();
+
+#ifndef QT_NO_MENUBAR
+ // if this menu is part of a chain attached to a QMenuBar, set the
+ // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
+ setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0);
+#endif
+
+ ensurePolished(); // Get the right font
+ emit aboutToShow();
+ const bool actionListChanged = d->itemsDirty;
+ d->updateActionRects();
+ QPoint pos;
+ QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget);
+ if (actionListChanged && causedButton)
+ pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
+ else
+ pos = p;
+
+ QSize size = sizeHint();
+ QRect screen;
+#ifndef QT_NO_GRAPHICSVIEW
+ bool isEmbedded = !bypassGraphicsProxyWidget(this) && d->nearestGraphicsProxyWidget(this);
+ if (isEmbedded)
+ screen = d->popupGeometry(this);
+ else
+#endif
+ screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
+ const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
+ bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
+
+ // if the screens have very different geometries and the menu is too big, we have to recalculate
+ if (size.height() > screen.height() || size.width() > screen.width()) {
+ size = d->adjustMenuSizeForScreen(screen);
+ adjustToDesktop = true;
+ }
+ // Layout is not right, we might be able to save horizontal space
+ if (d->ncols >1 && size.height() < screen.height()) {
+ size = d->adjustMenuSizeForScreen(screen);
+ adjustToDesktop = true;
+ }
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!atAction && QApplication::keypadNavigationEnabled()) {
+ // Try to have one item activated
+ if (d->defaultAction && d->defaultAction->isEnabled()) {
+ atAction = d->defaultAction;
+ // TODO: This works for first level menus, not yet sub menus
+ } else {
+ foreach (QAction *action, d->actions)
+ if (action->isEnabled()) {
+ atAction = action;
+ break;
+ }
+ }
+ d->currentAction = atAction;
+ }
+#endif
+ if (d->ncols > 1) {
+ pos.setY(screen.top() + desktopFrame);
+ } else if (atAction) {
+ for (int i = 0, above_height = 0; i < d->actions.count(); i++) {
+ QAction *action = d->actions.at(i);
+ if (action == atAction) {
+ int newY = pos.y() - above_height;
+ if (d->scroll && newY < desktopFrame) {
+ d->scroll->scrollFlags = d->scroll->scrollFlags
+ | QMenuPrivate::QMenuScroller::ScrollUp;
+ d->scroll->scrollOffset = newY;
+ newY = desktopFrame;
+ }
+ pos.setY(newY);
+
+ if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
+ && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
+ int below_height = above_height + d->scroll->scrollOffset;
+ for (int i2 = i; i2 < d->actionRects.count(); i2++)
+ below_height += d->actionRects.at(i2).height();
+ size.setHeight(below_height);
+ }
+ break;
+ } else {
+ above_height += d->actionRects.at(i).height();
+ }
+ }
+ }
+
+ QPoint mouse = QCursor::pos();
+ d->mousePopupPos = mouse;
+ const bool snapToMouse = (QRect(p.x() - 3, p.y() - 3, 6, 6).contains(mouse));
+
+ if (adjustToDesktop) {
+ // handle popup falling "off screen"
+ if (isRightToLeft()) {
+ if (snapToMouse) // position flowing left from the mouse
+ pos.setX(mouse.x() - size.width());
+
+#ifndef QT_NO_MENUBAR
+ // if in a menubar, it should be right-aligned
+ if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
+ pos.rx() -= size.width();
+#endif //QT_NO_MENUBAR
+
+ if (pos.x() < screen.left() + desktopFrame)
+ pos.setX(qMax(p.x(), screen.left() + desktopFrame));
+ if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
+ pos.setX(qMax(p.x() - size.width(), screen.right() - desktopFrame - size.width() + 1));
+ } else {
+ if (pos.x() + size.width() - 1 > screen.right() - desktopFrame)
+ pos.setX(screen.right() - desktopFrame - size.width() + 1);
+ if (pos.x() < screen.left() + desktopFrame)
+ pos.setX(screen.left() + desktopFrame);
+ }
+ if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
+ if(snapToMouse)
+ pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
+ else
+ pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
+ } else if (pos.y() < screen.top() + desktopFrame) {
+ pos.setY(screen.top() + desktopFrame);
+ }
+
+ if (pos.y() < screen.top() + desktopFrame)
+ pos.setY(screen.top() + desktopFrame);
+ if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
+ if (d->scroll) {
+ d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
+ int y = qMax(screen.y(),pos.y());
+ size.setHeight(screen.bottom() - (desktopFrame * 2) - y);
+ } else {
+ // Too big for screen, bias to see bottom of menu (for some reason)
+ pos.setY(screen.bottom() - size.height() + 1);
+ }
+ }
+ }
+ const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
+ const QSize menuSize(sizeHint());
+ QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget);
+ if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) {
+ QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction));
+ const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft());
+ parentActionRect.moveTopLeft(actionTopLeft);
+ if (isRightToLeft()) {
+ if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset)
+ && (pos.x() < parentActionRect.right()))
+ {
+ pos.rx() = parentActionRect.right();
+ }
+ } else {
+ if ((pos.x() < parentActionRect.right() + subMenuOffset)
+ && (pos.x() + menuSize.width() > parentActionRect.left()))
+ {
+ pos.rx() = parentActionRect.left() - menuSize.width();
+ }
+ }
+ }
+ setGeometry(QRect(pos, size));
+#ifndef QT_NO_EFFECTS
+ int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
+ int vGuess = QEffects::DownScroll;
+ if (isRightToLeft()) {
+ if ((snapToMouse && (pos.x() + size.width() / 2 > mouse.x())) ||
+ (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 > d->causedPopup.widget->x()))
+ hGuess = QEffects::RightScroll;
+ } else {
+ if ((snapToMouse && (pos.x() + size.width() / 2 < mouse.x())) ||
+ (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width() / 2 < d->causedPopup.widget->x()))
+ hGuess = QEffects::LeftScroll;
+ }
+
+#ifndef QT_NO_MENUBAR
+ if ((snapToMouse && (pos.y() + size.height() / 2 < mouse.y())) ||
+ (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
+ pos.y() + size.width() / 2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
+ vGuess = QEffects::UpScroll;
+#endif
+ if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
+ bool doChildEffects = true;
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) {
+ doChildEffects = mb->d_func()->doChildEffects;
+ mb->d_func()->doChildEffects = false;
+ } else
+#endif
+ if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) {
+ doChildEffects = m->d_func()->doChildEffects;
+ m->d_func()->doChildEffects = false;
+ }
+
+ if (doChildEffects) {
+ if (QApplication::isEffectEnabled(Qt::UI_FadeMenu))
+ qFadeEffect(this);
+ else if (d->causedPopup.widget)
+ qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess);
+ else
+ qScrollEffect(this, hGuess | vGuess);
+ } else {
+ // kill any running effect
+ qFadeEffect(0);
+ qScrollEffect(0);
+
+ show();
+ }
+ } else
+#endif
+ {
+ show();
+ }
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);
+#endif
+}
+
+/*!
+ Executes this menu synchronously.
+
+ This is equivalent to \c{exec(pos())}.
+
+ This returns the triggered QAction in either the popup menu or one
+ of its submenus, or 0 if no item was triggered (normally because
+ the user pressed Esc).
+
+ In most situations you'll want to specify the position yourself,
+ for example, the current mouse position:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 0
+ or aligned to a widget:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 1
+ or in reaction to a QMouseEvent *e:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 2
+*/
+QAction *QMenu::exec()
+{
+ return exec(pos());
+}
+
+
+/*!
+ \overload
+
+ Executes this menu synchronously.
+
+ Pops up the menu so that the action \a action will be at the
+ specified \e global position \a p. To translate a widget's local
+ coordinates into global coordinates, use QWidget::mapToGlobal().
+
+ This returns the triggered QAction in either the popup menu or one
+ of its submenus, or 0 if no item was triggered (normally because
+ the user pressed Esc).
+
+ Note that all signals are emitted as usual. If you connect a
+ QAction to a slot and call the menu's exec(), you get the result
+ both via the signal-slot connection and in the return value of
+ exec().
+
+ Common usage is to position the menu at the current mouse
+ position:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 3
+ or aligned to a widget:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 4
+ or in reaction to a QMouseEvent *e:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 5
+
+ When positioning a menu with exec() or popup(), bear in mind that
+ you cannot rely on the menu's current size(). For performance
+ reasons, the menu adapts its size only when necessary. So in many
+ cases, the size before and after the show is different. Instead,
+ use sizeHint() which calculates the proper size depending on the
+ menu's current contents.
+
+ \sa popup(), QWidget::mapToGlobal()
+*/
+QAction *QMenu::exec(const QPoint &p, QAction *action)
+{
+ Q_D(QMenu);
+ createWinId();
+ QEventLoop eventLoop;
+ d->eventLoop = &eventLoop;
+ popup(p, action);
+
+ QPointer<QObject> guard = this;
+ (void) eventLoop.exec();
+ if (guard.isNull())
+ return 0;
+
+ action = d->syncAction;
+ d->syncAction = 0;
+ d->eventLoop = 0;
+ return action;
+}
+
+/*!
+ \overload
+
+ Executes a menu synchronously.
+
+ The menu's actions are specified by the list of \a actions. The menu will
+ pop up so that the specified action, \a at, appears at global position \a
+ pos. If \a at is not specified then the menu appears at position \a
+ pos. \a parent is the menu's parent widget; specifying the parent will
+ provide context when \a pos alone is not enough to decide where the menu
+ should go (e.g., with multiple desktops or when the parent is embedded in
+ QGraphicsView).
+
+ The function returns the triggered QAction in either the popup
+ menu or one of its submenus, or 0 if no item was triggered
+ (normally because the user pressed Esc).
+
+ This is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
+
+ \sa popup(), QWidget::mapToGlobal()
+*/
+QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
+{
+ QMenu menu(parent);
+ menu.addActions(actions);
+ return menu.exec(pos, at);
+}
+
+/*!
+ \overload
+
+ Executes a menu synchronously.
+
+ The menu's actions are specified by the list of \a actions. The menu
+ will pop up so that the specified action, \a at, appears at global
+ position \a pos. If \a at is not specified then the menu appears
+ at position \a pos.
+
+ The function returns the triggered QAction in either the popup
+ menu or one of its submenus, or 0 if no item was triggered
+ (normally because the user pressed Esc).
+
+ This is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
+
+ \sa popup(), QWidget::mapToGlobal()
+*/
+QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at)
+{
+ // ### Qt 5: merge
+ return exec(actions, pos, at, 0);
+}
+
+/*!
+ \reimp
+*/
+void QMenu::hideEvent(QHideEvent *)
+{
+ Q_D(QMenu);
+ emit aboutToHide();
+ if (d->eventLoop)
+ d->eventLoop->exit();
+ d->setCurrentAction(0);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuEnd);
+#endif
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget))
+ mb->d_func()->setCurrentAction(0);
+#endif
+ d->mouseDown = 0;
+ d->hasHadMouse = false;
+ d->causedPopup.widget = 0;
+ d->causedPopup.action = 0;
+ if (d->scroll)
+ d->scroll->scrollTimer.stop(); //make sure the timer stops
+}
+
+/*!
+ \reimp
+*/
+void QMenu::paintEvent(QPaintEvent *e)
+{
+ Q_D(QMenu);
+ d->updateActionRects();
+ QPainter p(this);
+ QRegion emptyArea = QRegion(rect());
+
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.initFrom(this);
+ menuOpt.state = QStyle::State_None;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.maxIconWidth = 0;
+ menuOpt.tabWidth = 0;
+ style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
+
+ //draw the items that need updating..
+ for (int i = 0; i < d->actions.count(); ++i) {
+ QAction *action = d->actions.at(i);
+ QRect adjustedActionRect = d->actionRects.at(i);
+ if (!e->rect().intersects(adjustedActionRect)
+ || d->widgetItems.value(action))
+ continue;
+ //set the clip region to be extra safe (and adjust for the scrollers)
+ QRegion adjustedActionReg(adjustedActionRect);
+ emptyArea -= adjustedActionReg;
+ p.setClipRegion(adjustedActionReg);
+
+ QStyleOptionMenuItem opt;
+ initStyleOption(&opt, action);
+ opt.rect = adjustedActionRect;
+ style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
+ }
+
+ const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
+ //draw the scroller regions..
+ if (d->scroll) {
+ menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
+ menuOpt.state |= QStyle::State_Enabled;
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
+ menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
+ emptyArea -= QRegion(menuOpt.rect);
+ p.setClipRect(menuOpt.rect);
+ style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
+ }
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
+ menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
+ d->scrollerHeight());
+ emptyArea -= QRegion(menuOpt.rect);
+ menuOpt.state |= QStyle::State_DownArrow;
+ p.setClipRect(menuOpt.rect);
+ style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
+ }
+ }
+ //paint the tear off..
+ if (d->tearoff) {
+ menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
+ menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
+ style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
+ if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ menuOpt.rect.translate(0, d->scrollerHeight());
+ emptyArea -= QRegion(menuOpt.rect);
+ p.setClipRect(menuOpt.rect);
+ menuOpt.state = QStyle::State_None;
+ if (d->tearoffHighlighted)
+ menuOpt.state |= QStyle::State_Selected;
+ style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this);
+ }
+ //draw border
+ if (fw) {
+ QRegion borderReg;
+ borderReg += QRect(0, 0, fw, height()); //left
+ borderReg += QRect(width()-fw, 0, fw, height()); //right
+ borderReg += QRect(0, 0, width(), fw); //top
+ borderReg += QRect(0, height()-fw, width(), fw); //bottom
+ p.setClipRegion(borderReg);
+ emptyArea -= borderReg;
+ QStyleOptionFrame frame;
+ frame.rect = rect();
+ frame.palette = palette();
+ frame.state = QStyle::State_None;
+ frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth);
+ frame.midLineWidth = 0;
+ style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this);
+ }
+
+ //finally the rest of the space
+ p.setClipRegion(emptyArea);
+ menuOpt.state = QStyle::State_None;
+ menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.rect = rect();
+ menuOpt.menuRect = rect();
+ style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
+}
+
+#ifndef QT_NO_WHEELEVENT
+/*!
+ \reimp
+*/
+void QMenu::wheelEvent(QWheelEvent *e)
+{
+ Q_D(QMenu);
+ if (d->scroll && rect().contains(e->pos()))
+ d->scrollMenu(e->delta() > 0 ?
+ QMenuPrivate::QMenuScroller::ScrollUp : QMenuPrivate::QMenuScroller::ScrollDown);
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QMenu::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QMenu);
+ if (d->aboutToHide || d->mouseEventTaken(e))
+ return;
+ if (!rect().contains(e->pos())) {
+ if (d->noReplayFor
+ && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
+ setAttribute(Qt::WA_NoMouseReplay);
+ if (d->eventLoop) // synchronous operation
+ d->syncAction = 0;
+ d->hideUpToMenuBar();
+ return;
+ }
+ d->mouseDown = this;
+
+ QAction *action = d->actionAt(e->pos());
+ d->setCurrentAction(action, 20);
+ update();
+}
+
+/*!
+ \reimp
+*/
+void QMenu::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QMenu);
+ if (d->aboutToHide || d->mouseEventTaken(e))
+ return;
+ if(d->mouseDown != this) {
+ d->mouseDown = 0;
+ return;
+ }
+
+ d->mouseDown = 0;
+ d->setSyncAction();
+ QAction *action = d->actionAt(e->pos());
+
+ if (action && action == d->currentAction) {
+ if (!action->menu()){
+#if defined(Q_WS_WIN)
+ //On Windows only context menus can be activated with the right button
+ if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
+#endif
+ d->activateAction(action, QAction::Trigger);
+ }
+ } else if (d->hasMouseMoved(e->globalPos())) {
+ d->hideUpToMenuBar();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMenu::changeEvent(QEvent *e)
+{
+ Q_D(QMenu);
+ if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange ||
+ e->type() == QEvent::LayoutDirectionChange) {
+ d->itemsDirty = 1;
+ setMouseTracking(style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, this));
+ if (isVisible())
+ resize(sizeHint());
+ if (!style()->styleHint(QStyle::SH_Menu_Scrollable, 0, this)) {
+ delete d->scroll;
+ d->scroll = 0;
+ } else if (!d->scroll) {
+ d->scroll = new QMenuPrivate::QMenuScroller;
+ d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
+ }
+ } else if (e->type() == QEvent::EnabledChange) {
+ if (d->tornPopup) // torn-off menu
+ d->tornPopup->setEnabled(isEnabled());
+ d->menuAction->setEnabled(isEnabled());
+ if (d->platformMenu)
+ d->platformMenu->setMenuEnabled(isEnabled());
+ }
+ QWidget::changeEvent(e);
+}
+
+
+/*!
+ \reimp
+*/
+bool
+QMenu::event(QEvent *e)
+{
+ Q_D(QMenu);
+ switch (e->type()) {
+ case QEvent::Polish:
+ d->updateLayoutDirection();
+ break;
+ case QEvent::ShortcutOverride: {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(e);
+ if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down
+ || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right
+ || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
+ || kev->key() == Qt::Key_Escape) {
+ e->accept();
+ return true;
+ }
+ }
+ break;
+ case QEvent::KeyPress: {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
+ keyPressEvent(ke);
+ return true;
+ }
+ } break;
+ case QEvent::ContextMenu:
+ if(d->menuDelayTimer.isActive()) {
+ d->menuDelayTimer.stop();
+ internalDelayedPopup();
+ }
+ break;
+ case QEvent::Resize: {
+ QStyleHintReturnMask menuMask;
+ QStyleOption option;
+ option.initFrom(this);
+ if (style()->styleHint(QStyle::SH_Menu_Mask, &option, this, &menuMask)) {
+ setMask(menuMask.region);
+ }
+ d->itemsDirty = 1;
+ d->updateActionRects();
+ break; }
+ case QEvent::Show:
+ d->mouseDown = 0;
+ d->updateActionRects();
+ if (d->currentAction)
+ d->popupAction(d->currentAction, 0, false);
+ break;
+#ifndef QT_NO_WHATSTHIS
+ case QEvent::QueryWhatsThis:
+ e->setAccepted(d->whatsThis.size());
+ if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
+ if (action->whatsThis().size() || action->menu())
+ e->accept();
+ }
+ return true;
+#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ case QEvent::LanguageChange: {
+ d->selectAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::SelectSoftKey));
+ d->cancelAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::CancelSoftKey));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ return QWidget::event(e);
+}
+
+/*!
+ \reimp
+*/
+bool QMenu::focusNextPrevChild(bool next)
+{
+ setFocus();
+ QKeyEvent ev(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
+ keyPressEvent(&ev);
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QMenu::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QMenu);
+ d->updateActionRects();
+ int key = e->key();
+ if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
+ if (key == Qt::Key_Left)
+ key = Qt::Key_Right;
+ else if (key == Qt::Key_Right)
+ key = Qt::Key_Left;
+ }
+#ifndef Q_OS_MAC
+ if (key == Qt::Key_Tab) //means down
+ key = Qt::Key_Down;
+ if (key == Qt::Key_Backtab) //means up
+ key = Qt::Key_Up;
+#endif
+
+ bool key_consumed = false;
+ switch(key) {
+ case Qt::Key_Home:
+ key_consumed = true;
+ if (d->scroll)
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
+ break;
+ case Qt::Key_End:
+ key_consumed = true;
+ if (d->scroll)
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
+ break;
+ case Qt::Key_PageUp:
+ key_consumed = true;
+ if (d->currentAction && d->scroll) {
+ if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollUp, true, true);
+ else
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
+ }
+ break;
+ case Qt::Key_PageDown:
+ key_consumed = true;
+ if (d->currentAction && d->scroll) {
+ if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollDown, true, true);
+ else
+ d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
+ }
+ break;
+ case Qt::Key_Up:
+ case Qt::Key_Down: {
+ key_consumed = true;
+ QAction *nextAction = 0;
+ QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay;
+ if (!d->currentAction) {
+ if(key == Qt::Key_Down) {
+ for(int i = 0; i < d->actions.count(); ++i) {
+ QAction *act = d->actions.at(i);
+ if (d->actionRects.at(i).isNull())
+ continue;
+ if (!act->isSeparator() &&
+ (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
+ || act->isEnabled())) {
+ nextAction = act;
+ break;
+ }
+ }
+ } else {
+ for(int i = d->actions.count()-1; i >= 0; --i) {
+ QAction *act = d->actions.at(i);
+ if (d->actionRects.at(i).isNull())
+ continue;
+ if (!act->isSeparator() &&
+ (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
+ || act->isEnabled())) {
+ nextAction = act;
+ break;
+ }
+ }
+ }
+ } else {
+ for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) {
+ QAction *act = d->actions.at(i);
+ if (act == d->currentAction) {
+ if (key == Qt::Key_Up) {
+ for(int next_i = i-1; true; next_i--) {
+ if (next_i == -1) {
+ if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
+ break;
+ if (d->scroll)
+ scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
+ next_i = d->actionRects.count()-1;
+ }
+ QAction *next = d->actions.at(next_i);
+ if (next == d->currentAction)
+ break;
+ if (d->actionRects.at(next_i).isNull())
+ continue;
+ if (next->isSeparator() ||
+ (!next->isEnabled() &&
+ !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
+ continue;
+ nextAction = next;
+ if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) {
+ int topVisible = d->scrollerHeight();
+ if (d->tearoff)
+ topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
+ if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height())
+ scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
+ }
+ break;
+ }
+ if (!nextAction && d->tearoff)
+ d->tearoffHighlighted = 1;
+ } else {
+ y += d->actionRects.at(i).height();
+ for(int next_i = i+1; true; next_i++) {
+ if (next_i == d->actionRects.count()) {
+ if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
+ break;
+ if (d->scroll)
+ scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
+ next_i = 0;
+ }
+ QAction *next = d->actions.at(next_i);
+ if (next == d->currentAction)
+ break;
+ if (d->actionRects.at(next_i).isNull())
+ continue;
+ if (next->isSeparator() ||
+ (!next->isEnabled() &&
+ !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
+ continue;
+ nextAction = next;
+ if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) {
+ int bottomVisible = height() - d->scrollerHeight();
+ if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
+ bottomVisible -= d->scrollerHeight();
+ if (d->tearoff)
+ bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
+ if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible)
+ scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ y += d->actionRects.at(i).height();
+ }
+ }
+ if (nextAction) {
+ if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) {
+ d->scroll->scrollTimer.stop();
+ d->scrollMenu(nextAction, scroll_loc);
+ }
+ d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
+ }
+ break; }
+
+ case Qt::Key_Right:
+ if (d->currentAction && d->currentAction->isEnabled() && d->currentAction->menu()) {
+ d->popupAction(d->currentAction, 0, true);
+ key_consumed = true;
+ break;
+ }
+ //FALL THROUGH
+ case Qt::Key_Left: {
+ if (d->currentAction && !d->scroll) {
+ QAction *nextAction = 0;
+ if (key == Qt::Key_Left) {
+ QRect actionR = d->actionRect(d->currentAction);
+ for(int x = actionR.left()-1; !nextAction && x >= 0; x--)
+ nextAction = d->actionAt(QPoint(x, actionR.center().y()));
+ } else {
+ QRect actionR = d->actionRect(d->currentAction);
+ for(int x = actionR.right()+1; !nextAction && x < width(); x++)
+ nextAction = d->actionAt(QPoint(x, actionR.center().y()));
+ }
+ if (nextAction) {
+ d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
+ key_consumed = true;
+ }
+ }
+ if (!key_consumed && key == Qt::Key_Left && qobject_cast<QMenu*>(d->causedPopup.widget)) {
+ QPointer<QWidget> caused = d->causedPopup.widget;
+ d->hideMenu(this);
+ if (caused)
+ caused->setFocus();
+ key_consumed = true;
+ }
+ break; }
+
+ case Qt::Key_Alt:
+ if (d->tornoff)
+ break;
+
+ key_consumed = true;
+ if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this))
+ {
+ d->hideMenu(this);
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) {
+ mb->d_func()->setKeyboardMode(false);
+ }
+#endif
+ }
+ break;
+
+ case Qt::Key_Escape:
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Back:
+#endif
+ key_consumed = true;
+ if (d->tornoff) {
+ close();
+ return;
+ }
+ {
+ QPointer<QWidget> caused = d->causedPopup.widget;
+ d->hideMenu(this); // hide after getting causedPopup
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
+ mb->d_func()->setCurrentAction(d->menuAction);
+ mb->d_func()->setKeyboardMode(true);
+ }
+#endif
+ }
+ break;
+
+ case Qt::Key_Space:
+ if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
+ break;
+ // for motif, fall through
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+#endif
+ case Qt::Key_Return:
+ case Qt::Key_Enter: {
+ if (!d->currentAction) {
+ d->setFirstActionActive();
+ key_consumed = true;
+ break;
+ }
+
+ d->setSyncAction();
+
+ if (d->currentAction->menu())
+ d->popupAction(d->currentAction, 0, true);
+ else
+ d->activateAction(d->currentAction, QAction::Trigger);
+ key_consumed = true;
+ break; }
+
+#ifndef QT_NO_WHATSTHIS
+ case Qt::Key_F1:
+ if (!d->currentAction || d->currentAction->whatsThis().isNull())
+ break;
+ QWhatsThis::enterWhatsThisMode();
+ d->activateAction(d->currentAction, QAction::Trigger);
+ return;
+#endif
+ default:
+ key_consumed = false;
+ }
+
+ if (!key_consumed) { // send to menu bar
+ if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) &&
+ e->text().length()==1) {
+ bool activateAction = false;
+ QAction *nextAction = 0;
+ if (style()->styleHint(QStyle::SH_Menu_KeyboardSearch, 0, this) && !e->modifiers()) {
+ int best_match_count = 0;
+ d->searchBufferTimer.start(2000, this);
+ d->searchBuffer += e->text();
+ for(int i = 0; i < d->actions.size(); ++i) {
+ int match_count = 0;
+ if (d->actionRects.at(i).isNull())
+ continue;
+ QAction *act = d->actions.at(i);
+ const QString act_text = act->text();
+ for(int c = 0; c < d->searchBuffer.size(); ++c) {
+ if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
+ ++match_count;
+ }
+ if(match_count > best_match_count) {
+ best_match_count = match_count;
+ nextAction = act;
+ }
+ }
+ }
+#ifndef QT_NO_SHORTCUT
+ else {
+ int clashCount = 0;
+ QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
+ QChar c = e->text().at(0).toUpper();
+ for(int i = 0; i < d->actions.size(); ++i) {
+ if (d->actionRects.at(i).isNull())
+ continue;
+ QAction *act = d->actions.at(i);
+ QKeySequence sequence = QKeySequence::mnemonic(act->text());
+ int key = sequence[0] & 0xffff;
+ if (key == c.unicode()) {
+ clashCount++;
+ if (!first)
+ first = act;
+ if (act == d->currentAction)
+ currentSelected = act;
+ else if (!firstAfterCurrent && currentSelected)
+ firstAfterCurrent = act;
+ }
+ }
+ if (clashCount == 1)
+ activateAction = true;
+ if (clashCount >= 1) {
+ if (clashCount == 1 || !currentSelected || !firstAfterCurrent)
+ nextAction = first;
+ else
+ nextAction = firstAfterCurrent;
+ }
+ }
+#endif
+ if (nextAction) {
+ key_consumed = true;
+ if(d->scroll)
+ d->scrollMenu(nextAction, QMenuPrivate::QMenuScroller::ScrollCenter, false);
+ d->setCurrentAction(nextAction, 20, QMenuPrivate::SelectedFromElsewhere, true);
+ if (!nextAction->menu() && activateAction) {
+ d->setSyncAction();
+ d->activateAction(nextAction, QAction::Trigger);
+ }
+ }
+ }
+ if (!key_consumed) {
+#ifndef QT_NO_MENUBAR
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->topCausedWidget())) {
+ QAction *oldAct = mb->d_func()->currentAction;
+ QApplication::sendEvent(mb, e);
+ if (mb->d_func()->currentAction != oldAct)
+ key_consumed = true;
+ }
+#endif
+ }
+
+#ifdef Q_OS_WIN32
+ if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta))
+ QApplication::beep();
+#endif // Q_OS_WIN32
+ }
+ if (key_consumed)
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QMenu::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QMenu);
+ if (!isVisible() || d->aboutToHide || d->mouseEventTaken(e))
+ return;
+ d->motions++;
+ if (d->motions == 0) // ignore first mouse move event (see enterEvent())
+ return;
+ d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
+
+ QAction *action = d->actionAt(e->pos());
+ if (!action) {
+ if (d->hasHadMouse
+ && (!d->currentAction
+ || !(d->currentAction->menu() && d->currentAction->menu()->isVisible())))
+ d->setCurrentAction(0);
+ return;
+ } else if(e->buttons()) {
+ d->mouseDown = this;
+ }
+ if (d->sloppyRegion.contains(e->pos())) {
+ d->sloppyAction = action;
+ QMenuPrivate::sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6);
+ } else if (action != d->currentAction) {
+ d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMenu::enterEvent(QEvent *)
+{
+ d_func()->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
+}
+
+/*!
+ \reimp
+*/
+void QMenu::leaveEvent(QEvent *)
+{
+ Q_D(QMenu);
+ d->sloppyAction = 0;
+ if (!d->sloppyRegion.isEmpty())
+ d->sloppyRegion = QRegion();
+ if (!d->activeMenu && d->currentAction)
+ setActiveAction(0);
+}
+
+/*!
+ \reimp
+*/
+void
+QMenu::timerEvent(QTimerEvent *e)
+{
+ Q_D(QMenu);
+ if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
+ d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
+ if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
+ d->scroll->scrollTimer.stop();
+ } else if(d->menuDelayTimer.timerId() == e->timerId()) {
+ d->menuDelayTimer.stop();
+ internalDelayedPopup();
+ } else if(QMenuPrivate::sloppyDelayTimer == e->timerId()) {
+ killTimer(QMenuPrivate::sloppyDelayTimer);
+ QMenuPrivate::sloppyDelayTimer = 0;
+ internalSetSloppyAction();
+ } else if(d->searchBufferTimer.timerId() == e->timerId()) {
+ d->searchBuffer.clear();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMenu::actionEvent(QActionEvent *e)
+{
+ Q_D(QMenu);
+ d->itemsDirty = 1;
+ setAttribute(Qt::WA_Resized, false);
+ if (d->tornPopup)
+ d->tornPopup->syncWithMenu(this, e);
+ if (e->type() == QEvent::ActionAdded) {
+ if(!d->tornoff) {
+ connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
+ connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
+ }
+ if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
+ QWidget *widget = wa->requestWidget(this);
+ if (widget)
+ d->widgetItems.insert(wa, widget);
+ }
+ } else if (e->type() == QEvent::ActionRemoved) {
+ e->action()->disconnect(this);
+ if (e->action() == d->currentAction)
+ d->currentAction = 0;
+ if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
+ if (QWidget *widget = d->widgetItems.value(wa))
+ wa->releaseWidget(widget);
+ }
+ d->widgetItems.remove(e->action());
+ }
+
+ if (d->platformMenu) {
+ if (e->type() == QEvent::ActionAdded)
+ d->platformMenu->addAction(e->action(), e->before());
+ else if (e->type() == QEvent::ActionRemoved)
+ d->platformMenu->removeAction(e->action());
+ else if (e->type() == QEvent::ActionChanged)
+ d->platformMenu->syncAction(e->action());
+ }
+
+#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
+ if (!d->wce_menu)
+ d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
+ if (e->type() == QEvent::ActionAdded)
+ d->wce_menu->addAction(e->action(), d->wce_menu->findAction(e->before()));
+ else if (e->type() == QEvent::ActionRemoved)
+ d->wce_menu->removeAction(e->action());
+ else if (e->type() == QEvent::ActionChanged)
+ d->wce_menu->syncAction(e->action());
+#endif
+
+#ifdef Q_WS_S60
+ if (!d->symbian_menu)
+ d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate;
+ if (e->type() == QEvent::ActionAdded)
+ d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before()));
+ else if (e->type() == QEvent::ActionRemoved)
+ d->symbian_menu->removeAction(e->action());
+ else if (e->type() == QEvent::ActionChanged)
+ d->symbian_menu->syncAction(e->action());
+#endif
+ if (isVisible()) {
+ d->updateActionRects();
+ resize(sizeHint());
+ update();
+ }
+}
+
+/*!
+ \internal
+*/
+void QMenu::internalSetSloppyAction()
+{
+ if (d_func()->sloppyAction)
+ d_func()->setCurrentAction(d_func()->sloppyAction, 0);
+}
+
+/*!
+ \internal
+*/
+void QMenu::internalDelayedPopup()
+{
+ Q_D(QMenu);
+
+ //hide the current item
+ if (QMenu *menu = d->activeMenu) {
+ d->activeMenu = 0;
+ d->hideMenu(menu);
+ }
+
+ if (!d->currentAction || !d->currentAction->isEnabled() || !d->currentAction->menu() ||
+ !d->currentAction->menu()->isEnabled() || d->currentAction->menu()->isVisible())
+ return;
+
+ //setup
+ d->activeMenu = d->currentAction->menu();
+ d->activeMenu->d_func()->causedPopup.widget = this;
+ d->activeMenu->d_func()->causedPopup.action = d->currentAction;
+
+ int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
+ const QRect actionRect(d->actionRect(d->currentAction));
+ const QSize menuSize(d->activeMenu->sizeHint());
+ const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top())));
+
+ QPoint pos(rightPos);
+
+ //calc sloppy focus buffer
+ if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) {
+ QPoint cur = QCursor::pos();
+ if (actionRect.contains(mapFromGlobal(cur))) {
+ QPoint pts[4];
+ pts[0] = QPoint(cur.x(), cur.y() - 2);
+ pts[3] = QPoint(cur.x(), cur.y() + 2);
+ if (pos.x() >= cur.x()) {
+ pts[1] = QPoint(geometry().right(), pos.y());
+ pts[2] = QPoint(geometry().right(), pos.y() + menuSize.height());
+ } else {
+ pts[1] = QPoint(pos.x() + menuSize.width(), pos.y());
+ pts[2] = QPoint(pos.x() + menuSize.width(), pos.y() + menuSize.height());
+ }
+ QPolygon points(4);
+ for(int i = 0; i < 4; i++)
+ points.setPoint(i, mapFromGlobal(pts[i]));
+ d->sloppyRegion = QRegion(points);
+ }
+ }
+
+ //do the popup
+ d->activeMenu->popup(pos);
+}
+
+/*!
+ \fn void QMenu::addAction(QAction *action)
+ \overload
+
+ Appends the action \a action to the menu's list of actions.
+
+ \sa QMenuBar::addAction(), QWidget::addAction()
+*/
+
+/*!
+ \fn void QMenu::aboutToHide()
+ \since 4.2
+
+ This signal is emitted just before the menu is hidden from the user.
+
+ \sa aboutToShow(), hide()
+*/
+
+/*!
+ \fn void QMenu::aboutToShow()
+
+ This signal is emitted just before the menu is shown to the user.
+
+ \sa aboutToHide(), show()
+*/
+
+/*!
+ \fn void QMenu::triggered(QAction *action)
+
+ This signal is emitted when an action in this menu is triggered.
+
+ \a action is the action that caused the signal to be emitted.
+
+ Normally, you connect each menu action's \l{QAction::}{triggered()} signal
+ to its own custom slot, but sometimes you will want to connect several
+ actions to a single slot, for example, when you have a group of closely
+ related actions, such as "left justify", "center", "right justify".
+
+ \note This signal is emitted for the main parent menu in a hierarchy.
+ Hence, only the parent menu needs to be connected to a slot; sub-menus need
+ not be connected.
+
+ \sa hovered(), QAction::triggered()
+*/
+
+/*!
+ \fn void QMenu::hovered(QAction *action)
+
+ This signal is emitted when a menu action is highlighted; \a action
+ is the action that caused the signal to be emitted.
+
+ Often this is used to update status information.
+
+ \sa triggered(), QAction::hovered()
+*/
+
+
+/*!\internal
+*/
+void QMenu::setNoReplayFor(QWidget *noReplayFor)
+{
+#ifdef Q_WS_WIN
+ d_func()->noReplayFor = noReplayFor;
+#else
+ Q_UNUSED(noReplayFor);
+#endif
+}
+
+/*!\internal
+*/
+QPlatformMenu *QMenu::platformMenu()
+{
+
+ return d_func()->platformMenu;
+}
+
+/*!
+ \property QMenu::separatorsCollapsible
+ \since 4.2
+
+ \brief whether consecutive separators should be collapsed
+
+ This property specifies whether consecutive separators in the menu
+ should be visually collapsed to a single one. Separators at the
+ beginning or the end of the menu are also hidden.
+
+ By default, this property is true.
+*/
+bool QMenu::separatorsCollapsible() const
+{
+ Q_D(const QMenu);
+ return d->collapsibleSeparators;
+}
+
+void QMenu::setSeparatorsCollapsible(bool collapse)
+{
+ Q_D(QMenu);
+ if (d->collapsibleSeparators == collapse)
+ return;
+
+ d->collapsibleSeparators = collapse;
+ d->itemsDirty = 1;
+ if (isVisible()) {
+ d->updateActionRects();
+ update();
+ }
+ if (d->platformMenu)
+ d->platformMenu->syncSeparatorsCollapsible(collapse);
+}
+
+QT_END_NAMESPACE
+
+// for private slots
+#include "moc_qmenu.cpp"
+#include "qmenu.moc"
+
+#endif // QT_NO_MENU
diff --git a/src/widgets/widgets/qmenu.h b/src/widgets/widgets/qmenu.h
new file mode 100644
index 0000000000..49bf8295ec
--- /dev/null
+++ b/src/widgets/widgets/qmenu.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMENU_H
+#define QMENU_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtCore/qstring.h>
+#include <QtWidgets/qicon.h>
+#include <QtWidgets/qaction.h>
+#include <QtWidgets/qplatformmenu_qpa.h>
+
+#ifdef Q_WS_WINCE
+#include <windef.h> // for HMENU
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MENU
+
+class QMenuPrivate;
+class QStyleOptionMenuItem;
+
+class Q_WIDGETS_EXPORT QMenu : public QWidget
+{
+private:
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QMenu)
+
+ Q_PROPERTY(bool tearOffEnabled READ isTearOffEnabled WRITE setTearOffEnabled)
+ Q_PROPERTY(QString title READ title WRITE setTitle)
+ Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
+ Q_PROPERTY(bool separatorsCollapsible READ separatorsCollapsible WRITE setSeparatorsCollapsible)
+
+public:
+ explicit QMenu(QWidget *parent = 0);
+ explicit QMenu(const QString &title, QWidget *parent = 0);
+ ~QMenu();
+
+#ifdef Q_NO_USING_KEYWORD
+ inline void addAction(QAction *action) { QWidget::addAction(action); }
+#else
+ using QWidget::addAction;
+#endif
+ QAction *addAction(const QString &text);
+ QAction *addAction(const QIcon &icon, const QString &text);
+ QAction *addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut = 0);
+ QAction *addAction(const QIcon &icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut = 0);
+
+ QAction *addMenu(QMenu *menu);
+ QMenu *addMenu(const QString &title);
+ QMenu *addMenu(const QIcon &icon, const QString &title);
+
+ QAction *addSeparator();
+
+ QAction *insertMenu(QAction *before, QMenu *menu);
+ QAction *insertSeparator(QAction *before);
+
+ bool isEmpty() const;
+ void clear();
+
+ void setTearOffEnabled(bool);
+ bool isTearOffEnabled() const;
+
+ bool isTearOffMenuVisible() const;
+ void hideTearOffMenu();
+
+ void setDefaultAction(QAction *);
+ QAction *defaultAction() const;
+
+ void setActiveAction(QAction *act);
+ QAction *activeAction() const;
+
+ void popup(const QPoint &pos, QAction *at=0);
+ QAction *exec();
+ QAction *exec(const QPoint &pos, QAction *at=0);
+
+ // ### Qt 5: merge
+ static QAction *exec(QList<QAction*> actions, const QPoint &pos, QAction *at=0);
+ static QAction *exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent);
+
+ QSize sizeHint() const;
+
+ QRect actionGeometry(QAction *) const;
+ QAction *actionAt(const QPoint &) const;
+
+ QAction *menuAction() const;
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QIcon icon() const;
+ void setIcon(const QIcon &icon);
+
+ void setNoReplayFor(QWidget *widget);
+ QPlatformMenu *platformMenu();
+
+#ifdef Q_WS_WINCE
+ HMENU wceMenu();
+#endif
+
+ bool separatorsCollapsible() const;
+ void setSeparatorsCollapsible(bool collapse);
+
+Q_SIGNALS:
+ void aboutToShow();
+ void aboutToHide();
+ void triggered(QAction *action);
+ void hovered(QAction *action);
+
+protected:
+ int columnCount() const;
+
+ void changeEvent(QEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *);
+#endif
+ void enterEvent(QEvent *);
+ void leaveEvent(QEvent *);
+ void hideEvent(QHideEvent *);
+ void paintEvent(QPaintEvent *);
+ void actionEvent(QActionEvent *);
+ void timerEvent(QTimerEvent *);
+ bool event(QEvent *);
+ bool focusNextPrevChild(bool next);
+ void initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const;
+
+#ifdef Q_WS_WINCE
+ QAction* wceCommands(uint command);
+#endif
+
+private Q_SLOTS:
+ void internalSetSloppyAction();
+ void internalDelayedPopup();
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered())
+ Q_PRIVATE_SLOT(d_func(), void _q_actionHovered())
+ Q_PRIVATE_SLOT(d_func(), void _q_overrideMenuActionDestroyed())
+
+protected:
+ QMenu(QMenuPrivate &dd, QWidget* parent = 0);
+
+private:
+ Q_DISABLE_COPY(QMenu)
+
+ friend class QMenuBar;
+ friend class QMenuBarPrivate;
+ friend class QTornOffMenu;
+ friend class Q3PopupMenu;
+ friend class QComboBox;
+ friend class QAction;
+ friend class QToolButtonPrivate;
+ friend void qt_mac_emit_menuSignals(QMenu *menu, bool show);
+ friend void qt_mac_menu_emit_hovered(QMenu *menu, QAction *action);
+};
+
+#endif // QT_NO_MENU
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMENU_H
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
new file mode 100644
index 0000000000..df15512b3e
--- /dev/null
+++ b/src/widgets/widgets/qmenu_p.h
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMENU_P_H
+#define QMENU_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 "QtWidgets/qmenubar.h"
+#include "QtWidgets/qstyleoption.h"
+#ifdef Q_OS_MAC
+#include "QtWidgets/qmacdefines_mac.h"
+#endif
+#include "QtCore/qdatetime.h"
+#include "QtCore/qmap.h"
+#include "QtCore/qhash.h"
+#include "QtCore/qbasictimer.h"
+#include "private/qwidget_p.h"
+
+
+#ifdef Q_WS_S60
+class CEikMenuPane;
+#define QT_SYMBIAN_FIRST_MENU_ITEM 32000
+#define QT_SYMBIAN_LAST_MENU_ITEM 41999 // 10000 items ought to be enough for anybody...
+#endif
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_MENU
+
+#ifdef Q_WS_S60
+void qt_symbian_next_menu_from_action(QWidget* actionContainer);
+void qt_symbian_show_toplevel(CEikMenuPane* menuPane);
+void qt_symbian_show_submenu(CEikMenuPane* menuPane, int id);
+#endif // Q_WS_S60
+
+class QTornOffMenu;
+class QEventLoop;
+
+#ifdef Q_WS_WINCE
+struct QWceMenuAction {
+ uint command;
+ QPointer<QAction> action;
+ HMENU menuHandle;
+ QWceMenuAction() : menuHandle(0), command(0) {}
+};
+#endif
+#ifdef Q_WS_S60
+struct QSymbianMenuAction {
+ uint command;
+ int parent;
+ CEikMenuPane* menuPane;
+ QPointer<QAction> action;
+ QSymbianMenuAction() : command(0) {}
+};
+#endif
+
+class QMenuPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QMenu)
+public:
+ QMenuPrivate() : itemsDirty(0), maxIconWidth(0), tabWidth(0), ncols(0),
+ collapsibleSeparators(true), activationRecursionGuard(false), hasHadMouse(0), aboutToHide(0), motions(0),
+ currentAction(0),
+#ifdef QT_KEYPAD_NAVIGATION
+ selectAction(0),
+ cancelAction(0),
+#endif
+ scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
+ hasCheckableItems(0), sloppyAction(0), doChildEffects(false), platformMenu(0)
+
+#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
+ ,wce_menu(0)
+#endif
+#ifdef Q_WS_S60
+ ,symbian_menu(0)
+#endif
+ { }
+ ~QMenuPrivate()
+ {
+ delete scroll;
+ delete platformMenu;
+#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
+ delete wce_menu;
+#endif
+#ifdef Q_WS_S60
+ delete symbian_menu;
+#endif
+
+ }
+ void init();
+
+ static QMenuPrivate *get(QMenu *m) { return m->d_func(); }
+ int scrollerHeight() const;
+
+ //item calculations
+ mutable uint itemsDirty : 1;
+ mutable uint maxIconWidth, tabWidth;
+ QRect actionRect(QAction *) const;
+
+ mutable QVector<QRect> actionRects;
+ mutable QHash<QAction *, QWidget *> widgetItems;
+ void updateActionRects() const;
+ void updateActionRects(const QRect &screen) const;
+ QRect popupGeometry(const QWidget *widget) const;
+ QRect popupGeometry(int screen = -1) const;
+ mutable uint ncols : 4; //4 bits is probably plenty
+ uint collapsibleSeparators : 1;
+ QSize adjustMenuSizeForScreen(const QRect & screen);
+ int getLastVisibleAction() const;
+
+ bool activationRecursionGuard;
+
+ //selection
+ static QMenu *mouseDown;
+ QPoint mousePopupPos;
+ uint hasHadMouse : 1;
+ uint aboutToHide : 1;
+ int motions;
+ QAction *currentAction;
+#ifdef QT_KEYPAD_NAVIGATION
+ QAction *selectAction;
+ QAction *cancelAction;
+#endif
+ QBasicTimer menuDelayTimer;
+ enum SelectionReason {
+ SelectedFromKeyboard,
+ SelectedFromElsewhere
+ };
+ QWidget *topCausedWidget() const;
+ QAction *actionAt(QPoint p) const;
+ void setFirstActionActive();
+ void setCurrentAction(QAction *, int popup = -1, SelectionReason reason = SelectedFromElsewhere, bool activateFirst = false);
+ void popupAction(QAction *, int, bool);
+ void setSyncAction();
+
+ //scrolling support
+ struct QMenuScroller {
+ enum ScrollLocation { ScrollStay, ScrollBottom, ScrollTop, ScrollCenter };
+ enum ScrollDirection { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
+ uint scrollFlags : 2, scrollDirection : 2;
+ int scrollOffset;
+ QBasicTimer scrollTimer;
+
+ QMenuScroller() : scrollFlags(ScrollNone), scrollDirection(ScrollNone), scrollOffset(0) { }
+ ~QMenuScroller() { }
+ } *scroll;
+ void scrollMenu(QMenuScroller::ScrollLocation location, bool active=false);
+ void scrollMenu(QMenuScroller::ScrollDirection direction, bool page=false, bool active=false);
+ void scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active=false);
+
+ //synchronous operation (ie exec())
+ QEventLoop *eventLoop;
+ QPointer<QAction> syncAction;
+
+ //search buffer
+ QString searchBuffer;
+ QBasicTimer searchBufferTimer;
+
+ //passing of mouse events up the parent hierarchy
+ QPointer<QMenu> activeMenu;
+ bool mouseEventTaken(QMouseEvent *);
+
+ //used to walk up the popup list
+ struct QMenuCaused {
+ QPointer<QWidget> widget;
+ QPointer<QAction> action;
+ };
+ virtual QList<QPointer<QWidget> > calcCausedStack() const;
+ QMenuCaused causedPopup;
+ void hideUpToMenuBar();
+ void hideMenu(QMenu *menu, bool justRegister = false);
+
+ //index mappings
+ inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
+ inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
+
+ //tear off support
+ uint tearoff : 1, tornoff : 1, tearoffHighlighted : 1;
+ QPointer<QTornOffMenu> tornPopup;
+
+ mutable bool hasCheckableItems;
+
+ //sloppy selection
+ static int sloppyDelayTimer;
+ mutable QAction *sloppyAction;
+ QRegion sloppyRegion;
+
+ //default action
+ QPointer<QAction> defaultAction;
+
+ QAction *menuAction;
+ QAction *defaultMenuAction;
+
+ void setOverrideMenuAction(QAction *);
+ void _q_overrideMenuActionDestroyed();
+
+ //firing of events
+ void activateAction(QAction *, QAction::ActionEvent, bool self=true);
+ void activateCausedStack(const QList<QPointer<QWidget> > &, QAction *, QAction::ActionEvent, bool);
+
+ void _q_actionTriggered();
+ void _q_actionHovered();
+
+ bool hasMouseMoved(const QPoint &globalPos);
+
+ void updateLayoutDirection();
+
+ //menu fading/scrolling effects
+ bool doChildEffects;
+
+ QPlatformMenu *platformMenu;
+
+ QPointer<QAction> actionAboutToTrigger;
+
+#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
+ struct QWceMenuPrivate {
+ QList<QWceMenuAction*> actionItems;
+ HMENU menuHandle;
+ QWceMenuPrivate();
+ ~QWceMenuPrivate();
+ void addAction(QAction *, QWceMenuAction* =0);
+ void addAction(QWceMenuAction *, QWceMenuAction* =0);
+ void syncAction(QWceMenuAction *);
+ inline void syncAction(QAction *a) { syncAction(findAction(a)); }
+ void removeAction(QWceMenuAction *);
+ void rebuild();
+ inline void removeAction(QAction *a) { removeAction(findAction(a)); }
+ inline QWceMenuAction *findAction(QAction *a) {
+ for(int i = 0; i < actionItems.size(); i++) {
+ QWceMenuAction *act = actionItems[i];
+ if(a == act->action)
+ return act;
+ }
+ return 0;
+ }
+ } *wce_menu;
+ HMENU wceMenu();
+ QAction* wceCommands(uint command);
+#endif
+#if defined(Q_WS_S60)
+ struct QSymbianMenuPrivate {
+ QList<QSymbianMenuAction*> actionItems;
+ QSymbianMenuPrivate();
+ ~QSymbianMenuPrivate();
+ void addAction(QAction *, QSymbianMenuAction* =0);
+ void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0);
+ void syncAction(QSymbianMenuAction *);
+ inline void syncAction(QAction *a) { syncAction(findAction(a)); }
+ void removeAction(QSymbianMenuAction *);
+ void rebuild(bool reCreate = false);
+ inline void removeAction(QAction *a) { removeAction(findAction(a)); }
+ inline QSymbianMenuAction *findAction(QAction *a) {
+ for(int i = 0; i < actionItems.size(); i++) {
+ QSymbianMenuAction *act = actionItems[i];
+ if(a == act->action)
+ return act;
+ }
+ return 0;
+ }
+ } *symbian_menu;
+#endif
+ QPointer<QWidget> noReplayFor;
+};
+
+#endif // QT_NO_MENU
+
+QT_END_NAMESPACE
+
+#endif // QMENU_P_H
diff --git a/src/widgets/widgets/qmenu_symbian.cpp b/src/widgets/widgets/qmenu_symbian.cpp
new file mode 100644
index 0000000000..4250601f98
--- /dev/null
+++ b/src/widgets/widgets/qmenu_symbian.cpp
@@ -0,0 +1,464 @@
+/****************************************************************************
+**
+** 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 S60 port of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmenu.h"
+#include "qapplication.h"
+#include "qevent.h"
+#include "qstyle.h"
+#include "qdebug.h"
+#include "qwidgetaction.h"
+#include <private/qapplication_p.h>
+#include <private/qmenu_p.h>
+#include <private/qmenubar_p.h>
+#include <private/qt_s60_p.h>
+#include <QtCore/qlibrary.h>
+
+#ifdef Q_WS_S60
+#include <eikmenub.h>
+#include <eikmenup.h>
+#include <eikaufty.h>
+#include <eikbtgpc.h>
+#include <avkon.rsg>
+#endif
+
+#if !defined(QT_NO_MENUBAR) && defined(Q_WS_S60)
+
+QT_BEGIN_NAMESPACE
+
+typedef QMultiHash<QWidget *, QMenuBarPrivate *> MenuBarHash;
+Q_GLOBAL_STATIC(MenuBarHash, menubars)
+
+struct SymbianMenuItem
+{
+ int id;
+ CEikMenuPaneItem::SData menuItemData;
+ QList<SymbianMenuItem*> children;
+ QAction* action;
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QAction, contextAction, (0))
+
+static QList<SymbianMenuItem*> symbianMenus;
+static QList<QMenuBar*> nativeMenuBars;
+static uint qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
+static QPointer<QWidget> widgetWithContextMenu;
+static QList<QAction*> contextMenuActionList;
+static QWidget* actionMenu = NULL;
+static int contexMenuCommand=0;
+
+bool menuExists()
+{
+ QWidget *w = qApp->activeWindow();
+ QMenuBarPrivate *mb = menubars()->value(w);
+ if ((!mb) && !menubars()->count())
+ return false;
+ return true;
+}
+
+static bool hasContextMenu(QWidget* widget)
+{
+ if (!widget)
+ return false;
+ const Qt::ContextMenuPolicy policy = widget->contextMenuPolicy();
+ if (policy != Qt::NoContextMenu && policy != Qt::PreventContextMenu ) {
+ return true;
+ }
+ return false;
+}
+
+static SymbianMenuItem* qt_symbian_find_menu(int id, const QList<SymbianMenuItem*> &parent)
+{
+ int index=0;
+ while (index < parent.count()) {
+ SymbianMenuItem* temp = parent[index];
+ if (temp->menuItemData.iCascadeId == id)
+ return temp;
+ else if (temp->menuItemData.iCascadeId != 0) {
+ SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children);
+ if (result)
+ return result;
+ }
+ index++;
+ }
+ return 0;
+}
+
+static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList<SymbianMenuItem*> &parent)
+{
+ int index=0;
+ while (index < parent.count()) {
+ SymbianMenuItem* temp = parent[index];
+ if (temp->menuItemData.iCascadeId != 0) {
+ SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children);
+ if (result)
+ return result;
+ }
+ else if (temp->menuItemData.iCommandId == id)
+ return temp;
+ index++;
+
+ }
+ return 0;
+}
+
+static void qt_symbian_insert_action(QSymbianMenuAction* action, QList<SymbianMenuItem*>* parent)
+{
+ if (action->action->isVisible()) {
+ if (action->action->isSeparator())
+ return;
+
+ Q_ASSERT_X(action->command <= QT_SYMBIAN_LAST_MENU_ITEM, "qt_symbian_insert_action",
+ "Too many menu actions");
+
+ const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut);
+ QString actionText;
+ if (underlineShortCut)
+ actionText = action->action->text().left(CEikMenuPaneItem::SData::ENominalTextLength);
+ else
+ actionText = action->action->iconText().left(CEikMenuPaneItem::SData::ENominalTextLength);
+ TPtrC menuItemText = qt_QString2TPtrC(actionText);
+ if (action->action->menu()) {
+ SymbianMenuItem* menuItem = new SymbianMenuItem();
+ menuItem->menuItemData.iCascadeId = action->command;
+ menuItem->menuItemData.iCommandId = action->command;
+ menuItem->menuItemData.iFlags = 0;
+ menuItem->menuItemData.iText = menuItemText;
+ menuItem->action = action->action;
+ if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() )
+ menuItem->menuItemData.iFlags |= EEikMenuItemDimmed;
+ parent->append(menuItem);
+
+ if (action->action->menu()->actions().size() > 0) {
+ for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) {
+ QScopedPointer<QSymbianMenuAction> symbianAction2(new QSymbianMenuAction);
+ symbianAction2->action = action->action->menu()->actions().at(c2);
+ QMenu * menu = symbianAction2->action->menu();
+ symbianAction2->command = qt_symbian_menu_static_cmd_id++;
+ qt_symbian_insert_action(symbianAction2.data(), &(menuItem->children));
+ }
+ }
+
+ } else {
+ SymbianMenuItem* menuItem = new SymbianMenuItem();
+ menuItem->menuItemData.iCascadeId = 0;
+ menuItem->menuItemData.iCommandId = action->command;
+ menuItem->menuItemData.iFlags = 0;
+ menuItem->menuItemData.iText = menuItemText;
+ menuItem->action = action->action;
+ if (!action->action->isEnabled()){
+ menuItem->menuItemData.iFlags += EEikMenuItemDimmed;
+ }
+
+ if (action->action->isCheckable()) {
+ if (action->action->isChecked())
+ menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn;
+ else
+ menuItem->menuItemData.iFlags += EEikMenuItemCheckBox;
+ }
+ parent->append(menuItem);
+ }
+ }
+}
+
+void deleteAll(QList<SymbianMenuItem*> *items)
+{
+ while (!items->isEmpty()) {
+ SymbianMenuItem* temp = items->takeFirst();
+ deleteAll(&temp->children);
+ delete temp;
+ }
+}
+
+static void rebuildMenu()
+{
+ widgetWithContextMenu = 0;
+ QMenuBarPrivate *mb = 0;
+ QWidget *w = qApp->activeWindow();
+ QWidget* focusWidget = QApplication::focusWidget();
+ if (focusWidget) {
+ if (hasContextMenu(focusWidget))
+ widgetWithContextMenu = focusWidget;
+ }
+
+ if (w) {
+ mb = menubars()->value(w);
+ qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
+ deleteAll( &symbianMenus );
+ if (!mb)
+ return;
+ mb->symbian_menubar->rebuild();
+ }
+}
+
+#ifdef Q_WS_S60
+void qt_symbian_next_menu_from_action(QWidget *actionContainer)
+{
+ actionMenu = actionContainer;
+}
+
+void qt_symbian_show_toplevel( CEikMenuPane* menuPane)
+{
+ if (actionMenu) {
+ QMenuBarPrivate *mb = 0;
+ mb = menubars()->value(actionMenu);
+ qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
+ deleteAll( &symbianMenus );
+ Q_ASSERT(mb);
+ mb->symbian_menubar->rebuild();
+ for (int i = 0; i < symbianMenus.count(); ++i)
+ QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData));
+ actionMenu = NULL;
+ return;
+ }
+
+ if (!menuExists())
+ return;
+ rebuildMenu();
+ for (int i = 0; i < symbianMenus.count(); ++i)
+ QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData));
+}
+
+void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id)
+{
+ SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus);
+ if (menu) {
+ // Normally first AddMenuItemL call for menuPane will create the item array.
+ // However if we don't have any items, we still need the item array. Otherwise
+ // menupane will crash. That's why we create item array here manually, and
+ // AddMenuItemL will then use the existing array.
+ CEikMenuPane::CItemArray* itemArray = new CEikMenuPane::CItemArray;
+ Q_CHECK_PTR(itemArray);
+ menuPane->SetItemArray(itemArray);
+ menuPane->SetItemArrayOwnedExternally(EFalse);
+
+ for (int i = 0; i < menu->children.count(); ++i)
+ QT_TRAP_THROWING(menuPane->AddMenuItemL(menu->children.at(i)->menuItemData));
+ }
+}
+#endif // Q_WS_S60
+
+int QMenuBarPrivate::symbianCommands(int command)
+{
+ int ret = 0;
+
+ if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) {
+ QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0));
+ QCoreApplication::postEvent(widgetWithContextMenu, event);
+ ret = 1;
+ }
+
+ int size = nativeMenuBars.size();
+ for (int i = 0; i < nativeMenuBars.size(); ++i) {
+ SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus);
+ if (!menu)
+ continue;
+
+ emit nativeMenuBars.at(i)->triggered(menu->action);
+ menu->action->activate(QAction::Trigger);
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+
+void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent)
+{
+ Q_Q(QMenuBar);
+ if (parent) {
+ if(parent->isWindow()) {
+ menubars()->insert(q->window(), this);
+ symbian_menubar = new QSymbianMenuBarPrivate(this);
+ nativeMenuBars.append(q);
+ } else {
+ menubars()->insert(q->parentWidget(), this);
+ symbian_menubar = new QSymbianMenuBarPrivate(this);
+ nativeMenuBars.append(q);
+ }
+ }
+}
+
+void QMenuBarPrivate::symbianDestroyMenuBar()
+{
+ Q_Q(QMenuBar);
+ int index = nativeMenuBars.indexOf(q);
+ nativeMenuBars.removeAt(index);
+ menubars()->remove(q->window(), this);
+ menubars()->remove(q->parentWidget(), this);
+ rebuildMenu();
+ if (symbian_menubar)
+ delete symbian_menubar;
+ symbian_menubar = 0;
+}
+
+void QMenuBarPrivate::reparentMenuBar(QWidget *oldParent, QWidget *newParent)
+{
+ if (menubars()->contains(oldParent)) {
+ QMenuBarPrivate *object = menubars()->take(oldParent);
+ menubars()->insert(newParent, object);
+ }
+}
+
+QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar)
+{
+ d = menubar;
+}
+
+QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate()
+{
+ qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
+ deleteAll( &symbianMenus );
+ symbianMenus.clear();
+ d = 0;
+ rebuild();
+}
+
+QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate()
+{
+}
+
+QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate()
+{
+
+}
+
+void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before)
+{
+ QSymbianMenuAction *action = new QSymbianMenuAction;
+ action->action = a;
+ action->command = qt_symbian_menu_static_cmd_id++;
+ addAction(action, before);
+}
+
+void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before)
+{
+ if (!action)
+ return;
+ int before_index = actionItems.indexOf(before);
+ if (before_index < 0) {
+ before = 0;
+ before_index = actionItems.size();
+ }
+ actionItems.insert(before_index, action);
+}
+
+
+void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *)
+{
+ rebuild();
+}
+
+void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action)
+{
+ actionItems.removeAll(action);
+ delete action;
+ action = 0;
+ rebuild();
+}
+
+void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool)
+{
+}
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QAction *before)
+{
+ QSymbianMenuAction *action = new QSymbianMenuAction;
+ action->action = a;
+ action->command = qt_symbian_menu_static_cmd_id++;
+ addAction(action, findAction(before));
+}
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before)
+{
+ if (!action)
+ return;
+ int before_index = actionItems.indexOf(before);
+ if (before_index < 0) {
+ before = 0;
+ before_index = actionItems.size();
+ }
+ actionItems.insert(before_index, action);
+}
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*)
+{
+ rebuild();
+}
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action)
+{
+ actionItems.removeAll(action);
+ delete action;
+ rebuild();
+}
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList<QAction*> &actions)
+{
+ for (int i = 0; i <actions.size(); ++i) {
+ QScopedPointer<QSymbianMenuAction> symbianActionTopLevel(new QSymbianMenuAction);
+ symbianActionTopLevel->action = actions.at(i);
+ symbianActionTopLevel->parent = 0;
+ symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++;
+ qt_symbian_insert_action(symbianActionTopLevel.data(), &symbianMenus);
+ }
+}
+
+
+
+void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild()
+{
+ contexMenuCommand = 0;
+ qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
+ deleteAll( &symbianMenus );
+ if (d)
+ insertNativeMenuItems(d->actions);
+
+ contextMenuActionList.clear();
+ if (widgetWithContextMenu) {
+ contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems
+ contextAction()->setText(QMenuBar::tr("Actions"));
+ contextMenuActionList.append(contextAction());
+ insertNativeMenuItems(contextMenuActionList);
+ }
+}
+QT_END_NAMESPACE
+
+#endif //QT_NO_MENUBAR
diff --git a/src/widgets/widgets/qmenu_wince.cpp b/src/widgets/widgets/qmenu_wince.cpp
new file mode 100644
index 0000000000..b0c6c1bd12
--- /dev/null
+++ b/src/widgets/widgets/qmenu_wince.cpp
@@ -0,0 +1,668 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//Native menubars are only supported for Windows Mobile not the standard SDK/generic WinCE
+#ifdef Q_WS_WINCE
+#include "qmenu.h"
+#include "qt_windows.h"
+#include "qapplication.h"
+#include "qmainwindow.h"
+#include "qtoolbar.h"
+#include "qevent.h"
+#include "qstyle.h"
+#include "qdebug.h"
+#include "qwidgetaction.h"
+#include <private/qapplication_p.h>
+#include <private/qmenu_p.h>
+#include <private/qmenubar_p.h>
+
+#include "qmenu_wince_resource_p.h"
+
+#include <QtCore/qlibrary.h>
+#include <commctrl.h>
+#if Q_OS_WINCE_WM
+# include <windowsm.h>
+#endif
+
+#include "qguifunctions_wince.h"
+
+#ifndef QT_NO_MENUBAR
+
+#ifndef SHCMBF_EMPTYBAR
+#define SHCMBF_EMPTYBAR 0x0001
+#endif
+
+#ifndef SHCMBM_GETSUBMENU
+#define SHCMBM_GETSUBMENU (WM_USER + 401)
+#endif
+
+#ifdef Q_OS_WINCE_WM
+# define SHMBOF_NODEFAULT 0x00000001
+# define SHMBOF_NOTIFY 0x00000002
+# define SHCMBM_OVERRIDEKEY (WM_USER + 0x193)
+#endif
+
+extern bool qt_wince_is_smartphone();//defined in qguifunctions_wce.cpp
+extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wce.cpp
+
+QT_BEGIN_NAMESPACE
+
+static uint qt_wce_menu_static_cmd_id = 200;
+static QList<QMenuBar*> nativeMenuBars;
+
+struct qt_SHMENUBARINFO
+{
+ DWORD cbSize;
+ HWND hwndParent;
+ DWORD dwFlags;
+ UINT nToolBarId;
+ HINSTANCE hInstRes;
+ int nBmpId;
+ int cBmpImages;
+ HWND hwndMB;
+ COLORREF clrBk;
+};
+
+typedef BOOL (WINAPI *AygCreateMenuBar)(qt_SHMENUBARINFO*);
+typedef HRESULT (WINAPI *AygEnableSoftKey)(HWND,UINT,BOOL,BOOL);
+
+static bool aygResolved = false;
+static AygCreateMenuBar ptrCreateMenuBar = 0;
+static AygEnableSoftKey ptrEnableSoftKey = 0;
+
+static void resolveAygLibs()
+{
+ if (!aygResolved) {
+ aygResolved = true;
+ QLibrary aygLib(QLatin1String("aygshell"));
+ ptrCreateMenuBar = (AygCreateMenuBar) aygLib.resolve("SHCreateMenuBar");
+ ptrEnableSoftKey = (AygEnableSoftKey) aygLib.resolve("SHEnableSoftkey");
+ }
+}
+
+static void qt_wce_enable_soft_key(HWND handle, uint command)
+{
+ resolveAygLibs();
+ if (ptrEnableSoftKey)
+ ptrEnableSoftKey(handle, command, false, true);
+}
+
+static void qt_wce_disable_soft_key(HWND handle, uint command)
+{
+ resolveAygLibs();
+ if (ptrEnableSoftKey)
+ ptrEnableSoftKey(handle, command, false, false);
+}
+
+static void qt_wce_delete_action_list(QList<QWceMenuAction*> *list)
+{
+ for(QList<QWceMenuAction*>::Iterator it = list->begin(); it != list->end(); ++it) {
+ QWceMenuAction *action = (*it);
+ delete action;
+ action = 0;
+ }
+ list->clear();
+}
+
+//search for first QuitRole in QMenuBar
+static QAction* qt_wce_get_quit_action(QList<QAction *> actionItems)
+{
+ QAction *returnAction = 0;
+ for (int i = 0; i < actionItems.size(); ++i) {
+ QAction *action = actionItems.at(i);
+ if (action->menuRole() == QAction::QuitRole)
+ returnAction = action;
+ else
+ if (action->menu())
+ returnAction = qt_wce_get_quit_action(action->menu()->actions());
+ if (returnAction)
+ return returnAction; //return first action found
+ }
+ return 0; //nothing found;
+}
+
+static QAction* qt_wce_get_quit_action(QList<QWceMenuAction*> actionItems)
+{
+ for (int i = 0; i < actionItems.size(); ++i) {
+ if (actionItems.at(i)->action->menuRole() == QAction::QuitRole)
+ return actionItems.at(i)->action;
+ else if (actionItems.at(i)->action->menu()) {
+ QAction *returnAction = qt_wce_get_quit_action(actionItems.at(i)->action->menu()->actions());
+ if (returnAction)
+ return returnAction;
+ }
+ }
+ return 0;
+}
+
+static HMODULE qt_wce_get_module_handle()
+{
+ HMODULE module = 0; //handle to resources
+ if (!(module = GetModuleHandle(L"QtGui4"))) //release dynamic
+ if (!(module = GetModuleHandle(L"QtGuid4"))) //debug dynamic
+ module = (HINSTANCE)qWinAppInst(); //static
+ Q_ASSERT_X(module, "qt_wce_get_module_handle()", "cannot get handle to module?");
+ return module;
+}
+
+static void qt_wce_change_command(HWND menuHandle, int item, int command)
+{
+TBBUTTONINFOA tbbi;
+ memset(&tbbi,0,sizeof(tbbi));
+ tbbi.cbSize = sizeof(tbbi);
+ tbbi.dwMask = TBIF_COMMAND;
+ tbbi.idCommand = command;
+ SendMessage(menuHandle, TB_SETBUTTONINFO, item, (LPARAM)&tbbi);
+}
+
+static void qt_wce_rename_menu_item(HWND menuHandle, int item, const QString &newText)
+{
+ TBBUTTONINFOA tbbi;
+ memset(&tbbi,0,sizeof(tbbi));
+ tbbi.cbSize = sizeof(tbbi);
+ tbbi.dwMask = TBIF_TEXT;
+ QString text = newText;
+ text.remove(QChar::fromLatin1('&'));
+ tbbi.pszText = (LPSTR) text.utf16();
+ SendMessage(menuHandle, TB_SETBUTTONINFO, item, (LPARAM)&tbbi);
+}
+
+static HWND qt_wce_create_menubar(HWND parentHandle, HINSTANCE resourceHandle, int toolbarID, int flags = 0)
+{
+ resolveAygLibs();
+
+ if (ptrCreateMenuBar) {
+ qt_SHMENUBARINFO mbi;
+ memset(&mbi, 0, sizeof(qt_SHMENUBARINFO));
+ mbi.cbSize = sizeof(qt_SHMENUBARINFO);
+ mbi.hwndParent = parentHandle;
+ mbi.hInstRes = resourceHandle;
+ mbi.dwFlags = flags;
+ mbi.nToolBarId = toolbarID;
+
+ if (ptrCreateMenuBar(&mbi)) {
+#ifdef Q_OS_WINCE_WM
+ // Tell the menu bar that we want to override hot key behaviour.
+ LPARAM lparam = MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY,
+ SHMBOF_NODEFAULT | SHMBOF_NOTIFY);
+ SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, lparam);
+#endif
+ return mbi.hwndMB;
+ }
+ }
+ return 0;
+}
+
+static void qt_wce_insert_action(HMENU menu, QWceMenuAction *action)
+{
+ Q_ASSERT_X(menu, "AppendMenu", "menu is 0");
+ if (action->action->isVisible()) {
+ int flags;
+ action->action->isEnabled() ? flags = MF_ENABLED : flags = MF_GRAYED;
+
+ QString text = action->action->iconText();
+ text.remove(QChar::fromLatin1('&'));
+ if (action->action->isSeparator()) {
+ AppendMenu (menu, MF_SEPARATOR , 0, 0);
+ }
+ else if (action->action->menu()) {
+ text.remove(QChar::fromLatin1('&'));
+ AppendMenu (menu, MF_STRING | flags | MF_POPUP,
+ (UINT) action->action->menu()->wceMenu(), reinterpret_cast<const wchar_t *> (text.utf16()));
+ }
+ else {
+ AppendMenu (menu, MF_STRING | flags, action->command, reinterpret_cast<const wchar_t *> (text.utf16()));
+ }
+ if (action->action->isCheckable())
+ if (action->action->isChecked())
+ CheckMenuItem(menu, action->command, MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(menu, action->command, MF_BYCOMMAND | MF_UNCHECKED);
+ }
+}
+
+// Removes all items from the menu without destroying the handles.
+static void qt_wce_clear_menu(HMENU hMenu)
+{
+ while (RemoveMenu(hMenu, 0, MF_BYPOSITION));
+}
+
+/*!
+ \internal
+
+ This function refreshes the native Windows CE menu.
+*/
+
+void QMenuBar::wceRefresh()
+{
+ for (int i = 0; i < nativeMenuBars.size(); ++i)
+ nativeMenuBars.at(i)->d_func()->wceRefresh();
+}
+
+void QMenuBarPrivate::wceRefresh()
+{
+ DrawMenuBar(wce_menubar->menubarHandle);
+}
+
+/*!
+ \internal
+
+ This function sends native Windows CE commands to Qt menus.
+*/
+
+QAction* QMenu::wceCommands(uint command)
+{
+ Q_D(QMenu);
+ return d->wceCommands(command);
+}
+
+/*!
+ \internal
+
+ This function sends native Windows CE commands to Qt menu bars
+ and all their child menus.
+*/
+
+void QMenuBar::wceCommands(uint command)
+{
+ const HWND hwndActiveWindow = GetActiveWindow();
+ for (int i = 0; i < nativeMenuBars.size(); ++i) {
+ QMenuBarPrivate* nativeMenuBar = nativeMenuBars.at(i)->d_func();
+ if (hwndActiveWindow == nativeMenuBar->wce_menubar->parentWindowHandle)
+ nativeMenuBar->wceCommands(command);
+ }
+}
+
+bool QMenuBarPrivate::wceEmitSignals(QList<QWceMenuAction*> actions, uint command)
+{
+ QAction *foundAction = 0;
+ for (int i = 0; i < actions.size(); ++i) {
+ QWceMenuAction *action = actions.at(i);
+ if (action->action->menu()) {
+ foundAction = action->action->menu()->wceCommands(command);
+ if (foundAction)
+ break;
+ }
+ else if (action->command == command) {
+ action->action->activate(QAction::Trigger);
+ return true;
+ }
+ }
+ if (foundAction) {
+ emit q_func()->triggered(foundAction);
+ return true;
+ }
+ return false;
+}
+
+void QMenuBarPrivate::wceCommands(uint command)
+{
+ if (wceClassicMenu) {
+ for (int i = 0; i < wce_menubar->actionItemsClassic.size(); ++i)
+ wceEmitSignals(wce_menubar->actionItemsClassic.at(i), command);
+ } else {
+ if (wceEmitSignals(wce_menubar->actionItems, command)) {
+ return;
+ }
+ else if (wce_menubar->leftButtonIsMenu) {//check if command is on the left quick button
+ wceEmitSignals(wce_menubar->actionItemsLeftButton, command);
+ }
+ else if ((wce_menubar->leftButtonAction) && (command == wce_menubar->leftButtonCommand)) {
+ emit q_func()->triggered(wce_menubar->leftButtonAction);
+ wce_menubar->leftButtonAction->activate(QAction::Trigger);
+ }
+ }
+}
+
+QAction *QMenuPrivate::wceCommands(uint command)
+{
+ QAction *foundAction = 0;
+ for (int i = 0; i < wce_menu->actionItems.size(); ++i) {
+ if (foundAction)
+ break;
+ QWceMenuAction *action = wce_menu->actionItems.at(i);
+ if (action->action->menu()) {
+ foundAction = action->action->menu()->d_func()->wceCommands(command);
+ }
+ else if (action->command == command) {
+ activateAction(action->action, QAction::Trigger);
+ return action->action;
+ }
+ }
+ if (foundAction)
+ emit q_func()->triggered(foundAction);
+ return foundAction;
+}
+
+void QMenuBarPrivate::wceCreateMenuBar(QWidget *parent)
+{
+ Q_Q(QMenuBar);
+ wce_menubar = new QWceMenuBarPrivate(this);
+
+ wce_menubar->parentWindowHandle = parent ? parent->winId() : q->winId();
+ wce_menubar->leftButtonAction = defaultAction;
+
+ wce_menubar->menubarHandle = qt_wce_create_menubar(wce_menubar->parentWindowHandle, (HINSTANCE)qWinAppInst(), 0, SHCMBF_EMPTYBAR);
+ Q_ASSERT_X(wce_menubar->menubarHandle, "wceCreateMenuBar", "cannot create empty menu bar");
+ DrawMenuBar(wce_menubar->menubarHandle);
+ nativeMenuBars.append(q);
+ wceClassicMenu = (!qt_wince_is_smartphone() && !qt_wince_is_pocket_pc());
+}
+
+void QMenuBarPrivate::wceDestroyMenuBar()
+{
+ Q_Q(QMenuBar);
+ int index = nativeMenuBars.indexOf(q);
+ nativeMenuBars.removeAt(index);
+ if (wce_menubar) {
+ delete wce_menubar;
+ wce_menubar = 0;
+ }
+}
+
+QMenuBarPrivate::QWceMenuBarPrivate::QWceMenuBarPrivate(QMenuBarPrivate *menubar)
+: menubarHandle(0), menuHandle(0), leftButtonMenuHandle(0),
+ leftButtonAction(0), leftButtonIsMenu(false), d(menubar)
+{
+}
+
+QMenuBarPrivate::QWceMenuBarPrivate::~QWceMenuBarPrivate()
+{
+ if (menubarHandle)
+ DestroyWindow(menubarHandle);
+ qt_wce_delete_action_list(&actionItems);
+ qt_wce_delete_action_list(&actionItemsLeftButton);
+
+ for (int i=0; i<actionItemsClassic.size(); ++i)
+ if (!actionItemsClassic.value(i).empty())
+ qt_wce_delete_action_list(&actionItemsClassic[i]);
+ actionItemsClassic.clear();
+
+ menubarHandle = 0;
+ menuHandle = 0;
+ leftButtonMenuHandle = 0;
+ leftButtonCommand = 0;
+ QMenuBar::wceRefresh();
+}
+
+QMenuPrivate::QWceMenuPrivate::QWceMenuPrivate()
+: menuHandle(0)
+{
+}
+
+QMenuPrivate::QWceMenuPrivate::~QWceMenuPrivate()
+{
+ qt_wce_delete_action_list(&actionItems);
+ if (menuHandle)
+ DestroyMenu(menuHandle);
+}
+
+void QMenuPrivate::QWceMenuPrivate::addAction(QAction *a, QWceMenuAction *before)
+{
+ QWceMenuAction *action = new QWceMenuAction;
+ action->action = a;
+ action->command = qt_wce_menu_static_cmd_id++;
+ addAction(action, before);
+}
+
+void QMenuPrivate::QWceMenuPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before)
+{
+ if (!action)
+ return;
+ int before_index = actionItems.indexOf(before);
+ if (before_index < 0) {
+ before = 0;
+ before_index = actionItems.size();
+ }
+ actionItems.insert(before_index, action);
+ rebuild();
+}
+
+/*!
+ \internal
+
+ This function will return the HMENU used to create the native
+ Windows CE menu bar bindings.
+*/
+
+HMENU QMenu::wceMenu()
+{
+ return d_func()->wceMenu();
+}
+
+HMENU QMenuPrivate::wceMenu()
+{
+ if (!wce_menu)
+ wce_menu = new QWceMenuPrivate;
+ if (!wce_menu->menuHandle)
+ wce_menu->rebuild();
+ return wce_menu->menuHandle;
+}
+
+void QMenuPrivate::QWceMenuPrivate::rebuild()
+{
+ if (!menuHandle)
+ menuHandle = CreatePopupMenu();
+ else
+ qt_wce_clear_menu(menuHandle);
+
+ for (int i = 0; i < actionItems.size(); ++i) {
+ QWceMenuAction *action = actionItems.at(i);
+ action->menuHandle = menuHandle;
+ qt_wce_insert_action(menuHandle, action);
+ }
+ QMenuBar::wceRefresh();
+}
+
+void QMenuPrivate::QWceMenuPrivate::syncAction(QWceMenuAction *)
+{
+ rebuild();
+}
+
+void QMenuPrivate::QWceMenuPrivate::removeAction(QWceMenuAction *action)
+{
+ actionItems.removeAll(action);
+ delete action;
+ rebuild();
+}
+
+void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QAction *before)
+{
+ QWceMenuAction *action = new QWceMenuAction;
+ action->action = a;
+ action->command = qt_wce_menu_static_cmd_id++;
+ addAction(action, findAction(before));
+}
+
+void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before)
+{
+ if (!action)
+ return;
+ int before_index = actionItems.indexOf(before);
+ if (before_index < 0) {
+ before = 0;
+ before_index = actionItems.size();
+ }
+ actionItems.insert(before_index, action);
+ rebuild();
+}
+
+void QMenuBarPrivate::QWceMenuBarPrivate::syncAction(QWceMenuAction*)
+{
+ QMenuBar::wceRefresh();
+ rebuild();
+}
+
+void QMenuBarPrivate::QWceMenuBarPrivate::removeAction(QWceMenuAction *action)
+{
+ actionItems.removeAll(action);
+ delete action;
+ rebuild();
+}
+
+void QMenuBarPrivate::_q_updateDefaultAction()
+{
+ if (wce_menubar)
+ wce_menubar->rebuild();
+}
+
+void QMenuBarPrivate::QWceMenuBarPrivate::rebuild()
+{
+ d->q_func()->resize(0,0);
+ parentWindowHandle = d->q_func()->parentWidget() ? d->q_func()->parentWidget()->winId() : d->q_func()->winId();
+ if (d->wceClassicMenu) {
+ QList<QAction*> actions = d->actions;
+ int maxEntries;
+ int resourceHandle;
+ if (actions.size() < 5) {
+ maxEntries = 4;
+ resourceHandle = IDR_MAIN_MENU3;
+ } else if (actions.size() < 7) {
+ maxEntries = 6;
+ resourceHandle = IDR_MAIN_MENU4;
+ }
+ else {
+ maxEntries = 8;
+ resourceHandle = IDR_MAIN_MENU5;
+ }
+ Q_ASSERT_X(menubarHandle, "rebuild !created", "menubar already deleted");
+ qt_wce_clear_menu(menuHandle);
+ DestroyWindow(menubarHandle);
+ menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), resourceHandle);
+ Q_ASSERT_X(menubarHandle, "rebuild classic menu", "cannot create menubar from resource");
+ DrawMenuBar(menubarHandle);
+ QList<int> menu_ids;
+ QList<int> item_ids;
+ menu_ids << IDM_MENU1 << IDM_MENU2 << IDM_MENU3 << IDM_MENU4 << IDM_MENU5 << IDM_MENU6 << IDM_MENU7 << IDM_MENU8;
+ item_ids << IDM_ITEM1 << IDM_ITEM2 << IDM_ITEM3 << IDM_ITEM4 << IDM_ITEM5 << IDM_ITEM6 << IDM_ITEM7 << IDM_ITEM8;
+
+ for (int i = 0; i < actionItemsClassic.size(); ++i)
+ if (!actionItemsClassic.value(i).empty())
+ qt_wce_delete_action_list(&actionItemsClassic[i]);
+ actionItemsClassic.clear();
+
+ for (int i = 0; i < actions.size(); ++i) {
+ qt_wce_rename_menu_item(menubarHandle, menu_ids.at(i), actions.at(i)->text());
+ QList<QAction *> subActions = actions.at(i)->menu()->actions();
+ HMENU subMenuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0 , menu_ids.at(i));
+ DeleteMenu(subMenuHandle, item_ids.at(i), MF_BYCOMMAND);
+ for (int c = 0; c < subActions.size(); ++c) {
+ QList<QWceMenuAction*> list;
+ actionItemsClassic.append(list);
+ QWceMenuAction *action = new QWceMenuAction;
+ action->action = subActions.at(c);
+ action->command = qt_wce_menu_static_cmd_id++;
+ action->menuHandle = subMenuHandle;
+ actionItemsClassic.last().append(action);
+ qt_wce_insert_action(subMenuHandle, action);
+ }
+ }
+ for (int i = actions.size();i<maxEntries;++i) {
+ qt_wce_rename_menu_item(menubarHandle, menu_ids.at(i), QString());
+ qt_wce_disable_soft_key(menubarHandle, menu_ids.at(i));
+ }
+ } else {
+ leftButtonAction = d->defaultAction;
+ if (!leftButtonAction)
+ leftButtonAction = qt_wce_get_quit_action(actionItems);
+
+ leftButtonIsMenu = (leftButtonAction && leftButtonAction->menu());
+ Q_ASSERT_X(menubarHandle, "rebuild !created", "menubar already deleted");
+ qt_wce_clear_menu(menuHandle);
+ DestroyWindow(menubarHandle);
+ if (leftButtonIsMenu) {
+ menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), IDR_MAIN_MENU2);
+ Q_ASSERT_X(menubarHandle, "rebuild !created left menubar", "cannot create menubar from resource");
+ menuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_MENU);
+ Q_ASSERT_X(menuHandle, "rebuild !created", "IDM_MENU not found - invalid resource?");
+ DeleteMenu(menuHandle, IDM_ABOUT, MF_BYCOMMAND);
+ leftButtonMenuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_LEFTMENU);
+ Q_ASSERT_X(leftButtonMenuHandle, "rebuild !created", "IDM_LEFTMENU not found - invalid resource?");
+ DeleteMenu(leftButtonMenuHandle, IDM_VIEW, MF_BYCOMMAND);
+ } else {
+ menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), IDR_MAIN_MENU);
+ Q_ASSERT_X(menubarHandle, "rebuild !created no left menubar", "cannot create menubar from resource");
+ menuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_MENU);
+ Q_ASSERT_X(menuHandle, "rebuild !created", "IDM_MENU not found - invalid resource?");
+ DeleteMenu(menuHandle, IDM_ABOUT, MF_BYCOMMAND);
+ leftButtonMenuHandle = 0;
+ leftButtonCommand = qt_wce_menu_static_cmd_id++;
+ qt_wce_change_command(menubarHandle, IDM_EXIT, leftButtonCommand);
+ }
+
+ if (actionItems.size() == 0) {
+ qt_wce_rename_menu_item(menubarHandle, IDM_MENU, QLatin1String(""));
+ qt_wce_disable_soft_key(menubarHandle, IDM_MENU);
+ }
+ for (int i = 0; i < actionItems.size(); ++i) {
+ QWceMenuAction *action = actionItems.at(i);
+ action->menuHandle = menuHandle;
+ qt_wce_insert_action(menuHandle, action);
+ }
+ if (!leftButtonIsMenu) {
+ if (leftButtonAction) {
+ qt_wce_rename_menu_item(menubarHandle, leftButtonCommand, leftButtonAction->text());
+ qt_wce_enable_soft_key(menubarHandle, leftButtonCommand);
+ } else {
+ qt_wce_rename_menu_item(menubarHandle, leftButtonCommand, QLatin1String(""));
+ qt_wce_disable_soft_key(menubarHandle, leftButtonCommand);
+ }
+ } else {
+ qt_wce_rename_menu_item(menubarHandle, IDM_LEFTMENU, leftButtonAction->text());
+ QList<QAction *> actions = leftButtonAction->menu()->actions();
+ qt_wce_delete_action_list(&actionItemsLeftButton);
+ for (int i=0; i<actions.size(); ++i) {
+ QWceMenuAction *action = new QWceMenuAction;
+ action->action = actions.at(i);
+ action->command = qt_wce_menu_static_cmd_id++;
+ action->menuHandle = leftButtonMenuHandle;
+ actionItemsLeftButton.append(action);
+ qt_wce_insert_action(leftButtonMenuHandle, action);
+ }
+ }
+ }
+ DrawMenuBar(menubarHandle);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_MENUBAR
+#endif //Q_WS_WINCE
diff --git a/src/widgets/widgets/qmenu_wince.rc b/src/widgets/widgets/qmenu_wince.rc
new file mode 100644
index 0000000000..2540d9f43a
--- /dev/null
+++ b/src/widgets/widgets/qmenu_wince.rc
@@ -0,0 +1,231 @@
+#include "qmenu_wince_resource_p.h"
+
+#include <commctrl.h>
+#include "winuser.h"
+
+#if defined (_DEBUG) && defined(QT_DLL)
+#include "QtGuid_resource.rc"
+#elif defined(QT_DLL)
+#include "QtGui_resource.rc"
+#endif
+
+#define DIALOGEX DIALOG DISCARDABLE
+#define SHMENUBAR RCDATA
+#define I_IMAGENONE (-2)
+#define NOMENU 0xFFFF
+
+IDR_MAIN_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Menu"
+ BEGIN
+ MENUITEM "About", IDM_ABOUT
+ END
+END
+
+IDR_MAIN_MENU2 MENU DISCARDABLE
+BEGIN
+ POPUP "Menu"
+ BEGIN
+ MENUITEM "About", IDM_ABOUT
+ END
+ POPUP "Display"
+ BEGIN
+ MENUITEM "View", IDM_VIEW
+ END
+END
+
+
+IDR_MAIN_MENU3 MENU DISCARDABLE
+BEGIN
+ POPUP "Menu1"
+ BEGIN
+ MENUITEM "Item1", IDM_ITEM1
+ END
+ POPUP "Menu2"
+ BEGIN
+ MENUITEM "Item2", IDM_ITEM2
+ END
+ POPUP "Menu3"
+ BEGIN
+ MENUITEM "Item3", IDM_ITEM3
+ END
+ POPUP "Menu4"
+ BEGIN
+ MENUITEM "Item4", IDM_ITEM4
+ END
+END
+
+IDR_MAIN_MENU4 MENU DISCARDABLE
+BEGIN
+ POPUP "Menu1"
+ BEGIN
+ MENUITEM "Item1", IDM_ITEM1
+ END
+ POPUP "Menu2"
+ BEGIN
+ MENUITEM "Item2", IDM_ITEM2
+ END
+ POPUP "Menu3"
+ BEGIN
+ MENUITEM "Item3", IDM_ITEM3
+ END
+ POPUP "Menu4"
+ BEGIN
+ MENUITEM "Item4", IDM_ITEM4
+ END
+ POPUP "Menu5"
+ BEGIN
+ MENUITEM "Item5", IDM_ITEM5
+ END
+ POPUP "Menu6"
+ BEGIN
+ MENUITEM "Item6", IDM_ITEM6
+ END
+END
+
+IDR_MAIN_MENU5 MENU DISCARDABLE
+BEGIN
+ POPUP "Menu1"
+ BEGIN
+ MENUITEM "Item1", IDM_ITEM1
+ END
+ POPUP "Menu2"
+ BEGIN
+ MENUITEM "Item2", IDM_ITEM2
+ END
+ POPUP "Menu3"
+ BEGIN
+ MENUITEM "Item3", IDM_ITEM3
+ END
+ POPUP "Menu4"
+ BEGIN
+ MENUITEM "Item4", IDM_ITEM4
+ END
+ POPUP "Menu5"
+ BEGIN
+ MENUITEM "Item5", IDM_ITEM5
+ END
+ POPUP "Menu6"
+ BEGIN
+ MENUITEM "Item6", IDM_ITEM6
+ END
+ POPUP "Menu7"
+ BEGIN
+ MENUITEM "Item7", IDM_ITEM7
+ END
+ POPUP "Menu8"
+ BEGIN
+ MENUITEM "Item8", IDM_ITEM8
+ END
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EXIT "Exit"
+ IDS_MENU "Menu"
+ IDS_LEFTMENU "Display"
+ IDS_MENU1 "Menu__1"
+ IDS_MENU2 "Menu__2"
+ IDS_MENU3 "Menu__3"
+ IDS_MENU4 "Menu__4"
+ IDS_MENU5 "Menu__5"
+ IDS_MENU6 "Menu__6"
+ IDS_MENU7 "Menu__7"
+ IDS_MENU8 "Menu__8"
+END
+
+IDR_MAIN_MENU SHMENUBAR DISCARDABLE
+BEGIN
+ IDR_MAIN_MENU,
+ 2,
+
+ I_IMAGENONE, IDM_EXIT, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE,
+ IDS_EXIT, 0, NOMENU,
+
+ I_IMAGENONE, IDM_MENU, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU, 0, 0,
+END
+
+IDR_MAIN_MENU2 SHMENUBAR DISCARDABLE
+BEGIN
+ IDR_MAIN_MENU2,
+ 2,
+
+ I_IMAGENONE, IDM_LEFTMENU, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_LEFTMENU, 0, 1,
+
+ I_IMAGENONE, IDM_MENU, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU, 0, 0,
+END
+
+IDR_MAIN_MENU3 SHMENUBAR DISCARDABLE
+BEGIN
+ IDR_MAIN_MENU3,
+ 4,
+
+ I_IMAGENONE, IDM_MENU1, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU1, 0, 0,
+
+ I_IMAGENONE, IDM_MENU2, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU2, 0, 1,
+
+ I_IMAGENONE, IDM_MENU3, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU3, 0, 2,
+
+ I_IMAGENONE, IDM_MENU4, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU4, 0, 3,
+END
+
+IDR_MAIN_MENU4 SHMENUBAR DISCARDABLE
+BEGIN
+ IDR_MAIN_MENU4,
+ 6,
+
+ I_IMAGENONE, IDM_MENU1, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU1, 0, 0,
+
+ I_IMAGENONE, IDM_MENU2, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU2, 0, 1,
+
+ I_IMAGENONE, IDM_MENU3, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU3, 0, 2,
+
+ I_IMAGENONE, IDM_MENU4, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU4, 0, 3,
+
+ I_IMAGENONE, IDM_MENU5, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU5, 0, 4,
+
+ I_IMAGENONE, IDM_MENU6, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU6, 0, 5,
+END
+
+IDR_MAIN_MENU5 SHMENUBAR DISCARDABLE
+BEGIN
+ IDR_MAIN_MENU5,
+ 8,
+
+ I_IMAGENONE, IDM_MENU1, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU1, 0, 0,
+
+ I_IMAGENONE, IDM_MENU2, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU2, 0, 1,
+
+ I_IMAGENONE, IDM_MENU3, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU3, 0, 2,
+
+ I_IMAGENONE, IDM_MENU4, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU4, 0, 3,
+
+ I_IMAGENONE, IDM_MENU5, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU5, 0, 4,
+
+ I_IMAGENONE, IDM_MENU6, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU6, 0, 5,
+
+ I_IMAGENONE, IDM_MENU7, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU7, 0, 6,
+
+ I_IMAGENONE, IDM_MENU8, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
+ IDS_MENU8, 0, 7,
+END
diff --git a/src/widgets/widgets/qmenu_wince_resource_p.h b/src/widgets/widgets/qmenu_wince_resource_p.h
new file mode 100644
index 0000000000..42de05f319
--- /dev/null
+++ b/src/widgets/widgets/qmenu_wince_resource_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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
+
+#define IDR_MAIN_MENU 102
+#define IDR_MAIN_MENU2 103
+#define IDR_MAIN_MENU3 104
+#define IDS_EXIT 105
+#define IDS_MENU 106
+#define IDS_LEFTMENU 107
+#define IDM_ABOUT 108
+#define IDM_VIEW 109
+#define IDM_ITEM1 108
+#define IDM_ITEM2 109
+#define IDM_ITEM3 110
+#define IDM_ITEM4 111
+#define IDM_ITEM5 112
+#define IDM_ITEM6 113
+#define IDM_ITEM7 114
+#define IDM_ITEM8 115
+#define IDS_MENU1 116
+#define IDS_MENU2 117
+#define IDS_MENU3 118
+#define IDS_MENU4 119
+#define IDS_MENU5 120
+#define IDS_MENU6 121
+#define IDS_MENU7 122
+#define IDS_MENU8 123
+#define IDR_MAIN_MENU4 124
+#define IDR_MAIN_MENU5 125
+#define IDM_EXIT 40000
+#define IDM_MENU 40001
+#define IDM_LEFTMENU 40002
+#define IDM_MENU1 40003
+#define IDM_MENU2 40004
+#define IDM_MENU3 40005
+#define IDM_MENU4 40006
+#define IDM_MENU5 40007
+#define IDM_MENU6 40008
+#define IDM_MENU7 40009
+#define IDM_MENU8 40010
+
+QT_END_HEADER
+
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
new file mode 100644
index 0000000000..385df52adf
--- /dev/null
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -0,0 +1,2063 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qmenubar.h>
+
+#include <qstyle.h>
+#include <qlayout.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#ifndef QT_NO_ACCESSIBILITY
+# include <qaccessible.h>
+#endif
+#include <qpainter.h>
+#include <qstylepainter.h>
+#include <qevent.h>
+#include <qmainwindow.h>
+#include <qtoolbar.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+#include "private/qguiapplication_p.h"
+
+#ifndef QT_NO_MENUBAR
+
+#ifdef QT3_SUPPORT
+#include <private/qaction_p.h>
+#include <qmenudata.h>
+#endif
+
+#include "qmenu_p.h"
+#include "qmenubar_p.h"
+#include "qdebug.h"
+
+#ifdef Q_WS_WINCE
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp
+#endif
+
+#ifdef QT_SOFTKEYS_ENABLED
+#include <private/qsoftkeymanager_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMenuBarExtension : public QToolButton
+{
+public:
+ explicit QMenuBarExtension(QWidget *parent);
+
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *);
+};
+
+QMenuBarExtension::QMenuBarExtension(QWidget *parent)
+ : QToolButton(parent)
+{
+ setObjectName(QLatin1String("qt_menubar_ext_button"));
+ setAutoRaise(true);
+#ifndef QT_NO_MENU
+ setPopupMode(QToolButton::InstantPopup);
+#endif
+ setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, 0, parentWidget()));
+}
+
+void QMenuBarExtension::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ // We do not need to draw both extension arrows
+ opt.features &= ~QStyleOptionToolButton::HasMenu;
+ p.drawComplexControl(QStyle::CC_ToolButton, opt);
+}
+
+
+QSize QMenuBarExtension::sizeHint() const
+{
+ int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, 0, parentWidget());
+ return QSize(ext, ext);
+}
+
+
+/*!
+ \internal
+*/
+QAction *QMenuBarPrivate::actionAt(QPoint p) const
+{
+ for(int i = 0; i < actions.size(); ++i) {
+ if(actionRect(actions.at(i)).contains(p))
+ return actions.at(i);
+ }
+ return 0;
+}
+
+QRect QMenuBarPrivate::menuRect(bool extVisible) const
+{
+ Q_Q(const QMenuBar);
+
+ int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
+ QRect result = q->rect();
+ result.adjust(hmargin, 0, -hmargin, 0);
+
+ if (extVisible) {
+ if (q->isRightToLeft())
+ result.setLeft(result.left() + extension->sizeHint().width());
+ else
+ result.setWidth(result.width() - extension->sizeHint().width());
+ }
+
+ if (leftWidget && leftWidget->isVisible()) {
+ QSize sz = leftWidget->sizeHint();
+ if (q->isRightToLeft())
+ result.setRight(result.right() - sz.width());
+ else
+ result.setLeft(result.left() + sz.width());
+ }
+
+ if (rightWidget && rightWidget->isVisible()) {
+ QSize sz = rightWidget->sizeHint();
+ if (q->isRightToLeft())
+ result.setLeft(result.left() + sz.width());
+ else
+ result.setRight(result.right() - sz.width());
+ }
+
+ return result;
+}
+
+bool QMenuBarPrivate::isVisible(QAction *action)
+{
+ return !hiddenActions.contains(action);
+}
+
+void QMenuBarPrivate::updateGeometries()
+{
+ Q_Q(QMenuBar);
+ if(!itemsDirty)
+ return;
+ int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2);
+ int q_start = -1;
+ if(leftWidget || rightWidget) {
+ int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q)
+ + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
+ int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q)
+ + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
+ if (leftWidget && leftWidget->isVisible()) {
+ QSize sz = leftWidget->sizeHint();
+ q_width -= sz.width();
+ q_start = sz.width();
+ QPoint pos(hmargin, (q->height() - leftWidget->height()) / 2);
+ QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
+ leftWidget->setGeometry(vRect);
+ }
+ if (rightWidget && rightWidget->isVisible()) {
+ QSize sz = rightWidget->sizeHint();
+ q_width -= sz.width();
+ QPoint pos(q->width() - sz.width() - hmargin, vmargin);
+ QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
+ rightWidget->setGeometry(vRect);
+ }
+ }
+
+#ifdef Q_OS_MAC
+ if(q->isNativeMenuBar()) {//nothing to see here folks, move along..
+ itemsDirty = false;
+ return;
+ }
+#endif
+ calcActionRects(q_width, q_start);
+ currentAction = 0;
+#ifndef QT_NO_SHORTCUT
+ if(itemsDirty) {
+ for(int j = 0; j < shortcutIndexMap.size(); ++j)
+ q->releaseShortcut(shortcutIndexMap.value(j));
+ shortcutIndexMap.resize(0); // faster than clear
+ for(int i = 0; i < actions.count(); i++)
+ shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text())));
+ }
+#endif
+ itemsDirty = false;
+
+ hiddenActions.clear();
+ //this is the menu rectangle without any extension
+ QRect menuRect = this->menuRect(false);
+
+ //we try to see if the actions will fit there
+ bool hasHiddenActions = false;
+ for (int i = 0; i < actions.count(); ++i) {
+ const QRect &rect = actionRects.at(i);
+ if (rect.isValid() && !menuRect.contains(rect)) {
+ hasHiddenActions = true;
+ break;
+ }
+ }
+
+ //...and if not, determine the ones that fit on the menu with the extension visible
+ if (hasHiddenActions) {
+ menuRect = this->menuRect(true);
+ for (int i = 0; i < actions.count(); ++i) {
+ const QRect &rect = actionRects.at(i);
+ if (rect.isValid() && !menuRect.contains(rect)) {
+ hiddenActions.append(actions.at(i));
+ }
+ }
+ }
+
+ if (hiddenActions.count() > 0) {
+ QMenu *pop = extension->menu();
+ if (!pop) {
+ pop = new QMenu(q);
+ extension->setMenu(pop);
+ }
+ pop->clear();
+ pop->addActions(hiddenActions);
+
+ int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q);
+ int x = q->isRightToLeft()
+ ? menuRect.left() - extension->sizeHint().width() + 1
+ : menuRect.right();
+ extension->setGeometry(x, vmargin, extension->sizeHint().width(), menuRect.height() - vmargin*2);
+ extension->show();
+ } else {
+ extension->hide();
+ }
+ q->updateGeometry();
+#ifdef QT3_SUPPORT
+ if (parent) {
+ QMenubarUpdatedEvent menubarUpdated(q);
+ QApplication::sendEvent(parent, &menubarUpdated);
+ }
+#endif
+}
+
+QRect QMenuBarPrivate::actionRect(QAction *act) const
+{
+ const int index = actions.indexOf(act);
+
+ //makes sure the geometries are up-to-date
+ const_cast<QMenuBarPrivate*>(this)->updateGeometries();
+
+ if (index < 0 || index >= actionRects.count())
+ return QRect(); // that can happen in case of native menubar
+
+ return actionRects.at(index);
+}
+
+void QMenuBarPrivate::focusFirstAction()
+{
+ if(!currentAction) {
+ updateGeometries();
+ int index = 0;
+ while (index < actions.count() && actionRects.at(index).isNull()) ++index;
+ if (index < actions.count())
+ setCurrentAction(actions.at(index));
+ }
+}
+
+void QMenuBarPrivate::setKeyboardMode(bool b)
+{
+ Q_Q(QMenuBar);
+ if (b && !q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, q)) {
+ setCurrentAction(0);
+ return;
+ }
+ keyboardState = b;
+ if(b) {
+ QWidget *fw = QApplication::focusWidget();
+ if (fw != q)
+ keyboardFocusWidget = fw;
+ focusFirstAction();
+ q->setFocus(Qt::MenuBarFocusReason);
+ } else {
+ if(!popupState)
+ setCurrentAction(0);
+ if(keyboardFocusWidget) {
+ if (QApplication::focusWidget() == q)
+ keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason);
+ keyboardFocusWidget = 0;
+ }
+ }
+ q->update();
+}
+
+void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
+{
+ Q_Q(QMenuBar);
+ if(!action || !action->menu() || closePopupMode)
+ return;
+ popupState = true;
+ if (action->isEnabled() && action->menu()->isEnabled()) {
+ closePopupMode = 0;
+ activeMenu = action->menu();
+ activeMenu->d_func()->causedPopup.widget = q;
+ activeMenu->d_func()->causedPopup.action = action;
+
+ QRect adjustedActionRect = actionRect(action);
+ QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1)));
+ QSize popup_size = activeMenu->sizeHint();
+
+ //we put the popup menu on the screen containing the bottom-center of the action rect
+ QRect screenRect = QApplication::desktop()->screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0));
+ pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
+
+ const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height());
+ const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom());
+ const bool rtl = q->isRightToLeft();
+ const int actionWidth = adjustedActionRect.width();
+
+ if (!fitUp && !fitDown) { //we should shift the menu
+ bool shouldShiftToRight = !rtl;
+ if (rtl && popup_size.width() > pos.x())
+ shouldShiftToRight = true;
+ else if (actionWidth + popup_size.width() + pos.x() > screenRect.right())
+ shouldShiftToRight = false;
+
+ if (shouldShiftToRight) {
+ pos.rx() += actionWidth + (rtl ? popup_size.width() : 0);
+ } else {
+ //shift to left
+ if (!rtl)
+ pos.rx() -= popup_size.width();
+ }
+ } else if (rtl) {
+ pos.rx() += actionWidth;
+ }
+
+ if(!defaultPopDown || (fitUp && !fitDown))
+ pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y()));
+ activeMenu->popup(pos);
+ if(activateFirst)
+ activeMenu->d_func()->setFirstActionActive();
+ }
+ q->update(actionRect(action));
+}
+
+void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst)
+{
+ if(currentAction == action && popup == popupState)
+ return;
+
+ autoReleaseTimer.stop();
+
+ doChildEffects = (popup && !activeMenu);
+ Q_Q(QMenuBar);
+ QWidget *fw = 0;
+ if(QMenu *menu = activeMenu) {
+ activeMenu = 0;
+ if (popup) {
+ fw = q->window()->focusWidget();
+ q->setFocus(Qt::NoFocusReason);
+ }
+ menu->hide();
+ }
+
+ if(currentAction)
+ q->update(actionRect(currentAction));
+
+ popupState = popup;
+#ifndef QT_NO_STATUSTIP
+ QAction *previousAction = currentAction;
+#endif
+ currentAction = action;
+ if (action) {
+ activateAction(action, QAction::Hover);
+ if(popup)
+ popupAction(action, activateFirst);
+ q->update(actionRect(action));
+#ifndef QT_NO_STATUSTIP
+ } else if (previousAction) {
+ QString empty;
+ QStatusTipEvent tip(empty);
+ QApplication::sendEvent(q, &tip);
+#endif
+ }
+ if (fw)
+ fw->setFocus(Qt::NoFocusReason);
+}
+
+void QMenuBarPrivate::calcActionRects(int max_width, int start) const
+{
+ Q_Q(const QMenuBar);
+
+ if(!itemsDirty)
+ return;
+
+ //let's reinitialize the buffer
+ actionRects.resize(actions.count());
+ actionRects.fill(QRect());
+
+ const QStyle *style = q->style();
+
+ const int itemSpacing = style->pixelMetric(QStyle::PM_MenuBarItemSpacing, 0, q);
+ int max_item_height = 0, separator = -1, separator_start = 0, separator_len = 0;
+
+ //calculate size
+ const QFontMetrics fm = q->fontMetrics();
+ const int hmargin = style->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q),
+ vmargin = style->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q),
+ icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q);
+ for(int i = 0; i < actions.count(); i++) {
+ QAction *action = actions.at(i);
+ if(!action->isVisible())
+ continue;
+
+ QSize sz;
+
+ //calc what I think the size is..
+ if(action->isSeparator()) {
+ if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q))
+ separator = i;
+ continue; //we don't really position these!
+ } else {
+ const QString s = action->text();
+ QIcon is = action->icon();
+ // If an icon is set, only the icon is visible
+ if (!is.isNull())
+ sz = sz.expandedTo(QSize(icone, icone));
+ else if (!s.isEmpty())
+ sz = fm.size(Qt::TextShowMnemonic, s);
+ }
+
+ //let the style modify the above size..
+ QStyleOptionMenuItem opt;
+ q->initStyleOption(&opt, action);
+ sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q);
+
+ if(!sz.isEmpty()) {
+ { //update the separator state
+ int iWidth = sz.width() + itemSpacing;
+ if(separator == -1)
+ separator_start += iWidth;
+ else
+ separator_len += iWidth;
+ }
+ //maximum height
+ max_item_height = qMax(max_item_height, sz.height());
+ //append
+ actionRects[i] = QRect(0, 0, sz.width(), sz.height());
+ }
+ }
+
+ //calculate position
+ const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
+ int x = fw + ((start == -1) ? hmargin : start) + itemSpacing;
+ int y = fw + vmargin;
+ for(int i = 0; i < actions.count(); i++) {
+ QRect &rect = actionRects[i];
+ if (rect.isNull())
+ continue;
+
+ //resize
+ rect.setHeight(max_item_height);
+
+ //move
+ if(separator != -1 && i >= separator) { //after the separator
+ int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin);
+ if(left < separator_start) { //wrap
+ separator_start = x = hmargin;
+ y += max_item_height;
+ }
+ rect.moveLeft(left);
+ } else {
+ rect.moveLeft(x);
+ }
+ rect.moveTop(y);
+
+ //keep moving along..
+ x += rect.width() + itemSpacing;
+
+ //make sure we follow the layout direction
+ rect = QStyle::visualRect(q->layoutDirection(), q->rect(), rect);
+ }
+}
+
+void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent action_e)
+{
+ Q_Q(QMenuBar);
+ if (!action || !action->isEnabled())
+ return;
+ action->activate(action_e);
+ if (action_e == QAction::Hover)
+ action->showStatusText(q);
+
+// if(action_e == QAction::Trigger)
+// emit q->activated(action);
+// else if(action_e == QAction::Hover)
+// emit q->highlighted(action);
+}
+
+
+void QMenuBarPrivate::_q_actionTriggered()
+{
+ Q_Q(QMenuBar);
+ if (QAction *action = qobject_cast<QAction *>(q->sender())) {
+ emit q->triggered(action);
+#ifdef QT3_SUPPORT
+ emit q->activated(q->findIdForAction(action));
+#endif
+ }
+}
+
+void QMenuBarPrivate::_q_actionHovered()
+{
+ Q_Q(QMenuBar);
+ if (QAction *action = qobject_cast<QAction *>(q->sender())) {
+ emit q->hovered(action);
+#ifndef QT_NO_ACCESSIBILITY
+ if (QAccessible::isActive()) {
+ int actionIndex = actions.indexOf(action);
+ ++actionIndex;
+ QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus);
+ QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection);
+ }
+#endif //QT_NO_ACCESSIBILITY
+ }
+}
+
+/*!
+ Initialize \a option with the values from the menu bar and information from \a action. This method
+ is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom() QMenu::initStyleOption()
+*/
+void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
+{
+ if (!option || !action)
+ return;
+ Q_D(const QMenuBar);
+ option->palette = palette();
+ option->state = QStyle::State_None;
+ if (isEnabled() && action->isEnabled())
+ option->state |= QStyle::State_Enabled;
+ else
+ option->palette.setCurrentColorGroup(QPalette::Disabled);
+ option->fontMetrics = fontMetrics();
+ if (d->currentAction && d->currentAction == action) {
+ option->state |= QStyle::State_Selected;
+ if (d->popupState && !d->closePopupMode)
+ option->state |= QStyle::State_Sunken;
+ }
+ if (hasFocus() || d->currentAction)
+ option->state |= QStyle::State_HasFocus;
+ option->menuRect = rect();
+ option->menuItemType = QStyleOptionMenuItem::Normal;
+ option->checkType = QStyleOptionMenuItem::NotCheckable;
+ option->text = action->text();
+ option->icon = action->icon();
+}
+
+/*!
+ \class QMenuBar
+ \brief The QMenuBar class provides a horizontal menu bar.
+
+ \ingroup mainwindow-classes
+
+ A menu bar consists of a list of pull-down menu items. You add
+ menu items with addMenu(). For example, asuming that \c menubar
+ is a pointer to a QMenuBar and \c fileMenu is a pointer to a
+ QMenu, the following statement inserts the menu into the menu bar:
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenubar.cpp 0
+
+ The ampersand in the menu item's text sets Alt+F as a shortcut for
+ this menu. (You can use "\&\&" to get a real ampersand in the menu
+ bar.)
+
+ There is no need to lay out a menu bar. It automatically sets its
+ own geometry to the top of the parent widget and changes it
+ appropriately whenever the parent is resized.
+
+ \section1 Usage
+
+ In most main window style applications you would use the
+ \l{QMainWindow::}{menuBar()} function provided in QMainWindow,
+ adding \l{QMenu}s to the menu bar and adding \l{QAction}s to the
+ pop-up menus.
+
+ Example (from the \l{mainwindows/menus}{Menus} example):
+
+ \snippet examples/mainwindows/menus/mainwindow.cpp 9
+
+ Menu items may be removed with removeAction().
+
+ Widgets can be added to menus by using instances of the QWidgetAction
+ class to hold them. These actions can then be inserted into menus
+ in the usual way; see the QMenu documentation for more details.
+
+ \section1 Platform Dependent Look and Feel
+
+ Different platforms have different requirements for the appearance
+ of menu bars and their behavior when the user interacts with them.
+ For example, Windows systems are often configured so that the
+ underlined character mnemonics that indicate keyboard shortcuts
+ for items in the menu bar are only shown when the \gui{Alt} key is
+ pressed.
+
+ \table
+
+ \row \o \inlineimage plastique-menubar.png A menu bar shown in the
+ Plastique widget style.
+
+ \o The \l{QPlastiqueStyle}{Plastique widget style}, like most
+ other styles, handles the \gui{Help} menu in the same way as it
+ handles any other menu.
+
+ \row \o \inlineimage motif-menubar.png A menu bar shown in the
+ Motif widget style.
+
+ \o The \l{QMotifStyle}{Motif widget style} treats \gui{Help} menus
+ in a special way, placing them at right-hand end of the menu bar.
+
+ \endtable
+
+ \section1 QMenuBar on Mac OS X
+
+ QMenuBar on Mac OS X is a wrapper for using the system-wide menu bar.
+ If you have multiple menu bars in one dialog the outermost menu bar
+ (normally inside a widget with widget flag Qt::Window) will
+ be used for the system-wide menu bar.
+
+ Qt for Mac OS X also provides a menu bar merging feature to make
+ QMenuBar conform more closely to accepted Mac OS X menu bar layout.
+ The merging functionality is based on string matching the title of
+ a QMenu entry. These strings are translated (using QObject::tr())
+ in the "QMenuBar" context. If an entry is moved its slots will still
+ fire as if it was in the original place. The table below outlines
+ the strings looked for and where the entry is placed if matched:
+
+ \table
+ \header \i String matches \i Placement \i Notes
+ \row \i about.*
+ \i Application Menu | About <application name>
+ \i The application name is fetched from the \c {Info.plist} file
+ (see note below). If this entry is not found no About item
+ will appear in the Application Menu.
+ \row \i config, options, setup, settings or preferences
+ \i Application Menu | Preferences
+ \i If this entry is not found the Settings item will be disabled
+ \row \i quit or exit
+ \i Application Menu | Quit <application name>
+ \i If this entry is not found a default Quit item will be
+ created to call QApplication::quit()
+ \endtable
+
+ You can override this behavior by using the QAction::menuRole()
+ property.
+
+ If you want all windows in a Mac application to share one menu
+ bar, you must create a menu bar that does not have a parent.
+ Create a parent-less menu bar this way:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qmenubar.cpp 1
+
+ \bold{Note:} Do \e{not} call QMainWindow::menuBar() to create the
+ shared menu bar, because that menu bar will have the QMainWindow
+ as its parent. That menu bar would only be displayed for the
+ parent QMainWindow.
+
+ \bold{Note:} The text used for the application name in the menu
+ bar is obtained from the value set in the \c{Info.plist} file in
+ the application's bundle. See \l{Deploying an Application on
+ Mac OS X} for more information.
+
+ \section1 QMenuBar on Windows CE
+
+ QMenuBar on Windows CE is a wrapper for using the system-wide menu bar,
+ similar to the Mac. This feature is activated for Windows Mobile
+ and integrates QMenuBar with the native soft keys. The left soft
+ key can be controlled with QMenuBar::setDefaultAction() and the
+ right soft key can be used to access the menu bar.
+
+ The hovered() signal is not supported for the native menu
+ integration. Also, it is not possible to display an icon in a
+ native menu on Windows Mobile.
+
+ \section1 Examples
+
+ The \l{mainwindows/menus}{Menus} example shows how to use QMenuBar
+ and QMenu. The other \l{Main Window Examples}{main window
+ application examples} also provide menus using these classes.
+
+ \sa QMenu, QShortcut, QAction,
+ {http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGIntro/XHIGIntro.html}{Introduction to Apple Human Interface Guidelines},
+ {fowler}{GUI Design Handbook: Menu Bar}, {Menus Example}
+*/
+
+
+void QMenuBarPrivate::init()
+{
+ Q_Q(QMenuBar);
+ q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
+ q->setAttribute(Qt::WA_CustomWhatsThis);
+
+ platformMenuBar = QGuiApplicationPrivate::platformIntegration()->createPlatformMenuBar(q);
+
+ if (platformMenuBar)
+ q->hide();
+#ifdef Q_WS_WINCE
+ if (qt_wince_is_mobile()) {
+ wceCreateMenuBar(q->parentWidget());
+ if(wce_menubar)
+ q->hide();
+ }
+ else {
+ QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
+ }
+#endif
+ q->setBackgroundRole(QPalette::Button);
+ oldWindow = oldParent = 0;
+#ifdef QT_SOFTKEYS_ENABLED
+ menuBarAction = 0;
+#endif
+ handleReparent();
+ q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, q));
+
+ extension = new QMenuBarExtension(q);
+ extension->setFocusPolicy(Qt::NoFocus);
+ extension->hide();
+}
+
+//Gets the next action for keyboard navigation
+QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) const
+{
+ Q_Q(const QMenuBar);
+ const_cast<QMenuBarPrivate*>(this)->updateGeometries();
+ bool allowActiveAndDisabled = q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q);
+ const int start = (_start == -1 && increment == -1) ? actions.count() : _start;
+ const int end = increment == -1 ? 0 : actions.count() - 1;
+
+ for (int i = start; i != end;) {
+ i += increment;
+ QAction *current = actions.at(i);
+ if (!actionRects.at(i).isNull() && (allowActiveAndDisabled || current->isEnabled()))
+ return current;
+ }
+
+ if (_start != -1) //let's try from the beginning or the end
+ return getNextAction(-1, increment);
+
+ return 0;
+}
+
+/*!
+ Constructs a menu bar with parent \a parent.
+*/
+QMenuBar::QMenuBar(QWidget *parent) : QWidget(*new QMenuBarPrivate, parent, 0)
+{
+ Q_D(QMenuBar);
+ d->init();
+}
+
+
+/*!
+ Destroys the menu bar.
+*/
+QMenuBar::~QMenuBar()
+{
+ Q_D(QMenuBar);
+ delete d->platformMenuBar;
+ d->platformMenuBar = 0;
+
+#ifdef Q_WS_WINCE
+ Q_D(QMenuBar);
+ if (qt_wince_is_mobile())
+ d->wceDestroyMenuBar();
+#endif
+#ifdef Q_WS_S60
+ Q_D(QMenuBar);
+ d->symbianDestroyMenuBar();
+#endif
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with \a text.
+ The function adds the newly created action to the menu's
+ list of actions, and returns it.
+
+ \sa QWidget::addAction(), QWidget::actions()
+*/
+QAction *QMenuBar::addAction(const QString &text)
+{
+ QAction *ret = new QAction(text, this);
+ addAction(ret);
+ return ret;
+}
+
+/*!
+ \overload
+
+ This convenience function creates a new action with the given \a
+ text. The action's triggered() signal is connected to the \a
+ receiver's \a member slot. The function adds the newly created
+ action to the menu's list of actions and returns it.
+
+ \sa QWidget::addAction(), QWidget::actions()
+*/
+QAction *QMenuBar::addAction(const QString &text, const QObject *receiver, const char* member)
+{
+ QAction *ret = new QAction(text, this);
+ QObject::connect(ret, SIGNAL(triggered(bool)), receiver, member);
+ addAction(ret);
+ return ret;
+}
+
+/*!
+ Appends a new QMenu with \a title to the menu bar. The menu bar
+ takes ownership of the menu. Returns the new menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QMenu *QMenuBar::addMenu(const QString &title)
+{
+ QMenu *menu = new QMenu(title, this);
+ addAction(menu->menuAction());
+ return menu;
+}
+
+/*!
+ Appends a new QMenu with \a icon and \a title to the menu bar. The menu bar
+ takes ownership of the menu. Returns the new menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title)
+{
+ QMenu *menu = new QMenu(title, this);
+ menu->setIcon(icon);
+ addAction(menu->menuAction());
+ return menu;
+}
+
+/*!
+ Appends \a menu to the menu bar. Returns the menu's menuAction().
+
+ \note The returned QAction object can be used to hide the corresponding
+ menu.
+
+ \sa QWidget::addAction() QMenu::menuAction()
+*/
+QAction *QMenuBar::addMenu(QMenu *menu)
+{
+ QAction *action = menu->menuAction();
+ addAction(action);
+ return action;
+}
+
+/*!
+ Appends a separator to the menu.
+*/
+QAction *QMenuBar::addSeparator()
+{
+ QAction *ret = new QAction(this);
+ ret->setSeparator(true);
+ addAction(ret);
+ return ret;
+}
+
+/*!
+ This convenience function creates a new separator action, i.e. an
+ action with QAction::isSeparator() returning true. The function inserts
+ the newly created action into this menu bar's list of actions before
+ action \a before and returns it.
+
+ \sa QWidget::insertAction(), addSeparator()
+*/
+QAction *QMenuBar::insertSeparator(QAction *before)
+{
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ This convenience function inserts \a menu before action \a before
+ and returns the menus menuAction().
+
+ \sa QWidget::insertAction() addMenu()
+*/
+QAction *QMenuBar::insertMenu(QAction *before, QMenu *menu)
+{
+ QAction *action = menu->menuAction();
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ Returns the QAction that is currently highlighted. A null pointer
+ will be returned if no action is currently selected.
+*/
+QAction *QMenuBar::activeAction() const
+{
+ Q_D(const QMenuBar);
+ return d->currentAction;
+}
+
+/*!
+ \since 4.1
+
+ Sets the currently highlighted action to \a act.
+*/
+void QMenuBar::setActiveAction(QAction *act)
+{
+ Q_D(QMenuBar);
+ d->setCurrentAction(act, true, false);
+}
+
+
+/*!
+ Removes all the actions from the menu bar.
+
+ \note On Mac OS X, menu items that have been merged to the system
+ menu bar are not removed by this function. One way to handle this
+ would be to remove the extra actions yourself. You can set the
+ \l{QAction::MenuRole}{menu role} on the different menus, so that
+ you know ahead of time which menu items get merged and which do
+ not. Then decide what to recreate or remove yourself.
+
+ \sa removeAction()
+*/
+void QMenuBar::clear()
+{
+ QList<QAction*> acts = actions();
+ for(int i = 0; i < acts.size(); i++)
+ removeAction(acts[i]);
+}
+
+/*!
+ \property QMenuBar::defaultUp
+ \brief the popup orientation
+
+ The default popup orientation. By default, menus pop "down" the
+ screen. By setting the property to true, the menu will pop "up".
+ You might call this for menus that are \e below the document to
+ which they refer.
+
+ If the menu would not fit on the screen, the other direction is
+ used automatically.
+*/
+void QMenuBar::setDefaultUp(bool b)
+{
+ Q_D(QMenuBar);
+ d->defaultPopDown = !b;
+}
+
+bool QMenuBar::isDefaultUp() const
+{
+ Q_D(const QMenuBar);
+ return !d->defaultPopDown;
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::resizeEvent(QResizeEvent *)
+{
+ Q_D(QMenuBar);
+ d->itemsDirty = true;
+ d->updateGeometries();
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::paintEvent(QPaintEvent *e)
+{
+ Q_D(QMenuBar);
+ QPainter p(this);
+ QRegion emptyArea(rect());
+
+ //draw the items
+ for (int i = 0; i < d->actions.count(); ++i) {
+ QAction *action = d->actions.at(i);
+ QRect adjustedActionRect = d->actionRect(action);
+ if (adjustedActionRect.isEmpty() || !d->isVisible(action))
+ continue;
+ if(!e->rect().intersects(adjustedActionRect))
+ continue;
+
+ emptyArea -= adjustedActionRect;
+ QStyleOptionMenuItem opt;
+ initStyleOption(&opt, action);
+ opt.rect = adjustedActionRect;
+ p.setClipRect(adjustedActionRect);
+ style()->drawControl(QStyle::CE_MenuBarItem, &opt, &p, this);
+ }
+ //draw border
+ if(int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this)) {
+ QRegion borderReg;
+ borderReg += QRect(0, 0, fw, height()); //left
+ borderReg += QRect(width()-fw, 0, fw, height()); //right
+ borderReg += QRect(0, 0, width(), fw); //top
+ borderReg += QRect(0, height()-fw, width(), fw); //bottom
+ p.setClipRegion(borderReg);
+ emptyArea -= borderReg;
+ QStyleOptionFrame frame;
+ frame.rect = rect();
+ frame.palette = palette();
+ frame.state = QStyle::State_None;
+ frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth);
+ frame.midLineWidth = 0;
+ style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this);
+ }
+ p.setClipRegion(emptyArea);
+ QStyleOptionMenuItem menuOpt;
+ menuOpt.palette = palette();
+ menuOpt.state = QStyle::State_None;
+ menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
+ menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
+ menuOpt.rect = rect();
+ menuOpt.menuRect = rect();
+ style()->drawControl(QStyle::CE_MenuBarEmptyArea, &menuOpt, &p, this);
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::setVisible(bool visible)
+{
+#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60)
+ if (isNativeMenuBar()) {
+ if (!visible)
+ QWidget::setVisible(false);
+ return;
+ }
+#endif
+ QWidget::setVisible(visible);
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QMenuBar);
+ if(e->button() != Qt::LeftButton)
+ return;
+
+ d->mouseDown = true;
+
+ QAction *action = d->actionAt(e->pos());
+ if (!action || !d->isVisible(action)) {
+ d->setCurrentAction(0);
+#ifndef QT_NO_WHATSTHIS
+ if (QWhatsThis::inWhatsThisMode())
+ QWhatsThis::showText(e->globalPos(), d->whatsThis, this);
+#endif
+ return;
+ }
+
+ if(d->currentAction == action && d->popupState) {
+ if(QMenu *menu = d->activeMenu) {
+ d->activeMenu = 0;
+ menu->hide();
+ }
+#ifdef Q_WS_WIN
+ if((d->closePopupMode = style()->styleHint(QStyle::SH_MenuBar_DismissOnSecondClick)))
+ update(d->actionRect(action));
+#endif
+ } else {
+ d->setCurrentAction(action, true);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QMenuBar);
+ if(e->button() != Qt::LeftButton || !d->mouseDown)
+ return;
+
+ d->mouseDown = false;
+ QAction *action = d->actionAt(e->pos());
+ if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) {
+ //we set the current action before activating
+ //so that we let the leave event set the current back to 0
+ d->setCurrentAction(action, false);
+ if(action)
+ d->activateAction(action, QAction::Trigger);
+ }
+ d->closePopupMode = 0;
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QMenuBar);
+ d->updateGeometries();
+ int key = e->key();
+ if(isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
+ if(key == Qt::Key_Left)
+ key = Qt::Key_Right;
+ else if(key == Qt::Key_Right)
+ key = Qt::Key_Left;
+ }
+ if(key == Qt::Key_Tab) //means right
+ key = Qt::Key_Right;
+ else if(key == Qt::Key_Backtab) //means left
+ key = Qt::Key_Left;
+
+ bool key_consumed = false;
+ switch(key) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Enter:
+ case Qt::Key_Space:
+ case Qt::Key_Return: {
+ if(!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction)
+ break;
+ if(d->currentAction->menu()) {
+ d->popupAction(d->currentAction, true);
+ } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) {
+ d->activateAction(d->currentAction, QAction::Trigger);
+ d->setCurrentAction(d->currentAction, false);
+ d->setKeyboardMode(false);
+ }
+ key_consumed = true;
+ break; }
+
+ case Qt::Key_Right:
+ case Qt::Key_Left: {
+ if(d->currentAction) {
+ int index = d->actions.indexOf(d->currentAction);
+ if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) {
+ d->setCurrentAction(nextAction, d->popupState, true);
+ key_consumed = true;
+ }
+ }
+ break; }
+
+ case Qt::Key_Escape:
+ d->setCurrentAction(0);
+ d->setKeyboardMode(false);
+ key_consumed = true;
+ break;
+
+ default:
+ key_consumed = false;
+ }
+
+ if(!key_consumed &&
+ (!e->modifiers() ||
+ (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) {
+ int clashCount = 0;
+ QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
+ {
+ QChar c = e->text()[0].toUpper();
+ for(int i = 0; i < d->actions.size(); ++i) {
+ if (d->actionRects.at(i).isNull())
+ continue;
+ QAction *act = d->actions.at(i);
+ QString s = act->text();
+ if(!s.isEmpty()) {
+ int ampersand = s.indexOf(QLatin1Char('&'));
+ if(ampersand >= 0) {
+ if(s[ampersand+1].toUpper() == c) {
+ clashCount++;
+ if(!first)
+ first = act;
+ if(act == d->currentAction)
+ currentSelected = act;
+ else if (!firstAfterCurrent && currentSelected)
+ firstAfterCurrent = act;
+ }
+ }
+ }
+ }
+ }
+ QAction *next_action = 0;
+ if(clashCount >= 1) {
+ if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent))
+ next_action = first;
+ else
+ next_action = firstAfterCurrent;
+ }
+ if(next_action) {
+ key_consumed = true;
+ d->setCurrentAction(next_action, true, true);
+ }
+ }
+ if(key_consumed)
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QMenuBar);
+ if (!(e->buttons() & Qt::LeftButton))
+ d->mouseDown = false;
+ bool popupState = d->popupState || d->mouseDown;
+ QAction *action = d->actionAt(e->pos());
+ if ((action && d->isVisible(action)) || !popupState)
+ d->setCurrentAction(action, popupState);
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::leaveEvent(QEvent *)
+{
+ Q_D(QMenuBar);
+ if((!hasFocus() && !d->popupState) ||
+ (d->currentAction && d->currentAction->menu() == 0))
+ d->setCurrentAction(0);
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::actionEvent(QActionEvent *e)
+{
+ Q_D(QMenuBar);
+ d->itemsDirty = true;
+
+ if (d->platformMenuBar) {
+ QPlatformMenuBar *nativeMenuBar = d->platformMenuBar;
+#if defined(Q_WS_S60)
+ QMenuBarPrivate::QSymbianMenuBarPrivate *nativeMenuBar = d->symbian_menubar;
+#elif defined(Q_WS_WINCE)
+ QMenuBarPrivate::QWceMenuBarPrivate *nativeMenuBar = d->wce_menubar;
+#endif
+ if (!nativeMenuBar)
+ return;
+ if(e->type() == QEvent::ActionAdded)
+ nativeMenuBar->addAction(e->action(), e->before());
+ else if(e->type() == QEvent::ActionRemoved)
+ nativeMenuBar->removeAction(e->action());
+ else if(e->type() == QEvent::ActionChanged)
+ nativeMenuBar->syncAction(e->action());
+ }
+
+ if(e->type() == QEvent::ActionAdded) {
+ connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
+ connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
+ } else if(e->type() == QEvent::ActionRemoved) {
+ e->action()->disconnect(this);
+ }
+ if (isVisible()) {
+ d->updateGeometries();
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::focusInEvent(QFocusEvent *)
+{
+ Q_D(QMenuBar);
+ if(d->keyboardState)
+ d->focusFirstAction();
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::focusOutEvent(QFocusEvent *)
+{
+ Q_D(QMenuBar);
+ if(!d->popupState) {
+ d->setCurrentAction(0);
+ d->setKeyboardMode(false);
+ }
+}
+
+/*!
+ \reimp
+ */
+void QMenuBar::timerEvent (QTimerEvent *e)
+{
+ Q_D(QMenuBar);
+ if (e->timerId() == d->autoReleaseTimer.timerId()) {
+ d->autoReleaseTimer.stop();
+ d->setCurrentAction(0);
+ }
+ QWidget::timerEvent(e);
+}
+
+
+void QMenuBarPrivate::handleReparent()
+{
+ Q_Q(QMenuBar);
+ QWidget *newParent = q->parentWidget();
+ //Note: if parent is reparented, then window may change even if parent doesn't
+
+ // we need to install an event filter on parent, and remove the old one
+
+ if (oldParent != newParent) {
+ if (oldParent)
+ oldParent->removeEventFilter(q);
+ if (newParent)
+ newParent->installEventFilter(q);
+ }
+
+ //we also need event filter on top-level (for shortcuts)
+ QWidget *newWindow = newParent ? newParent->window() : 0;
+
+ if (oldWindow != newWindow) {
+ if (oldParent && oldParent != oldWindow)
+ oldWindow->removeEventFilter(q);
+
+ if (newParent && newParent != newWindow)
+ newWindow->installEventFilter(q);
+ }
+
+ oldParent = newParent;
+ oldWindow = newWindow;
+
+ if (platformMenuBar)
+ platformMenuBar->handleReparent(newParent);
+
+#ifdef Q_WS_WINCE
+ if (qt_wince_is_mobile() && wce_menubar)
+ wce_menubar->rebuild();
+#endif
+#ifdef Q_WS_S60
+
+ // Construct symbian_menubar when this code path is entered first time
+ // and when newParent != NULL
+ if (!symbian_menubar)
+ symbianCreateMenuBar(newParent);
+
+ // Reparent and rebuild menubar when parent is changed
+ if (symbian_menubar) {
+ if (oldParent != newParent)
+ reparentMenuBar(oldParent, newParent);
+ q->hide();
+ symbian_menubar->rebuild();
+ }
+
+#ifdef QT_SOFTKEYS_ENABLED
+ // Constuct menuBarAction when this code path is entered first time
+ if (!menuBarAction) {
+ if (newParent) {
+ menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, newParent);
+ newParent->addAction(menuBarAction);
+ }
+ } else {
+ // If reparenting i.e. we already have menuBarAction, remove it from old parent
+ // and add for a new parent
+ if (oldParent)
+ oldParent->removeAction(menuBarAction);
+ if (newParent)
+ newParent->addAction(menuBarAction);
+ }
+#endif // QT_SOFTKEYS_ENABLED
+#endif // Q_WS_S60
+}
+
+/*!
+ \reimp
+*/
+void QMenuBar::changeEvent(QEvent *e)
+{
+ Q_D(QMenuBar);
+ if(e->type() == QEvent::StyleChange) {
+ d->itemsDirty = true;
+ setMouseTracking(style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, this));
+ if(parentWidget())
+ resize(parentWidget()->width(), heightForWidth(parentWidget()->width()));
+ d->updateGeometries();
+ } else if (e->type() == QEvent::ParentChange) {
+ d->handleReparent();
+ } else if (e->type() == QEvent::FontChange
+ || e->type() == QEvent::ApplicationFontChange) {
+ d->itemsDirty = true;
+ d->updateGeometries();
+#ifdef QT_SOFTKEYS_ENABLED
+ } else if (e->type() == QEvent::LanguageChange) {
+ if (d->menuBarAction)
+ d->menuBarAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::MenuSoftKey));
+#endif
+ }
+
+ QWidget::changeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+bool QMenuBar::event(QEvent *e)
+{
+ Q_D(QMenuBar);
+ switch (e->type()) {
+ case QEvent::KeyPress: {
+ QKeyEvent *ke = (QKeyEvent*)e;
+#if 0
+ if(!d->keyboardState) { //all keypresses..
+ d->setCurrentAction(0);
+ return ;
+ }
+#endif
+ if(ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
+ keyPressEvent(ke);
+ return true;
+ }
+
+ } break;
+#ifndef QT_NO_SHORTCUT
+ case QEvent::Shortcut: {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ int shortcutId = se->shortcutId();
+ for(int j = 0; j < d->shortcutIndexMap.size(); ++j) {
+ if (shortcutId == d->shortcutIndexMap.value(j))
+ d->_q_internalShortcutActivated(j);
+ }
+ } break;
+#endif
+ case QEvent::Show:
+ d->_q_updateLayout();
+ break;
+ case QEvent::ShortcutOverride: {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(e);
+ //we only filter out escape if there is a current action
+ if (kev->key() == Qt::Key_Escape && d->currentAction) {
+ e->accept();
+ return true;
+ }
+ }
+ break;
+
+
+#ifndef QT_NO_WHATSTHIS
+ case QEvent::QueryWhatsThis:
+ e->setAccepted(d->whatsThis.size());
+ if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
+ if (action->whatsThis().size() || action->menu())
+ e->accept();
+ }
+ return true;
+#endif
+ case QEvent::LayoutDirectionChange:
+ d->_q_updateLayout();
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(e);
+}
+
+/*!
+ \reimp
+*/
+bool QMenuBar::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QMenuBar);
+ if (object == parent() && object) {
+ if (event->type() == QEvent::ParentChange) //GrandparentChange
+ d->handleReparent();
+ }
+ if (object == d->leftWidget || object == d->rightWidget) {
+ switch (event->type()) {
+ case QEvent::ShowToParent:
+ case QEvent::HideToParent:
+ d->_q_updateLayout();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this)) {
+ if (d->altPressed) {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(event);
+ if (kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta) {
+ if (event->type() == QEvent::KeyPress) // Alt-press does not interest us, we have the shortcut-override event
+ break;
+ d->setKeyboardMode(!d->keyboardState);
+ }
+ }
+ // fall through
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ case QEvent::ActivationChange:
+ d->altPressed = false;
+ qApp->removeEventFilter(this);
+ break;
+ default:
+ break;
+ }
+ } else if (isVisible()) {
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *kev = static_cast<QKeyEvent*>(event);
+ if ((kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta)
+ && kev->modifiers() == Qt::AltModifier) {
+ d->altPressed = true;
+ qApp->installEventFilter(this);
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/*!
+ Returns the QAction at \a pt. Returns 0 if there is no action at \a pt or if
+the location has a separator.
+
+ \sa addAction(), addSeparator()
+*/
+QAction *QMenuBar::actionAt(const QPoint &pt) const
+{
+ Q_D(const QMenuBar);
+ return d->actionAt(pt);
+}
+
+/*!
+ Returns the geometry of action \a act as a QRect.
+
+ \sa actionAt()
+*/
+QRect QMenuBar::actionGeometry(QAction *act) const
+{
+ Q_D(const QMenuBar);
+ return d->actionRect(act);
+}
+
+/*!
+ \reimp
+*/
+QSize QMenuBar::minimumSizeHint() const
+{
+ Q_D(const QMenuBar);
+#if defined(Q_OS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60)
+ const bool as_gui_menubar = !isNativeMenuBar();
+#else
+ const bool as_gui_menubar = true;
+#endif
+
+ ensurePolished();
+ QSize ret(0, 0);
+ const_cast<QMenuBarPrivate*>(d)->updateGeometries();
+ const int hmargin = style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, this);
+ const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this);
+ int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this);
+ int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this);
+ if(as_gui_menubar) {
+ int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width();
+ d->calcActionRects(w - (2 * fw), 0);
+ for (int i = 0; ret.isNull() && i < d->actions.count(); ++i)
+ ret = d->actionRects.at(i).size();
+ if (!d->extension->isHidden())
+ ret += QSize(d->extension->sizeHint().width(), 0);
+ ret += QSize(2*fw + hmargin, 2*fw + vmargin);
+ }
+ int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
+ if(d->leftWidget) {
+ QSize sz = d->leftWidget->minimumSizeHint();
+ ret.setWidth(ret.width() + sz.width());
+ if(sz.height() + margin > ret.height())
+ ret.setHeight(sz.height() + margin);
+ }
+ if(d->rightWidget) {
+ QSize sz = d->rightWidget->minimumSizeHint();
+ ret.setWidth(ret.width() + sz.width());
+ if(sz.height() + margin > ret.height())
+ ret.setHeight(sz.height() + margin);
+ }
+ if(as_gui_menubar) {
+ QStyleOptionMenuItem opt;
+ opt.rect = rect();
+ opt.menuRect = rect();
+ opt.state = QStyle::State_None;
+ opt.menuItemType = QStyleOptionMenuItem::Normal;
+ opt.checkType = QStyleOptionMenuItem::NotCheckable;
+ opt.palette = palette();
+ return (style()->sizeFromContents(QStyle::CT_MenuBar, &opt,
+ ret.expandedTo(QApplication::globalStrut()),
+ this));
+ }
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+QSize QMenuBar::sizeHint() const
+{
+ Q_D(const QMenuBar);
+#if defined(Q_OS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60)
+ const bool as_gui_menubar = !isNativeMenuBar();
+#else
+ const bool as_gui_menubar = true;
+#endif
+
+
+ ensurePolished();
+ QSize ret(0, 0);
+ const_cast<QMenuBarPrivate*>(d)->updateGeometries();
+ const int hmargin = style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, this);
+ const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this);
+ int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this);
+ int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this);
+ if(as_gui_menubar) {
+ const int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width();
+ d->calcActionRects(w - (2 * fw), 0);
+ for (int i = 0; i < d->actionRects.count(); ++i) {
+ const QRect &actionRect = d->actionRects.at(i);
+ ret = ret.expandedTo(QSize(actionRect.x() + actionRect.width(), actionRect.y() + actionRect.height()));
+ }
+ //the action geometries already contain the top and left
+ //margins. So we only need to add those from right and bottom.
+ ret += QSize(fw + hmargin, fw + vmargin);
+ }
+ int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
+ if(d->leftWidget) {
+ QSize sz = d->leftWidget->sizeHint();
+ ret.setWidth(ret.width() + sz.width());
+ if(sz.height() + margin > ret.height())
+ ret.setHeight(sz.height() + margin);
+ }
+ if(d->rightWidget) {
+ QSize sz = d->rightWidget->sizeHint();
+ ret.setWidth(ret.width() + sz.width());
+ if(sz.height() + margin > ret.height())
+ ret.setHeight(sz.height() + margin);
+ }
+ if(as_gui_menubar) {
+ QStyleOptionMenuItem opt;
+ opt.rect = rect();
+ opt.menuRect = rect();
+ opt.state = QStyle::State_None;
+ opt.menuItemType = QStyleOptionMenuItem::Normal;
+ opt.checkType = QStyleOptionMenuItem::NotCheckable;
+ opt.palette = palette();
+ return (style()->sizeFromContents(QStyle::CT_MenuBar, &opt,
+ ret.expandedTo(QApplication::globalStrut()),
+ this));
+ }
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+int QMenuBar::heightForWidth(int) const
+{
+ Q_D(const QMenuBar);
+#if defined(Q_OS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60)
+ const bool as_gui_menubar = !isNativeMenuBar();
+#else
+ const bool as_gui_menubar = true;
+#endif
+
+ const_cast<QMenuBarPrivate*>(d)->updateGeometries();
+ int height = 0;
+ const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this);
+ int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this);
+ int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this);
+ if(as_gui_menubar) {
+ for (int i = 0; i < d->actionRects.count(); ++i)
+ height = qMax(height, d->actionRects.at(i).height());
+ if (height) //there is at least one non-null item
+ height += spaceBelowMenuBar;
+ height += 2*fw;
+ height += 2*vmargin;
+ }
+ int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
+ if(d->leftWidget)
+ height = qMax(d->leftWidget->sizeHint().height() + margin, height);
+ if(d->rightWidget)
+ height = qMax(d->rightWidget->sizeHint().height() + margin, height);
+ if(as_gui_menubar) {
+ QStyleOptionMenuItem opt;
+ opt.init(this);
+ opt.menuRect = rect();
+ opt.state = QStyle::State_None;
+ opt.menuItemType = QStyleOptionMenuItem::Normal;
+ opt.checkType = QStyleOptionMenuItem::NotCheckable;
+ return style()->sizeFromContents(QStyle::CT_MenuBar, &opt, QSize(0, height), this).height(); //not pretty..
+ }
+ return height;
+}
+
+/*!
+ \internal
+*/
+void QMenuBarPrivate::_q_internalShortcutActivated(int id)
+{
+ Q_Q(QMenuBar);
+ QAction *act = actions.at(id);
+ setCurrentAction(act, true, true);
+ if (act && !act->menu()) {
+ activateAction(act, QAction::Trigger);
+ //100 is the same as the default value in QPushButton::animateClick
+ autoReleaseTimer.start(100, q);
+ } else if (act && q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, q)) {
+ // When we open a menu using a shortcut, we should end up in keyboard state
+ setKeyboardMode(true);
+ }
+}
+
+void QMenuBarPrivate::_q_updateLayout()
+{
+ Q_Q(QMenuBar);
+ itemsDirty = true;
+ if (q->isVisible()) {
+ updateGeometries();
+ q->update();
+ }
+}
+
+/*!
+ \fn void QMenuBar::setCornerWidget(QWidget *widget, Qt::Corner corner)
+
+ This sets the given \a widget to be shown directly on the left of the first
+ menu item, or on the right of the last menu item, depending on \a corner.
+
+ The menu bar takes ownership of \a widget, reparenting it into the menu bar.
+ However, if the \a corner already contains a widget, this previous widget
+ will no longer be managed and will still be a visible child of the menu bar.
+
+ \note Using a corner other than Qt::TopRightCorner or Qt::TopLeftCorner
+ will result in a warning.
+*/
+void QMenuBar::setCornerWidget(QWidget *w, Qt::Corner corner)
+{
+ Q_D(QMenuBar);
+ switch (corner) {
+ case Qt::TopLeftCorner:
+ if (d->leftWidget)
+ d->leftWidget->removeEventFilter(this);
+ d->leftWidget = w;
+ break;
+ case Qt::TopRightCorner:
+ if (d->rightWidget)
+ d->rightWidget->removeEventFilter(this);
+ d->rightWidget = w;
+ break;
+ default:
+ qWarning("QMenuBar::setCornerWidget: Only TopLeftCorner and TopRightCorner are supported");
+ return;
+ }
+
+ if (w) {
+ w->setParent(this);
+ w->installEventFilter(this);
+ }
+
+ d->_q_updateLayout();
+}
+
+/*!
+ Returns the widget on the left of the first or on the right of the last menu
+ item, depending on \a corner.
+
+ \note Using a corner other than Qt::TopRightCorner or Qt::TopLeftCorner
+ will result in a warning.
+*/
+QWidget *QMenuBar::cornerWidget(Qt::Corner corner) const
+{
+ Q_D(const QMenuBar);
+ QWidget *w = 0;
+ switch(corner) {
+ case Qt::TopLeftCorner:
+ w = d->leftWidget;
+ break;
+ case Qt::TopRightCorner:
+ w = d->rightWidget;
+ break;
+ default:
+ qWarning("QMenuBar::cornerWidget: Only TopLeftCorner and TopRightCorner are supported");
+ break;
+ }
+
+ return w;
+}
+
+/*!
+ \property QMenuBar::nativeMenuBar
+ \brief Whether or not a menubar will be used as a native menubar on platforms that support it
+ \since 4.6
+
+ This property specifies whether or not the menubar should be used as a native menubar on platforms
+ that support it. The currently supported platforms are Mac OS X and Windows CE. On these platforms
+ if this property is true, the menubar is used in the native menubar and is not in the window of
+ its parent, if false the menubar remains in the window. On other platforms the value of this
+ attribute has no effect.
+
+ The default is to follow whether the Qt::AA_DontUseNativeMenuBar attribute
+ is set for the application. Explicitly settings this property overrides
+ the presence (or abscence) of the attribute.
+*/
+
+void QMenuBar::setNativeMenuBar(bool nativeMenuBar)
+{
+ Q_D(QMenuBar);
+ if (d->nativeMenuBar == -1 || (nativeMenuBar != bool(d->nativeMenuBar))) {
+ d->nativeMenuBar = nativeMenuBar;
+
+ if (!d->nativeMenuBar) {
+ delete d->platformMenuBar;
+ d->platformMenuBar = 0;
+ } else {
+ if (!d->platformMenuBar)
+ d->platformMenuBar = QGuiApplicationPrivate::platformIntegration()->createPlatformMenuBar(this);
+ }
+
+ updateGeometry();
+ if (!d->nativeMenuBar && parentWidget())
+ setVisible(true);
+ }
+}
+
+bool QMenuBar::isNativeMenuBar() const
+{
+ Q_D(const QMenuBar);
+ if (d->nativeMenuBar == -1) {
+ return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar);
+ }
+ return d->nativeMenuBar;
+}
+
+QPlatformMenuBar *QMenuBar::platformMenuBar()
+{
+ Q_D(const QMenuBar);
+ return d->platformMenuBar;
+}
+
+/*!
+ \since 4.4
+
+ Sets the default action to \a act.
+
+ The default action is assigned to the left soft key. The menu is assigned
+ to the right soft key.
+
+ Currently there is only support for the default action on Windows
+ Mobile. On all other platforms this method is not available.
+
+ \sa defaultAction()
+*/
+
+#ifdef Q_WS_WINCE
+void QMenuBar::setDefaultAction(QAction *act)
+{
+ Q_D(QMenuBar);
+ if (d->defaultAction == act)
+ return;
+#ifdef Q_WS_WINCE
+ if (qt_wince_is_mobile())
+ if (d->defaultAction) {
+ disconnect(d->defaultAction, SIGNAL(changed()), this, SLOT(_q_updateDefaultAction()));
+ disconnect(d->defaultAction, SIGNAL(destroyed()), this, SLOT(_q_updateDefaultAction()));
+ }
+#endif
+ d->defaultAction = act;
+#ifdef Q_WS_WINCE
+ if (qt_wince_is_mobile())
+ if (d->defaultAction) {
+ connect(d->defaultAction, SIGNAL(changed()), this, SLOT(_q_updateDefaultAction()));
+ connect(d->defaultAction, SIGNAL(destroyed()), this, SLOT(_q_updateDefaultAction()));
+ }
+ if (d->wce_menubar) {
+ d->wce_menubar->rebuild();
+ }
+#endif
+}
+
+/*!
+ \since 4.4
+
+ Returns the current default action.
+
+ \sa setDefaultAction()
+*/
+QAction *QMenuBar::defaultAction() const
+{
+ return d_func()->defaultAction;
+}
+#endif
+
+/*!
+ \fn void QMenuBar::triggered(QAction *action)
+
+ This signal is emitted when an action in a menu belonging to this menubar
+ is triggered as a result of a mouse click; \a action is the action that
+ caused the signal to be emitted.
+
+ Normally, you connect each menu action to a single slot using
+ QAction::triggered(), but sometimes you will want to connect
+ several items to a single slot (most often if the user selects
+ from an array). This signal is useful in such cases.
+
+ \sa hovered(), QAction::triggered()
+*/
+
+/*!
+ \fn void QMenuBar::hovered(QAction *action)
+
+ This signal is emitted when a menu action is highlighted; \a action
+ is the action that caused the event to be sent.
+
+ Often this is used to update status information.
+
+ \sa triggered(), QAction::hovered()
+*/
+
+/*!
+ \enum QMenuBar::Separator
+
+ \compat
+
+ \value Never
+ \value InWindowsStyle
+
+*/
+
+/*!
+ \fn void QMenuBar::addAction(QAction *action)
+ \overload
+
+ Appends the action \a action to the menu bar's list of actions.
+
+ \sa QMenu::addAction(), QWidget::addAction(), QWidget::actions()
+*/
+
+/*!
+ \fn void QMenuBar::setFrameRect(QRect)
+ \internal
+*/
+
+/*!
+ \fn QRect QMenuBar::frameRect() const
+ \internal
+*/
+/*!
+ \enum QMenuBar::DummyFrame
+ \internal
+
+ \value Box
+ \value Sunken
+ \value Plain
+ \value Raised
+ \value MShadow
+ \value NoFrame
+ \value Panel
+ \value StyledPanel
+ \value HLine
+ \value VLine
+ \value GroupBoxPanel
+ \value WinPanel
+ \value ToolBarPanel
+ \value MenuBarPanel
+ \value PopupPanel
+ \value LineEditPanel
+ \value TabWidgetPanel
+ \value MShape
+*/
+
+/*!
+ \fn void QMenuBar::setFrameShadow(DummyFrame)
+ \internal
+*/
+
+/*!
+ \fn DummyFrame QMenuBar::frameShadow() const
+ \internal
+*/
+
+/*!
+ \fn void QMenuBar::setFrameShape(DummyFrame)
+ \internal
+*/
+
+/*!
+ \fn DummyFrame QMenuBar::frameShape() const
+ \internal
+*/
+
+/*!
+ \fn void QMenuBar::setFrameStyle(int)
+ \internal
+*/
+
+/*!
+ \fn int QMenuBar::frameStyle() const
+ \internal
+*/
+
+/*!
+ \fn void QMenuBar::setLineWidth(int)
+ \internal
+*/
+
+/*!
+ \fn int QMenuBar::lineWidth() const
+ \internal
+*/
+
+/*!
+ \fn void QMenuBar::setMidLineWidth(int)
+ \internal
+*/
+
+/*!
+ \fn int QMenuBar::midLineWidth() const
+ \internal
+*/
+
+// for private slots
+
+
+QT_END_NAMESPACE
+
+#include <moc_qmenubar.cpp>
+
+#endif // QT_NO_MENUBAR
diff --git a/src/widgets/widgets/qmenubar.h b/src/widgets/widgets/qmenubar.h
new file mode 100644
index 0000000000..b165ec78f3
--- /dev/null
+++ b/src/widgets/widgets/qmenubar.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMENUBAR_H
+#define QMENUBAR_H
+
+#include <QtWidgets/qmenu.h>
+#ifdef Q_OS_MAC
+#include "QtWidgets/qmacdefines_mac.h"
+#endif
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MENUBAR
+
+class QMenuBarPrivate;
+class QStyleOptionMenuItem;
+class QWindowsStyle;
+#ifdef QT3_SUPPORT
+class QMenuItem;
+#endif
+
+class Q_WIDGETS_EXPORT QMenuBar : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool defaultUp READ isDefaultUp WRITE setDefaultUp)
+ Q_PROPERTY(bool nativeMenuBar READ isNativeMenuBar WRITE setNativeMenuBar)
+
+public:
+ explicit QMenuBar(QWidget *parent = 0);
+ ~QMenuBar();
+
+#ifdef Q_NO_USING_KEYWORD
+ void addAction(QAction *action) { QWidget::addAction(action); }
+#else
+ using QWidget::addAction;
+#endif
+ QAction *addAction(const QString &text);
+ QAction *addAction(const QString &text, const QObject *receiver, const char* member);
+
+ QAction *addMenu(QMenu *menu);
+ QMenu *addMenu(const QString &title);
+ QMenu *addMenu(const QIcon &icon, const QString &title);
+
+
+ QAction *addSeparator();
+ QAction *insertSeparator(QAction *before);
+
+ QAction *insertMenu(QAction *before, QMenu *menu);
+
+ void clear();
+
+ QAction *activeAction() const;
+ void setActiveAction(QAction *action);
+
+ void setDefaultUp(bool);
+ bool isDefaultUp() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ int heightForWidth(int) const;
+
+ QRect actionGeometry(QAction *) const;
+ QAction *actionAt(const QPoint &) const;
+
+ void setCornerWidget(QWidget *w, Qt::Corner corner = Qt::TopRightCorner);
+ QWidget *cornerWidget(Qt::Corner corner = Qt::TopRightCorner) const;
+
+#ifdef Q_WS_WINCE
+ void setDefaultAction(QAction *);
+ QAction *defaultAction() const;
+
+ static void wceCommands(uint command);
+ static void wceRefresh();
+#endif
+
+ bool isNativeMenuBar() const;
+ void setNativeMenuBar(bool nativeMenuBar);
+ QPlatformMenuBar *platformMenuBar();
+public Q_SLOTS:
+ virtual void setVisible(bool visible);
+
+Q_SIGNALS:
+ void triggered(QAction *action);
+ void hovered(QAction *action);
+
+protected:
+ void changeEvent(QEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void leaveEvent(QEvent *);
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+ void actionEvent(QActionEvent *);
+ void focusOutEvent(QFocusEvent *);
+ void focusInEvent(QFocusEvent *);
+ void timerEvent(QTimerEvent *);
+ bool eventFilter(QObject *, QEvent *);
+ bool event(QEvent *);
+ void initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const;
+
+private:
+ Q_DECLARE_PRIVATE(QMenuBar)
+ Q_DISABLE_COPY(QMenuBar)
+ Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered())
+ Q_PRIVATE_SLOT(d_func(), void _q_actionHovered())
+ Q_PRIVATE_SLOT(d_func(), void _q_internalShortcutActivated(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateLayout())
+
+#ifdef Q_WS_WINCE
+ Q_PRIVATE_SLOT(d_func(), void _q_updateDefaultAction())
+#endif
+
+ friend class QMenu;
+ friend class QMenuPrivate;
+ friend class QWindowsStyle;
+
+#ifdef Q_OS_MAC
+ friend class QApplicationPrivate;
+ friend class QWidgetPrivate;
+ friend bool qt_mac_activate_action(MenuRef, uint, QAction::ActionEvent, bool);
+#endif
+};
+
+#endif // QT_NO_MENUBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMENUBAR_H
diff --git a/src/widgets/widgets/qmenubar_p.h b/src/widgets/widgets/qmenubar_p.h
new file mode 100644
index 0000000000..5f482c228e
--- /dev/null
+++ b/src/widgets/widgets/qmenubar_p.h
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMENUBAR_P_H
+#define QMENUBAR_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.
+//
+
+#ifndef QMAC_Q3MENUBAR_CPP_FILE
+#include "QtWidgets/qstyleoption.h"
+#include <private/qmenu_p.h> // Mac needs what in this file!
+
+#ifdef Q_WS_WINCE
+#include "qguifunctions_wince.h"
+#endif
+
+#ifndef QT_NO_MENUBAR
+#ifdef Q_WS_S60
+class CCoeControl;
+class CEikMenuBar;
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_MENUBAR
+class QMenuBarExtension;
+class QMenuBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QMenuBar)
+public:
+ QMenuBarPrivate() : itemsDirty(0), currentAction(0), mouseDown(0),
+ closePopupMode(0), defaultPopDown(1), popupState(0), keyboardState(0), altPressed(0),
+ nativeMenuBar(-1), doChildEffects(false), platformMenuBar(0)
+#ifdef QT3_SUPPORT
+ , doAutoResize(false)
+#endif
+
+#ifdef Q_WS_WINCE
+ , wce_menubar(0), wceClassicMenu(false)
+#endif
+#ifdef Q_WS_S60
+ , symbian_menubar(0)
+#endif
+
+ { }
+ ~QMenuBarPrivate()
+ {
+ delete platformMenuBar;
+#ifdef Q_WS_WINCE
+ delete wce_menubar;
+#endif
+#ifdef Q_WS_S60
+ delete symbian_menubar;
+#endif
+ }
+
+ void init();
+ QAction *getNextAction(const int start, const int increment) const;
+
+ //item calculations
+ uint itemsDirty : 1;
+
+ QVector<int> shortcutIndexMap;
+ mutable QVector<QRect> actionRects;
+ void calcActionRects(int max_width, int start) const;
+ QRect actionRect(QAction *) const;
+ void updateGeometries();
+
+ //selection
+ QPointer<QAction>currentAction;
+ uint mouseDown : 1, closePopupMode : 1, defaultPopDown;
+ QAction *actionAt(QPoint p) const;
+ void setCurrentAction(QAction *, bool =false, bool =false);
+ void popupAction(QAction *, bool);
+
+ //active popup state
+ uint popupState : 1;
+ QPointer<QMenu> activeMenu;
+
+ //keyboard mode for keyboard navigation
+ void focusFirstAction();
+ void setKeyboardMode(bool);
+ uint keyboardState : 1, altPressed : 1;
+ QPointer<QWidget> keyboardFocusWidget;
+
+
+ int nativeMenuBar : 3; // Only has values -1, 0, and 1
+ //firing of events
+ void activateAction(QAction *, QAction::ActionEvent);
+
+ void _q_actionTriggered();
+ void _q_actionHovered();
+ void _q_internalShortcutActivated(int);
+ void _q_updateLayout();
+
+#ifdef Q_WS_WINCE
+ void _q_updateDefaultAction();
+#endif
+
+ //extra widgets in the menubar
+ QPointer<QWidget> leftWidget, rightWidget;
+ QMenuBarExtension *extension;
+ bool isVisible(QAction *action);
+
+ //menu fading/scrolling effects
+ bool doChildEffects;
+
+ QRect menuRect(bool) const;
+
+ // reparenting
+ void handleReparent();
+ QWidget *oldParent;
+ QWidget *oldWindow;
+
+ QList<QAction*> hiddenActions;
+ //default action
+ QPointer<QAction> defaultAction;
+
+ QBasicTimer autoReleaseTimer;
+#ifdef QT3_SUPPORT
+ bool doAutoResize;
+#endif
+ QPlatformMenuBar *platformMenuBar;
+
+#ifdef Q_WS_WINCE
+ void wceCreateMenuBar(QWidget *);
+ void wceDestroyMenuBar();
+ struct QWceMenuBarPrivate {
+ QList<QWceMenuAction*> actionItems;
+ QList<QWceMenuAction*> actionItemsLeftButton;
+ QList<QList<QWceMenuAction*>> actionItemsClassic;
+ HMENU menuHandle;
+ HMENU leftButtonMenuHandle;
+ HWND menubarHandle;
+ HWND parentWindowHandle;
+ bool leftButtonIsMenu;
+ QPointer<QAction> leftButtonAction;
+ QMenuBarPrivate *d;
+ int leftButtonCommand;
+
+ QWceMenuBarPrivate(QMenuBarPrivate *menubar);
+ ~QWceMenuBarPrivate();
+ void addAction(QAction *, QWceMenuAction* =0);
+ void addAction(QWceMenuAction *, QWceMenuAction* =0);
+ void syncAction(QWceMenuAction *);
+ inline void syncAction(QAction *a) { syncAction(findAction(a)); }
+ void removeAction(QWceMenuAction *);
+ void rebuild();
+ inline void removeAction(QAction *a) { removeAction(findAction(a)); }
+ inline QWceMenuAction *findAction(QAction *a) {
+ for(int i = 0; i < actionItems.size(); i++) {
+ QWceMenuAction *act = actionItems[i];
+ if(a == act->action)
+ return act;
+ }
+ return 0;
+ }
+ } *wce_menubar;
+ bool wceClassicMenu;
+ void wceCommands(uint command);
+ void wceRefresh();
+ bool wceEmitSignals(QList<QWceMenuAction*> actions, uint command);
+#endif
+#ifdef Q_WS_S60
+ void symbianCreateMenuBar(QWidget *);
+ void symbianDestroyMenuBar();
+ void reparentMenuBar(QWidget *oldParent, QWidget *newParent);
+ struct QSymbianMenuBarPrivate {
+ QList<QSymbianMenuAction*> actionItems;
+ QMenuBarPrivate *d;
+ QSymbianMenuBarPrivate(QMenuBarPrivate *menubar);
+ ~QSymbianMenuBarPrivate();
+ void addAction(QAction *, QSymbianMenuAction* =0);
+ void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0);
+ void syncAction(QSymbianMenuAction *);
+ inline void syncAction(QAction *a) { syncAction(findAction(a)); }
+ void removeAction(QSymbianMenuAction *);
+ void rebuild();
+ inline void removeAction(QAction *a) { removeAction(findAction(a)); }
+ inline QSymbianMenuAction *findAction(QAction *a) {
+ for(int i = 0; i < actionItems.size(); i++) {
+ QSymbianMenuAction *act = actionItems[i];
+ if(a == act->action)
+ return act;
+ }
+ return 0;
+ }
+ void insertNativeMenuItems(const QList<QAction*> &actions);
+
+ } *symbian_menubar;
+ static int symbianCommands(int command);
+#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ QAction *menuBarAction;
+#endif
+};
+#endif
+
+#endif // QT_NO_MENUBAR
+
+QT_END_NAMESPACE
+
+#endif // QMENUBAR_P_H
diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp
new file mode 100644
index 0000000000..e408a6e7aa
--- /dev/null
+++ b/src/widgets/widgets/qplaintextedit.cpp
@@ -0,0 +1,2996 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplaintextedit_p.h"
+
+
+#include <qfont.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qdebug.h>
+#include <qmime.h>
+#include <qdrag.h>
+#include <qclipboard.h>
+#include <qmenu.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include "private/qtextdocumentlayout_p.h"
+#include "private/qabstracttextdocumentlayout_p.h"
+#include "qtextdocument.h"
+#include "private/qtextdocument_p.h"
+#include "qtextlist.h"
+
+#include <qtextformat.h>
+#include <qdatetime.h>
+#include <qapplication.h>
+#include <limits.h>
+#include <qtexttable.h>
+#include <qvariant.h>
+#include <qinputcontext.h>
+
+#ifndef QT_NO_TEXTEDIT
+
+QT_BEGIN_NAMESPACE
+
+static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit)
+{
+ return !plaintextedit->isReadOnly();
+}
+
+class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate
+{
+ Q_DECLARE_PUBLIC(QPlainTextDocumentLayout)
+public:
+ QPlainTextDocumentLayoutPrivate() {
+ mainViewPrivate = 0;
+ width = 0;
+ maximumWidth = 0;
+ maximumWidthBlockNumber = 0;
+ blockCount = 1;
+ blockUpdate = blockDocumentSizeChanged = false;
+ cursorWidth = 1;
+ textLayoutFlags = 0;
+ }
+
+ qreal width;
+ qreal maximumWidth;
+ int maximumWidthBlockNumber;
+ int blockCount;
+ QPlainTextEditPrivate *mainViewPrivate;
+ bool blockUpdate;
+ bool blockDocumentSizeChanged;
+ int cursorWidth;
+ int textLayoutFlags;
+
+ void layoutBlock(const QTextBlock &block);
+ qreal blockWidth(const QTextBlock &block);
+
+ void relayout();
+};
+
+
+
+/*! \class QPlainTextDocumentLayout
+ \since 4.4
+ \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument
+
+ \ingroup richtext-processing
+
+ A QPlainTextDocumentLayout is required for text documents that can
+ be display or edited in a QPlainTextEdit. See
+ QTextDocument::setDocumentLayout().
+
+ QPlainTextDocumentLayout uses the QAbstractTextDocumentLayout API
+ that QTextDocument requires, but redefines it partially in order to
+ support plain text better. For instances, it does not operate on
+ vertical pixels, but on paragraphs (called blocks) instead. The
+ height of a document is identical to the number of paragraphs it
+ contains. The layout also doesn't support tables or nested frames,
+ or any sort of advanced text layout that goes beyond a list of
+ paragraphs with syntax highlighting.
+
+*/
+
+
+
+/*!
+ Constructs a plain text document layout for the text \a document.
+ */
+QPlainTextDocumentLayout::QPlainTextDocumentLayout(QTextDocument *document)
+ :QAbstractTextDocumentLayout(* new QPlainTextDocumentLayoutPrivate, document) {
+}
+/*!
+ Destructs a plain text document layout.
+ */
+QPlainTextDocumentLayout::~QPlainTextDocumentLayout() {}
+
+
+/*!
+ \reimp
+ */
+void QPlainTextDocumentLayout::draw(QPainter *, const PaintContext &)
+{
+}
+
+/*!
+ \reimp
+ */
+int QPlainTextDocumentLayout::hitTest(const QPointF &, Qt::HitTestAccuracy ) const
+{
+// this function is used from
+// QAbstractTextDocumentLayout::anchorAt(), but is not
+// implementable in a plain text document layout, because the
+// layout depends on the top block and top line which depends on
+// the view
+ return -1;
+}
+
+/*!
+ \reimp
+ */
+int QPlainTextDocumentLayout::pageCount() const
+{ return 1; }
+
+/*!
+ \reimp
+ */
+QSizeF QPlainTextDocumentLayout::documentSize() const
+{
+ Q_D(const QPlainTextDocumentLayout);
+ return QSizeF(d->maximumWidth, document()->lineCount());
+}
+
+/*!
+ \reimp
+ */
+QRectF QPlainTextDocumentLayout::frameBoundingRect(QTextFrame *) const
+{
+ Q_D(const QPlainTextDocumentLayout);
+ return QRectF(0, 0, qMax(d->width, d->maximumWidth), qreal(INT_MAX));
+}
+
+/*!
+ \reimp
+ */
+QRectF QPlainTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
+{
+ if (!block.isValid()) { return QRectF(); }
+ QTextLayout *tl = block.layout();
+ if (!tl->lineCount())
+ const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);
+ QRectF br;
+ if (block.isVisible()) {
+ br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight());
+ if (tl->lineCount() == 1)
+ br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));
+ qreal margin = document()->documentMargin();
+ br.adjust(0, 0, margin, 0);
+ if (!block.next().isValid())
+ br.adjust(0, 0, 0, margin);
+ }
+ return br;
+
+}
+
+/*!
+ Ensures that \a block has a valid layout
+ */
+void QPlainTextDocumentLayout::ensureBlockLayout(const QTextBlock &block) const
+{
+ if (!block.isValid())
+ return;
+ QTextLayout *tl = block.layout();
+ if (!tl->lineCount())
+ const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);
+}
+
+
+/*! \property QPlainTextDocumentLayout::cursorWidth
+
+ This property specifies the width of the cursor in pixels. The default value is 1.
+*/
+void QPlainTextDocumentLayout::setCursorWidth(int width)
+{
+ Q_D(QPlainTextDocumentLayout);
+ d->cursorWidth = width;
+}
+
+int QPlainTextDocumentLayout::cursorWidth() const
+{
+ Q_D(const QPlainTextDocumentLayout);
+ return d->cursorWidth;
+}
+
+QPlainTextDocumentLayoutPrivate *QPlainTextDocumentLayout::priv() const
+{
+ Q_D(const QPlainTextDocumentLayout);
+ return const_cast<QPlainTextDocumentLayoutPrivate*>(d);
+}
+
+
+/*!
+
+ Requests a complete update on all views.
+ */
+void QPlainTextDocumentLayout::requestUpdate()
+{
+ emit update(QRectF(0., -document()->documentMargin(), 1000000000., 1000000000.));
+}
+
+
+void QPlainTextDocumentLayout::setTextWidth(qreal newWidth)
+{
+ Q_D(QPlainTextDocumentLayout);
+ d->width = d->maximumWidth = newWidth;
+ d->relayout();
+}
+
+qreal QPlainTextDocumentLayout::textWidth() const
+{
+ Q_D(const QPlainTextDocumentLayout);
+ return d->width;
+}
+
+void QPlainTextDocumentLayoutPrivate::relayout()
+{
+ Q_Q(QPlainTextDocumentLayout);
+ QTextBlock block = q->document()->firstBlock();
+ while (block.isValid()) {
+ block.layout()->clearLayout();
+ block.setLineCount(block.isVisible() ? 1 : 0);
+ block = block.next();
+ }
+ emit q->update();
+}
+
+
+/*! \reimp
+ */
+void QPlainTextDocumentLayout::documentChanged(int from, int /*charsRemoved*/, int charsAdded)
+{
+ Q_D(QPlainTextDocumentLayout);
+ QTextDocument *doc = document();
+ int newBlockCount = doc->blockCount();
+
+ QTextBlock changeStartBlock = doc->findBlock(from);
+ QTextBlock changeEndBlock = doc->findBlock(qMax(0, from + charsAdded - 1));
+
+ if (changeStartBlock == changeEndBlock && newBlockCount == d->blockCount) {
+ QTextBlock block = changeStartBlock;
+ int blockLineCount = block.layout()->lineCount();
+ if (block.isValid() && blockLineCount) {
+ QRectF oldBr = blockBoundingRect(block);
+ layoutBlock(block);
+ QRectF newBr = blockBoundingRect(block);
+ if (newBr.height() == oldBr.height()) {
+ if (!d->blockUpdate)
+ emit updateBlock(block);
+ return;
+ }
+ }
+ } else {
+ QTextBlock block = changeStartBlock;
+ do {
+ block.clearLayout();
+ if (block == changeEndBlock)
+ break;
+ block = block.next();
+ } while(block.isValid());
+ }
+
+ if (newBlockCount != d->blockCount) {
+
+ int changeEnd = changeEndBlock.blockNumber();
+ int blockDiff = newBlockCount - d->blockCount;
+ int oldChangeEnd = changeEnd - blockDiff;
+
+ if (d->maximumWidthBlockNumber > oldChangeEnd)
+ d->maximumWidthBlockNumber += blockDiff;
+
+ d->blockCount = newBlockCount;
+ if (d->blockCount == 1)
+ d->maximumWidth = blockWidth(doc->firstBlock());
+
+ if (!d->blockDocumentSizeChanged)
+ emit documentSizeChanged(documentSize());
+
+ if (blockDiff == 1 && changeEnd == newBlockCount -1 ) {
+ if (!d->blockUpdate) {
+ QTextBlock b = changeStartBlock;
+ for(;;) {
+ emit updateBlock(b);
+ if (b == changeEndBlock)
+ break;
+ b = b.next();
+ }
+ }
+ return;
+ }
+ }
+
+ if (!d->blockUpdate)
+ emit update(QRectF(0., -doc->documentMargin(), 1000000000., 1000000000.)); // optimization potential
+}
+
+
+void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block)
+{
+ Q_D(QPlainTextDocumentLayout);
+ QTextDocument *doc = document();
+ qreal margin = doc->documentMargin();
+ qreal blockMaximumWidth = 0;
+
+ qreal height = 0;
+ QTextLayout *tl = block.layout();
+ QTextOption option = doc->defaultTextOption();
+ tl->setTextOption(option);
+
+ int extraMargin = 0;
+ if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
+ QFontMetrics fm(block.charFormat().font());
+ extraMargin += fm.width(QChar(0x21B5));
+ }
+ tl->beginLayout();
+ qreal availableWidth = d->width;
+ if (availableWidth <= 0) {
+ availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0
+ }
+ availableWidth -= 2*margin + extraMargin;
+ while (1) {
+ QTextLine line = tl->createLine();
+ if (!line.isValid())
+ break;
+ line.setLeadingIncluded(true);
+ line.setLineWidth(availableWidth);
+ line.setPosition(QPointF(margin, height));
+ height += line.height();
+ blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin);
+ }
+ tl->endLayout();
+
+ int previousLineCount = doc->lineCount();
+ const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0);
+ int lineCount = doc->lineCount();
+
+ bool emitDocumentSizeChanged = previousLineCount != lineCount;
+ if (blockMaximumWidth > d->maximumWidth) {
+ // new longest line
+ d->maximumWidth = blockMaximumWidth;
+ d->maximumWidthBlockNumber = block.blockNumber();
+ emitDocumentSizeChanged = true;
+ } else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) {
+ // longest line shrinking
+ QTextBlock b = doc->firstBlock();
+ d->maximumWidth = 0;
+ QTextBlock maximumBlock;
+ while (b.isValid()) {
+ qreal blockMaximumWidth = blockWidth(b);
+ if (blockMaximumWidth > d->maximumWidth) {
+ d->maximumWidth = blockMaximumWidth;
+ maximumBlock = b;
+ }
+ b = b.next();
+ }
+ if (maximumBlock.isValid()) {
+ d->maximumWidthBlockNumber = maximumBlock.blockNumber();
+ emitDocumentSizeChanged = true;
+ }
+ }
+ if (emitDocumentSizeChanged && !d->blockDocumentSizeChanged)
+ emit documentSizeChanged(documentSize());
+}
+
+qreal QPlainTextDocumentLayout::blockWidth(const QTextBlock &block)
+{
+ QTextLayout *layout = block.layout();
+ if (!layout->lineCount())
+ return 0; // only for layouted blocks
+ qreal blockWidth = 0;
+ for (int i = 0; i < layout->lineCount(); ++i) {
+ QTextLine line = layout->lineAt(i);
+ blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth);
+ }
+ return blockWidth;
+}
+
+
+QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent)
+ : QWidgetTextControl(parent), textEdit(parent),
+ topBlock(0)
+{
+ setAcceptRichText(false);
+}
+
+void QPlainTextEditPrivate::_q_cursorPositionChanged()
+{
+ pageUpDownLastCursorYIsValid = false;
+}
+
+void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) {
+ if (action == QAbstractSlider::SliderPageStepAdd) {
+ pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor, false);
+ } else if (action == QAbstractSlider::SliderPageStepSub) {
+ pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor, false);
+ }
+}
+
+QMimeData *QPlainTextEditControl::createMimeDataFromSelection() const {
+ QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
+ if (!ed)
+ return QWidgetTextControl::createMimeDataFromSelection();
+ return ed->createMimeDataFromSelection();
+ }
+bool QPlainTextEditControl::canInsertFromMimeData(const QMimeData *source) const {
+ QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
+ if (!ed)
+ return QWidgetTextControl::canInsertFromMimeData(source);
+ return ed->canInsertFromMimeData(source);
+}
+void QPlainTextEditControl::insertFromMimeData(const QMimeData *source) {
+ QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
+ if (!ed)
+ QWidgetTextControl::insertFromMimeData(source);
+ else
+ ed->insertFromMimeData(source);
+}
+
+int QPlainTextEditPrivate::verticalOffset(int topBlock, int topLine) const
+{
+ qreal offset = 0;
+ QTextDocument *doc = control->document();
+
+ if (topLine) {
+ QTextBlock currentBlock = doc->findBlockByNumber(topBlock);
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ QRectF r = documentLayout->blockBoundingRect(currentBlock);
+ Q_UNUSED(r);
+ QTextLayout *layout = currentBlock.layout();
+ if (layout && topLine <= layout->lineCount()) {
+ QTextLine line = layout->lineAt(topLine - 1);
+ const QRectF lr = line.naturalTextRect();
+ offset = lr.bottom();
+ }
+ }
+ if (topBlock == 0 && topLine == 0)
+ offset -= doc->documentMargin(); // top margin
+ return (int)offset;
+}
+
+
+int QPlainTextEditPrivate::verticalOffset() const {
+ return verticalOffset(control->topBlock, topLine);
+}
+
+
+QTextBlock QPlainTextEditControl::firstVisibleBlock() const
+{
+ return document()->findBlockByNumber(topBlock);
+}
+
+
+
+int QPlainTextEditControl::hitTest(const QPointF &point, Qt::HitTestAccuracy ) const {
+ int currentBlockNumber = topBlock;
+ QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
+ if (!currentBlock.isValid())
+ return -1;
+
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPointF offset;
+ QRectF r = documentLayout->blockBoundingRect(currentBlock);
+ while (currentBlock.next().isValid() && r.bottom() + offset.y() <= point.y()) {
+ offset.ry() += r.height();
+ currentBlock = currentBlock.next();
+ ++currentBlockNumber;
+ r = documentLayout->blockBoundingRect(currentBlock);
+ }
+ while (currentBlock.previous().isValid() && r.top() + offset.y() > point.y()) {
+ offset.ry() -= r.height();
+ currentBlock = currentBlock.previous();
+ --currentBlockNumber;
+ r = documentLayout->blockBoundingRect(currentBlock);
+ }
+
+
+ if (!currentBlock.isValid())
+ return -1;
+ QTextLayout *layout = currentBlock.layout();
+ int off = 0;
+ QPointF pos = point - offset;
+ for (int i = 0; i < layout->lineCount(); ++i) {
+ QTextLine line = layout->lineAt(i);
+ const QRectF lr = line.naturalTextRect();
+ if (lr.top() > pos.y()) {
+ off = qMin(off, line.textStart());
+ } else if (lr.bottom() <= pos.y()) {
+ off = qMax(off, line.textStart() + line.textLength());
+ } else {
+ off = line.xToCursor(pos.x(), overwriteMode() ?
+ QTextLine::CursorOnCharacter : QTextLine::CursorBetweenCharacters);
+ break;
+ }
+ }
+
+ return currentBlock.position() + off;
+}
+
+QRectF QPlainTextEditControl::blockBoundingRect(const QTextBlock &block) const {
+ int currentBlockNumber = topBlock;
+ int blockNumber = block.blockNumber();
+ QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
+ if (!currentBlock.isValid())
+ return QRectF();
+ Q_ASSERT(currentBlock.blockNumber() == currentBlockNumber);
+ QTextDocument *doc = document();
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPointF offset;
+ if (!block.isValid())
+ return QRectF();
+ QRectF r = documentLayout->blockBoundingRect(currentBlock);
+ int maxVerticalOffset = r.height();
+ while (currentBlockNumber < blockNumber && offset.y() - maxVerticalOffset <= 2* textEdit->viewport()->height()) {
+ offset.ry() += r.height();
+ currentBlock = currentBlock.next();
+ ++currentBlockNumber;
+ if (!currentBlock.isVisible()) {
+ currentBlock = doc->findBlockByLineNumber(currentBlock.firstLineNumber());
+ currentBlockNumber = currentBlock.blockNumber();
+ }
+ r = documentLayout->blockBoundingRect(currentBlock);
+ }
+ while (currentBlockNumber > blockNumber && offset.y() + maxVerticalOffset >= -textEdit->viewport()->height()) {
+ currentBlock = currentBlock.previous();
+ --currentBlockNumber;
+ while (!currentBlock.isVisible()) {
+ currentBlock = currentBlock.previous();
+ --currentBlockNumber;
+ }
+ if (!currentBlock.isValid())
+ break;
+
+ r = documentLayout->blockBoundingRect(currentBlock);
+ offset.ry() -= r.height();
+ }
+
+ if (currentBlockNumber != blockNumber) {
+ // fallback for blocks out of reach. Give it some geometry at
+ // least, and ensure the layout is up to date.
+ r = documentLayout->blockBoundingRect(block);
+ if (currentBlockNumber > blockNumber)
+ offset.ry() -= r.height();
+ }
+ r.translate(offset);
+ return r;
+}
+
+
+void QPlainTextEditPrivate::setTopLine(int visualTopLine, int dx)
+{
+ QTextDocument *doc = control->document();
+ QTextBlock block = doc->findBlockByLineNumber(visualTopLine);
+ int blockNumber = block.blockNumber();
+ int lineNumber = visualTopLine - block.firstLineNumber();
+ setTopBlock(blockNumber, lineNumber, dx);
+}
+
+void QPlainTextEditPrivate::setTopBlock(int blockNumber, int lineNumber, int dx)
+{
+ Q_Q(QPlainTextEdit);
+ blockNumber = qMax(0, blockNumber);
+ lineNumber = qMax(0, lineNumber);
+ QTextDocument *doc = control->document();
+ QTextBlock block = doc->findBlockByNumber(blockNumber);
+
+ int newTopLine = block.firstLineNumber() + lineNumber;
+ int maxTopLine = vbar->maximum();
+
+ if (newTopLine > maxTopLine) {
+ block = doc->findBlockByLineNumber(maxTopLine);
+ blockNumber = block.blockNumber();
+ lineNumber = maxTopLine - block.firstLineNumber();
+ }
+
+ bool vbarSignalsBlocked = vbar->blockSignals(true);
+ vbar->setValue(newTopLine);
+ vbar->blockSignals(vbarSignalsBlocked);
+
+ if (!dx && blockNumber == control->topBlock && lineNumber == topLine)
+ return;
+
+ if (viewport->updatesEnabled() && viewport->isVisible()) {
+ int dy = 0;
+ if (doc->findBlockByNumber(control->topBlock).isValid()) {
+ dy = (int)(-q->blockBoundingGeometry(block).y())
+ + verticalOffset() - verticalOffset(blockNumber, lineNumber);
+ }
+ control->topBlock = blockNumber;
+ topLine = lineNumber;
+
+ bool vbarSignalsBlocked = vbar->blockSignals(true);
+ vbar->setValue(block.firstLineNumber() + lineNumber);
+ vbar->blockSignals(vbarSignalsBlocked);
+
+ if (dx || dy)
+ viewport->scroll(q->isRightToLeft() ? -dx : dx, dy);
+ else
+ viewport->update();
+ emit q->updateRequest(viewport->rect(), dy);
+ } else {
+ control->topBlock = blockNumber;
+ topLine = lineNumber;
+ }
+
+}
+
+
+
+void QPlainTextEditPrivate::ensureVisible(int position, bool center, bool forceCenter) {
+ Q_Q(QPlainTextEdit);
+ QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
+ QTextBlock block = control->document()->findBlock(position);
+ if (!block.isValid())
+ return;
+ QRectF br = control->blockBoundingRect(block);
+ if (!br.isValid())
+ return;
+ QRectF lr = br;
+ QTextLine line = block.layout()->lineForTextPosition(position - block.position());
+ Q_ASSERT(line.isValid());
+ lr = line.naturalTextRect().translated(br.topLeft());
+
+ if (lr.bottom() >= visible.bottom() || (center && lr.top() < visible.top()) || forceCenter){
+
+ qreal height = visible.height();
+ if (center)
+ height /= 2;
+
+ qreal h = center ? line.naturalTextRect().center().y() : line.naturalTextRect().bottom();
+
+ QTextBlock previousVisibleBlock = block;
+ while (h < height && block.previous().isValid()) {
+ previousVisibleBlock = block;
+ do {
+ block = block.previous();
+ } while (!block.isVisible() && block.previous().isValid());
+ h += q->blockBoundingRect(block).height();
+ }
+
+ int l = 0;
+ int lineCount = block.layout()->lineCount();
+ int voffset = verticalOffset(block.blockNumber(), 0);
+ while (l < lineCount) {
+ QRectF lineRect = block.layout()->lineAt(l).naturalTextRect();
+ if (h - voffset - lineRect.top() <= height)
+ break;
+ ++l;
+ }
+
+ if (l >= lineCount) {
+ block = previousVisibleBlock;
+ l = 0;
+ }
+ setTopBlock(block.blockNumber(), l);
+ } else if (lr.top() < visible.top()) {
+ setTopBlock(block.blockNumber(), line.lineNumber());
+ }
+
+}
+
+
+void QPlainTextEditPrivate::updateViewport()
+{
+ Q_Q(QPlainTextEdit);
+ viewport->update();
+ emit q->updateRequest(viewport->rect(), 0);
+}
+
+QPlainTextEditPrivate::QPlainTextEditPrivate()
+ : control(0),
+ tabChangesFocus(false),
+ lineWrap(QPlainTextEdit::WidgetWidth),
+ wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere),
+ clickCausedFocus(0),topLine(0),
+ pageUpDownLastCursorYIsValid(false)
+{
+ showCursorOnInitialShow = true;
+ backgroundVisible = false;
+ centerOnScroll = false;
+ inDrag = false;
+}
+
+
+void QPlainTextEditPrivate::init(const QString &txt)
+{
+ Q_Q(QPlainTextEdit);
+ control = new QPlainTextEditControl(q);
+
+ QTextDocument *doc = new QTextDocument(control);
+ QAbstractTextDocumentLayout *layout = new QPlainTextDocumentLayout(doc);
+ doc->setDocumentLayout(layout);
+ control->setDocument(doc);
+
+ control->setPalette(q->palette());
+
+ QObject::connect(vbar, SIGNAL(actionTriggered(int)), q, SLOT(_q_verticalScrollbarActionTriggered(int)));
+
+ QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));
+ QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));
+ QObject::connect(control, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));
+ QObject::connect(control, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));
+ QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
+ QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
+ QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
+
+ // set a null page size initially to avoid any relayouting until the textedit
+ // is shown. relayoutDocument() will take care of setting the page size to the
+ // viewport dimensions later.
+ doc->setTextWidth(-1);
+ doc->documentLayout()->setPaintDevice(viewport);
+ doc->setDefaultFont(q->font());
+
+
+ if (!txt.isEmpty())
+ control->setPlainText(txt);
+
+ hbar->setSingleStep(20);
+ vbar->setSingleStep(1);
+
+ viewport->setBackgroundRole(QPalette::Base);
+ q->setAcceptDrops(true);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setAttribute(Qt::WA_KeyCompression);
+ q->setAttribute(Qt::WA_InputMethodEnabled);
+
+#ifndef QT_NO_CURSOR
+ viewport->setCursor(Qt::IBeamCursor);
+#endif
+ originalOffsetY = 0;
+#ifdef Q_WS_WIN
+ setSingleFingerPanEnabled(true);
+#endif
+}
+
+void QPlainTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
+{
+ Q_Q(QPlainTextEdit);
+ if (!contentsRect.isValid()) {
+ updateViewport();
+ return;
+ }
+ const int xOffset = horizontalOffset();
+ const int yOffset = verticalOffset();
+ const QRect visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
+
+ QRect r = contentsRect.adjusted(-1, -1, 1, 1).intersected(visibleRect).toAlignedRect();
+ if (r.isEmpty())
+ return;
+
+ r.translate(-xOffset, -yOffset);
+ viewport->update(r);
+ emit q->updateRequest(r, 0);
+}
+
+void QPlainTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode, bool moveCursor)
+{
+
+ Q_Q(QPlainTextEdit);
+
+ QTextCursor cursor = control->textCursor();
+ if (moveCursor) {
+ ensureCursorVisible();
+ if (!pageUpDownLastCursorYIsValid)
+ pageUpDownLastCursorY = control->cursorRect(cursor).top() - verticalOffset();
+ }
+
+ qreal lastY = pageUpDownLastCursorY;
+
+
+ if (op == QTextCursor::Down) {
+ QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
+ QTextBlock firstVisibleBlock = q->firstVisibleBlock();
+ QTextBlock block = firstVisibleBlock;
+ QRectF br = q->blockBoundingRect(block);
+ qreal h = 0;
+ int atEnd = false;
+ while (h + br.height() <= visible.bottom()) {
+ if (!block.next().isValid()) {
+ atEnd = true;
+ lastY = visible.bottom(); // set cursor to last line
+ break;
+ }
+ h += br.height();
+ block = block.next();
+ br = q->blockBoundingRect(block);
+ }
+
+ if (!atEnd) {
+ int line = 0;
+ qreal diff = visible.bottom() - h;
+ int lineCount = block.layout()->lineCount();
+ while (line < lineCount - 1) {
+ if (block.layout()->lineAt(line).naturalTextRect().bottom() > diff) {
+ // the first line that did not completely fit the screen
+ break;
+ }
+ ++line;
+ }
+ setTopBlock(block.blockNumber(), line);
+ }
+
+ if (moveCursor) {
+ // move using movePosition to keep the cursor's x
+ lastY += verticalOffset();
+ bool moved = false;
+ do {
+ moved = cursor.movePosition(op, moveMode);
+ } while (moved && control->cursorRect(cursor).top() < lastY);
+ }
+
+ } else if (op == QTextCursor::Up) {
+
+ QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
+ visible.translate(0, -visible.height()); // previous page
+ QTextBlock block = q->firstVisibleBlock();
+ qreal h = 0;
+ while (h >= visible.top()) {
+ if (!block.previous().isValid()) {
+ if (control->topBlock == 0 && topLine == 0) {
+ lastY = 0; // set cursor to first line
+ }
+ break;
+ }
+ block = block.previous();
+ QRectF br = q->blockBoundingRect(block);
+ h -= br.height();
+ }
+
+ int line = 0;
+ if (block.isValid()) {
+ qreal diff = visible.top() - h;
+ int lineCount = block.layout()->lineCount();
+ while (line < lineCount) {
+ if (block.layout()->lineAt(line).naturalTextRect().top() >= diff)
+ break;
+ ++line;
+ }
+ if (line == lineCount) {
+ if (block.next().isValid() && block.next() != q->firstVisibleBlock()) {
+ block = block.next();
+ line = 0;
+ } else {
+ --line;
+ }
+ }
+ }
+ setTopBlock(block.blockNumber(), line);
+
+ if (moveCursor) {
+ cursor.setVisualNavigation(true);
+ // move using movePosition to keep the cursor's x
+ lastY += verticalOffset();
+ bool moved = false;
+ do {
+ moved = cursor.movePosition(op, moveMode);
+ } while (moved && control->cursorRect(cursor).top() > lastY);
+ }
+ }
+
+ if (moveCursor) {
+ control->setTextCursor(cursor);
+ pageUpDownLastCursorYIsValid = true;
+ }
+}
+
+#ifndef QT_NO_SCROLLBAR
+
+void QPlainTextEditPrivate::_q_adjustScrollbars()
+{
+ Q_Q(QPlainTextEdit);
+ QTextDocument *doc = control->document();
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
+ documentLayout->priv()->blockDocumentSizeChanged = true;
+ qreal margin = doc->documentMargin();
+
+ int vmax = 0;
+
+ int vSliderLength = 0;
+ if (!centerOnScroll && q->isVisible()) {
+ QTextBlock block = doc->lastBlock();
+ const qreal visible = viewport->rect().height() - margin - 1;
+ qreal y = 0;
+ int visibleFromBottom = 0;
+
+ while (block.isValid()) {
+ if (!block.isVisible()) {
+ block = block.previous();
+ continue;
+ }
+ y += documentLayout->blockBoundingRect(block).height();
+
+ QTextLayout *layout = block.layout();
+ int layoutLineCount = layout->lineCount();
+ if (y > visible) {
+ int lineNumber = 0;
+ while (lineNumber < layoutLineCount) {
+ QTextLine line = layout->lineAt(lineNumber);
+ const QRectF lr = line.naturalTextRect();
+ if (lr.top() >= y - visible)
+ break;
+ ++lineNumber;
+ }
+ if (lineNumber < layoutLineCount)
+ visibleFromBottom += (layoutLineCount - lineNumber);
+ break;
+
+ }
+ visibleFromBottom += layoutLineCount;
+ block = block.previous();
+ }
+ vmax = qMax(0, doc->lineCount() - visibleFromBottom);
+ vSliderLength = visibleFromBottom;
+
+ } else {
+ vmax = qMax(0, doc->lineCount() - 1);
+ vSliderLength = viewport->height() / q->fontMetrics().lineSpacing();
+ }
+
+
+
+ QSizeF documentSize = documentLayout->documentSize();
+ vbar->setRange(0, qMax(0, vmax));
+ vbar->setPageStep(vSliderLength);
+ int visualTopLine = vmax;
+ QTextBlock firstVisibleBlock = q->firstVisibleBlock();
+ if (firstVisibleBlock.isValid())
+ visualTopLine = firstVisibleBlock.firstLineNumber() + topLine;
+ bool vbarSignalsBlocked = vbar->blockSignals(true);
+ vbar->setValue(visualTopLine);
+ vbar->blockSignals(vbarSignalsBlocked);
+
+ hbar->setRange(0, (int)documentSize.width() - viewport->width());
+ hbar->setPageStep(viewport->width());
+ documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
+ setTopLine(vbar->value());
+}
+
+#endif
+
+
+void QPlainTextEditPrivate::ensureViewportLayouted()
+{
+}
+
+/*!
+ \class QPlainTextEdit
+ \since 4.4
+ \brief The QPlainTextEdit class provides a widget that is used to edit and display
+ plain text.
+
+ \ingroup richtext-processing
+
+
+ \tableofcontents
+
+ \section1 Introduction and Concepts
+
+ QPlainTextEdit is an advanced viewer/editor supporting plain
+ text. It is optimized to handle large documents and to respond
+ quickly to user input.
+
+ QPlainText uses very much the same technology and concepts as
+ QTextEdit, but is optimized for plain text handling.
+
+ QPlainTextEdit works on paragraphs and characters. A paragraph is
+ a formatted string which is word-wrapped to fit into the width of
+ the widget. By default when reading plain text, one newline
+ signifies a paragraph. A document consists of zero or more
+ paragraphs. Paragraphs are separated by hard line breaks. Each
+ character within a paragraph has its own attributes, for example,
+ font and color.
+
+ The shape of the mouse cursor on a QPlainTextEdit is
+ Qt::IBeamCursor by default. It can be changed through the
+ viewport()'s cursor property.
+
+ \section1 Using QPlainTextEdit as a Display Widget
+
+ The text is set or replaced using setPlainText() which deletes the
+ existing text and replaces it with the text passed to setPlainText().
+
+ Text can be inserted using the QTextCursor class or using the
+ convenience functions insertPlainText(), appendPlainText() or
+ paste().
+
+ By default, the text edit wraps words at whitespace to fit within
+ the text edit widget. The setLineWrapMode() function is used to
+ specify the kind of line wrap you want, \l WidgetWidth or \l
+ NoWrap if you don't want any wrapping. If you use word wrap to
+ the widget's width \l WidgetWidth, you can specify whether to
+ break on whitespace or anywhere with setWordWrapMode().
+
+ The find() function can be used to find and select a given string
+ within the text.
+
+ If you want to limit the total number of paragraphs in a
+ QPlainTextEdit, as it is for example useful in a log viewer, then
+ you can use the maximumBlockCount property. The combination of
+ setMaximumBlockCount() and appendPlainText() turns QPlainTextEdit
+ into an efficient viewer for log text. The scrolling can be
+ reduced with the centerOnScroll() property, making the log viewer
+ even faster. Text can be formatted in a limited way, either using
+ a syntax highlighter (see below), or by appending html-formatted
+ text with appendHtml(). While QPlainTextEdit does not support
+ complex rich text rendering with tables and floats, it does
+ support limited paragraph-based formatting that you may need in a
+ log viewer.
+
+ \section2 Read-only Key Bindings
+
+ When QPlainTextEdit is used read-only the key bindings are limited to
+ navigation, and text may only be selected with the mouse:
+ \table
+ \header \i Keypresses \i Action
+ \row \i Qt::UpArrow \i Moves one line up.
+ \row \i Qt::DownArrow \i Moves one line down.
+ \row \i Qt::LeftArrow \i Moves one character to the left.
+ \row \i Qt::RightArrow \i Moves one character to the right.
+ \row \i PageUp \i Moves one (viewport) page up.
+ \row \i PageDown \i Moves one (viewport) page down.
+ \row \i Home \i Moves to the beginning of the text.
+ \row \i End \i Moves to the end of the text.
+ \row \i Alt+Wheel
+ \i Scrolls the page horizontally (the Wheel is the mouse wheel).
+ \row \i Ctrl+Wheel \i Zooms the text.
+ \row \i Ctrl+A \i Selects all text.
+ \endtable
+
+
+ \section1 Using QPlainTextEdit as an Editor
+
+ All the information about using QPlainTextEdit as a display widget also
+ applies here.
+
+ Selection of text is handled by the QTextCursor class, which provides
+ functionality for creating selections, retrieving the text contents or
+ deleting selections. You can retrieve the object that corresponds with
+ the user-visible cursor using the textCursor() method. If you want to set
+ a selection in QPlainTextEdit just create one on a QTextCursor object and
+ then make that cursor the visible cursor using setCursor(). The selection
+ can be copied to the clipboard with copy(), or cut to the clipboard with
+ cut(). The entire text can be selected using selectAll().
+
+ QPlainTextEdit holds a QTextDocument object which can be retrieved using the
+ document() method. You can also set your own document object using setDocument().
+ QTextDocument emits a textChanged() signal if the text changes and it also
+ provides a isModified() function which will return true if the text has been
+ modified since it was either loaded or since the last call to setModified
+ with false as argument. In addition it provides methods for undo and redo.
+
+ \section2 Syntax Highlighting
+
+ Just like QTextEdit, QPlainTextEdit works together with
+ QSyntaxHighlighter.
+
+ \section2 Editing Key Bindings
+
+ The list of key bindings which are implemented for editing:
+ \table
+ \header \i Keypresses \i Action
+ \row \i Backspace \i Deletes the character to the left of the cursor.
+ \row \i Delete \i Deletes the character to the right of the cursor.
+ \row \i Ctrl+C \i Copy the selected text to the clipboard.
+ \row \i Ctrl+Insert \i Copy the selected text to the clipboard.
+ \row \i Ctrl+K \i Deletes to the end of the line.
+ \row \i Ctrl+V \i Pastes the clipboard text into text edit.
+ \row \i Shift+Insert \i Pastes the clipboard text into text edit.
+ \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
+ \row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.
+ \row \i Ctrl+Z \i Undoes the last operation.
+ \row \i Ctrl+Y \i Redoes the last operation.
+ \row \i LeftArrow \i Moves the cursor one character to the left.
+ \row \i Ctrl+LeftArrow \i Moves the cursor one word to the left.
+ \row \i RightArrow \i Moves the cursor one character to the right.
+ \row \i Ctrl+RightArrow \i Moves the cursor one word to the right.
+ \row \i UpArrow \i Moves the cursor one line up.
+ \row \i Ctrl+UpArrow \i Moves the cursor one word up.
+ \row \i DownArrow \i Moves the cursor one line down.
+ \row \i Ctrl+Down Arrow \i Moves the cursor one word down.
+ \row \i PageUp \i Moves the cursor one page up.
+ \row \i PageDown \i Moves the cursor one page down.
+ \row \i Home \i Moves the cursor to the beginning of the line.
+ \row \i Ctrl+Home \i Moves the cursor to the beginning of the text.
+ \row \i End \i Moves the cursor to the end of the line.
+ \row \i Ctrl+End \i Moves the cursor to the end of the text.
+ \row \i Alt+Wheel \i Scrolls the page horizontally (the Wheel is the mouse wheel).
+ \row \i Ctrl+Wheel \i Zooms the text.
+ \endtable
+
+ To select (mark) text hold down the Shift key whilst pressing one
+ of the movement keystrokes, for example, \e{Shift+Right Arrow}
+ will select the character to the right, and \e{Shift+Ctrl+Right
+ Arrow} will select the word to the right, etc.
+
+ \section1 Differences to QTextEdit
+
+ QPlainTextEdit is a thin class, implemented by using most of the
+ technology that is behind QTextEdit and QTextDocument. Its
+ performance benefits over QTextEdit stem mostly from using a
+ different and simplified text layout called
+ QPlainTextDocumentLayout on the text document (see
+ QTextDocument::setDocumentLayout()). The plain text document layout
+ does not support tables nor embedded frames, and \e{replaces a
+ pixel-exact height calculation with a line-by-line respectively
+ paragraph-by-paragraph scrolling approach}. This makes it possible
+ to handle significantly larger documents, and still resize the
+ editor with line wrap enabled in real time. It also makes for a
+ fast log viewer (see setMaximumBlockCount()).
+
+
+ \sa QTextDocument, QTextCursor, {Application Example},
+ {Code Editor Example}, {Syntax Highlighter Example},
+ {Rich Text Processing}
+
+*/
+
+/*!
+ \property QPlainTextEdit::plainText
+
+ This property gets and sets the plain text editor's contents. The previous
+ contents are removed and undo/redo history is reset when this property is set.
+
+ By default, for an editor with no contents, this property contains an empty string.
+*/
+
+/*!
+ \property QPlainTextEdit::undoRedoEnabled
+ \brief whether undo and redo are enabled
+
+ Users are only able to undo or redo actions if this property is
+ true, and if there is an action that can be undone (or redone).
+
+ By default, this property is true.
+*/
+
+/*!
+ \enum QPlainTextEdit::LineWrapMode
+
+ \value NoWrap
+ \value WidgetWidth
+*/
+
+
+/*!
+ Constructs an empty QPlainTextEdit with parent \a
+ parent.
+*/
+QPlainTextEdit::QPlainTextEdit(QWidget *parent)
+ : QAbstractScrollArea(*new QPlainTextEditPrivate, parent)
+{
+ Q_D(QPlainTextEdit);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+QPlainTextEdit::QPlainTextEdit(QPlainTextEditPrivate &dd, QWidget *parent)
+ : QAbstractScrollArea(dd, parent)
+{
+ Q_D(QPlainTextEdit);
+ d->init();
+}
+
+/*!
+ Constructs a QPlainTextEdit with parent \a parent. The text edit will display
+ the plain text \a text.
+*/
+QPlainTextEdit::QPlainTextEdit(const QString &text, QWidget *parent)
+ : QAbstractScrollArea(*new QPlainTextEditPrivate, parent)
+{
+ Q_D(QPlainTextEdit);
+ d->init(text);
+}
+
+
+/*!
+ Destructor.
+*/
+QPlainTextEdit::~QPlainTextEdit()
+{
+ Q_D(QPlainTextEdit);
+ if (d->documentLayoutPtr) {
+ if (d->documentLayoutPtr->priv()->mainViewPrivate == d)
+ d->documentLayoutPtr->priv()->mainViewPrivate = 0;
+ }
+}
+
+/*!
+ Makes \a document the new document of the text editor.
+
+ The parent QObject of the provided document remains the owner
+ of the object. If the current document is a child of the text
+ editor, then it is deleted.
+
+ The document must have a document layout that inherits
+ QPlainTextDocumentLayout (see QTextDocument::setDocumentLayout()).
+
+ \sa document()
+*/
+void QPlainTextEdit::setDocument(QTextDocument *document)
+{
+ Q_D(QPlainTextEdit);
+ QPlainTextDocumentLayout *documentLayout = 0;
+
+ if (!document) {
+ document = new QTextDocument(d->control);
+ documentLayout = new QPlainTextDocumentLayout(document);
+ document->setDocumentLayout(documentLayout);
+ } else {
+ documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
+ if (!documentLayout) {
+ qWarning("QPlainTextEdit::setDocument: Document set does not support QPlainTextDocumentLayout");
+ return;
+ }
+ }
+ d->control->setDocument(document);
+ if (!documentLayout->priv()->mainViewPrivate)
+ documentLayout->priv()->mainViewPrivate = d;
+ d->documentLayoutPtr = documentLayout;
+ d->updateDefaultTextOption();
+ d->relayoutDocument();
+ d->_q_adjustScrollbars();
+}
+
+/*!
+ Returns a pointer to the underlying document.
+
+ \sa setDocument()
+*/
+QTextDocument *QPlainTextEdit::document() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->document();
+}
+
+/*!
+ Sets the visible \a cursor.
+*/
+void QPlainTextEdit::setTextCursor(const QTextCursor &cursor)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Returns a copy of the QTextCursor that represents the currently visible cursor.
+ Note that changes on the returned cursor do not affect QPlainTextEdit's cursor; use
+ setTextCursor() to update the visible cursor.
+ */
+QTextCursor QPlainTextEdit::textCursor() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->textCursor();
+}
+
+/*!
+ Returns the reference of the anchor at position \a pos, or an
+ empty string if no anchor exists at that point.
+
+ \since 4.7
+ */
+QString QPlainTextEdit::anchorAt(const QPoint &pos) const
+{
+ Q_D(const QPlainTextEdit);
+ int cursorPos = d->control->hitTest(pos + QPoint(d->horizontalOffset(),
+ d->verticalOffset()),
+ Qt::ExactHit);
+ if (cursorPos < 0)
+ return QString();
+
+ QTextDocumentPrivate *pieceTable = document()->docHandle();
+ QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
+ QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format);
+ return fmt.anchorHref();
+}
+
+/*!
+ Undoes the last operation.
+
+ If there is no operation to undo, i.e. there is no undo step in
+ the undo/redo history, nothing happens.
+
+ \sa redo()
+*/
+void QPlainTextEdit::undo()
+{
+ Q_D(QPlainTextEdit);
+ d->control->undo();
+}
+
+void QPlainTextEdit::redo()
+{
+ Q_D(QPlainTextEdit);
+ d->control->redo();
+}
+
+/*!
+ \fn void QPlainTextEdit::redo()
+
+ Redoes the last operation.
+
+ If there is no operation to redo, i.e. there is no redo step in
+ the undo/redo history, nothing happens.
+
+ \sa undo()
+*/
+
+#ifndef QT_NO_CLIPBOARD
+/*!
+ Copies the selected text to the clipboard and deletes it from
+ the text edit.
+
+ If there is no selected text nothing happens.
+
+ \sa copy() paste()
+*/
+
+void QPlainTextEdit::cut()
+{
+ Q_D(QPlainTextEdit);
+ d->control->cut();
+}
+
+/*!
+ Copies any selected text to the clipboard.
+
+ \sa copyAvailable()
+*/
+
+void QPlainTextEdit::copy()
+{
+ Q_D(QPlainTextEdit);
+ d->control->copy();
+}
+
+/*!
+ Pastes the text from the clipboard into the text edit at the
+ current cursor position.
+
+ If there is no text in the clipboard nothing happens.
+
+ To change the behavior of this function, i.e. to modify what
+ QPlainTextEdit can paste and how it is being pasted, reimplement the
+ virtual canInsertFromMimeData() and insertFromMimeData()
+ functions.
+
+ \sa cut() copy()
+*/
+
+void QPlainTextEdit::paste()
+{
+ Q_D(QPlainTextEdit);
+ d->control->paste();
+}
+#endif
+
+/*!
+ Deletes all the text in the text edit.
+
+ Note that the undo/redo history is cleared by this function.
+
+ \sa cut() setPlainText()
+*/
+void QPlainTextEdit::clear()
+{
+ Q_D(QPlainTextEdit);
+ // clears and sets empty content
+ d->control->topBlock = d->topLine = 0;
+ d->control->clear();
+}
+
+
+/*!
+ Selects all text.
+
+ \sa copy() cut() textCursor()
+ */
+void QPlainTextEdit::selectAll()
+{
+ Q_D(QPlainTextEdit);
+ d->control->selectAll();
+}
+
+/*! \internal
+*/
+bool QPlainTextEdit::event(QEvent *e)
+{
+ Q_D(QPlainTextEdit);
+
+#ifndef QT_NO_CONTEXTMENU
+ if (e->type() == QEvent::ContextMenu
+ && static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
+ ensureCursorVisible();
+ const QPoint cursorPos = cursorRect().center();
+ QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
+ ce.setAccepted(e->isAccepted());
+ const bool result = QAbstractScrollArea::event(&ce);
+ e->setAccepted(ce.isAccepted());
+ return result;
+ }
+#endif // QT_NO_CONTEXTMENU
+ if (e->type() == QEvent::ShortcutOverride
+ || e->type() == QEvent::ToolTip) {
+ d->sendControlEvent(e);
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ else if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {
+ if (QApplication::keypadNavigationEnabled())
+ d->sendControlEvent(e);
+ }
+#endif
+#ifndef QT_NO_GESTURES
+ else if (e->type() == QEvent::Gesture) {
+ QGestureEvent *ge = static_cast<QGestureEvent *>(e);
+ QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));
+ if (g) {
+ QScrollBar *hBar = horizontalScrollBar();
+ QScrollBar *vBar = verticalScrollBar();
+ if (g->state() == Qt::GestureStarted)
+ d->originalOffsetY = vBar->value();
+ QPointF offset = g->offset();
+ if (!offset.isNull()) {
+ if (QApplication::isRightToLeft())
+ offset.rx() *= -1;
+ // QPlainTextEdit scrolls by lines only in vertical direction
+ QFontMetrics fm(document()->defaultFont());
+ int lineHeight = fm.height();
+ int newX = hBar->value() - g->delta().x();
+ int newY = d->originalOffsetY - offset.y()/lineHeight;
+ hBar->setValue(newX);
+ vBar->setValue(newY);
+ }
+ }
+ return true;
+ }
+#endif // QT_NO_GESTURES
+ return QAbstractScrollArea::event(e);
+}
+
+/*! \internal
+*/
+
+void QPlainTextEdit::timerEvent(QTimerEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ if (e->timerId() == d->autoScrollTimer.timerId()) {
+ QRect visible = d->viewport->rect();
+ QPoint pos;
+ if (d->inDrag) {
+ pos = d->autoScrollDragPos;
+ visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
+ -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
+ } else {
+ const QPoint globalPos = QCursor::pos();
+ pos = d->viewport->mapFromGlobal(globalPos);
+ QMouseEvent ev(QEvent::MouseMove, pos, d->viewport->mapTo(d->viewport->topLevelWidget(), pos), globalPos,
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ mouseMoveEvent(&ev);
+ }
+ int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
+ int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
+ int delta = qMax(deltaX, deltaY);
+ if (delta >= 0) {
+ if (delta < 7)
+ delta = 7;
+ int timeout = 4900 / (delta * delta);
+ d->autoScrollTimer.start(timeout, this);
+
+ if (deltaY > 0)
+ d->vbar->triggerAction(pos.y() < visible.center().y() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ if (deltaX > 0)
+ d->hbar->triggerAction(pos.x() < visible.center().x() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ }
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ else if (e->timerId() == d->deleteAllTimer.timerId()) {
+ d->deleteAllTimer.stop();
+ clear();
+ }
+#endif
+}
+
+/*!
+ Changes the text of the text edit to the string \a text.
+ Any previous text is removed.
+
+ \a text is interpreted as plain text.
+
+ Note that the undo/redo history is cleared by this function.
+
+ \sa toText()
+*/
+
+void QPlainTextEdit::setPlainText(const QString &text)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setPlainText(text);
+}
+
+/*!
+ \fn QString QPlainTextEdit::toPlainText() const
+
+ Returns the text of the text edit as plain text.
+
+ \sa QPlainTextEdit::setPlainText()
+ */
+
+/*! \reimp
+*/
+void QPlainTextEdit::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QPlainTextEdit);
+
+#ifdef QT_KEYPAD_NAVIGATION
+ switch (e->key()) {
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard))
+ setEditFocus(!hasEditFocus());
+ else {
+ if (!hasEditFocus())
+ setEditFocus(true);
+ else {
+ QTextCursor cursor = d->control->textCursor();
+ QTextCharFormat charFmt = cursor.charFormat();
+ if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
+ setEditFocus(false);
+ }
+ }
+ }
+ }
+ break;
+ case Qt::Key_Back:
+ case Qt::Key_No:
+ if (!QApplication::keypadNavigationEnabled()
+ || (QApplication::keypadNavigationEnabled() && !hasEditFocus())) {
+ e->ignore();
+ return;
+ }
+ break;
+ default:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
+ if (e->text()[0].isPrint()) {
+ setEditFocus(true);
+ clear();
+ } else {
+ e->ignore();
+ return;
+ }
+ }
+ }
+ break;
+ }
+#endif
+
+#ifndef QT_NO_SHORTCUT
+
+ Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
+
+ if (tif & Qt::TextSelectableByKeyboard){
+ if (e == QKeySequence::SelectPreviousPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
+ return;
+ } else if (e ==QKeySequence::SelectNextPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
+ return;
+ }
+ }
+ if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
+ if (e == QKeySequence::MoveToPreviousPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
+ return;
+ } else if (e == QKeySequence::MoveToNextPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
+ return;
+ }
+ }
+
+ if (!(tif & Qt::TextEditable)) {
+ switch (e->key()) {
+ case Qt::Key_Space:
+ e->accept();
+ if (e->modifiers() & Qt::ShiftModifier)
+ d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
+ else
+ d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
+ break;
+ default:
+ d->sendControlEvent(e);
+ if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
+ if (e->key() == Qt::Key_Home) {
+ d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
+ e->accept();
+ } else if (e->key() == Qt::Key_End) {
+ d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
+ e->accept();
+ }
+ }
+ if (!e->isAccepted()) {
+ QAbstractScrollArea::keyPressEvent(e);
+ }
+ }
+ return;
+ }
+#endif // QT_NO_SHORTCUT
+
+ d->sendControlEvent(e);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!e->isAccepted()) {
+ switch (e->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ if (QApplication::keypadNavigationEnabled()) {
+ // Cursor position didn't change, so we want to leave
+ // these keys to change focus.
+ e->ignore();
+ return;
+ }
+ break;
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ if (QApplication::keypadNavigationEnabled()
+ && QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
+ // Same as for Key_Up and Key_Down.
+ e->ignore();
+ return;
+ }
+ break;
+ case Qt::Key_Back:
+ if (!e->isAutoRepeat()) {
+ if (QApplication::keypadNavigationEnabled()) {
+ if (document()->isEmpty()) {
+ setEditFocus(false);
+ e->accept();
+ } else if (!d->deleteAllTimer.isActive()) {
+ e->accept();
+ d->deleteAllTimer.start(750, this);
+ }
+ } else {
+ e->ignore();
+ return;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+#endif
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::keyReleaseEvent(QKeyEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_D(QPlainTextEdit);
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
+ && d->deleteAllTimer.isActive()) {
+ d->deleteAllTimer.stop();
+ QTextCursor cursor = d->control->textCursor();
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextList *list = cursor.currentList();
+ if (list && cursor.atBlockStart()) {
+ list->remove(cursor.block());
+ } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
+ blockFmt.setIndent(blockFmt.indent() - 1);
+ cursor.setBlockFormat(blockFmt);
+ } else {
+ cursor.deletePreviousChar();
+ }
+ setTextCursor(cursor);
+ }
+ }
+#else
+ Q_UNUSED(e);
+#endif
+}
+
+/*!
+ Loads the resource specified by the given \a type and \a name.
+
+ This function is an extension of QTextDocument::loadResource().
+
+ \sa QTextDocument::loadResource()
+*/
+QVariant QPlainTextEdit::loadResource(int type, const QUrl &name)
+{
+ Q_UNUSED(type);
+ Q_UNUSED(name);
+ return QVariant();
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ if (e->oldSize().width() != e->size().width())
+ d->relayoutDocument();
+ d->_q_adjustScrollbars();
+}
+
+void QPlainTextEditPrivate::relayoutDocument()
+{
+ QTextDocument *doc = control->document();
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ documentLayoutPtr = documentLayout;
+
+ int width = viewport->width();
+
+ if (documentLayout->priv()->mainViewPrivate == 0
+ || documentLayout->priv()->mainViewPrivate == this
+ || width > documentLayout->textWidth()) {
+ documentLayout->priv()->mainViewPrivate = this;
+ documentLayout->setTextWidth(width);
+ }
+}
+
+static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, QRectF gradientRect = QRectF())
+{
+ p->save();
+ if (brush.style() >= Qt::LinearGradientPattern && brush.style() <= Qt::ConicalGradientPattern) {
+ if (!gradientRect.isNull()) {
+ QTransform m = QTransform::fromTranslate(gradientRect.left(), gradientRect.top());
+ m.scale(gradientRect.width(), gradientRect.height());
+ brush.setTransform(m);
+ const_cast<QGradient *>(brush.gradient())->setCoordinateMode(QGradient::LogicalMode);
+ }
+ } else {
+ p->setBrushOrigin(rect.topLeft());
+ }
+ p->fillRect(rect, brush);
+ p->restore();
+}
+
+
+
+/*! \reimp
+*/
+void QPlainTextEdit::paintEvent(QPaintEvent *e)
+{
+ QPainter painter(viewport());
+ Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));
+
+ QPointF offset(contentOffset());
+
+ QRect er = e->rect();
+ QRect viewportRect = viewport()->rect();
+
+ bool editable = !isReadOnly();
+
+ QTextBlock block = firstVisibleBlock();
+ qreal maximumWidth = document()->documentLayout()->documentSize().width();
+
+ // Set a brush origin so that the WaveUnderline knows where the wave started
+ painter.setBrushOrigin(offset);
+
+ // keep right margin clean from full-width selection
+ int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)
+ - document()->documentMargin();
+ er.setRight(qMin(er.right(), maxX));
+ painter.setClipRect(er);
+
+
+ QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
+
+ while (block.isValid()) {
+
+ QRectF r = blockBoundingRect(block).translated(offset);
+ QTextLayout *layout = block.layout();
+
+ if (!block.isVisible()) {
+ offset.ry() += r.height();
+ block = block.next();
+ continue;
+ }
+
+ if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
+
+ QTextBlockFormat blockFormat = block.blockFormat();
+
+ QBrush bg = blockFormat.background();
+ if (bg != Qt::NoBrush) {
+ QRectF contentsRect = r;
+ contentsRect.setWidth(qMax(r.width(), maximumWidth));
+ fillBackground(&painter, contentsRect, bg);
+ }
+
+
+ QVector<QTextLayout::FormatRange> selections;
+ int blpos = block.position();
+ int bllen = block.length();
+ for (int i = 0; i < context.selections.size(); ++i) {
+ const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
+ const int selStart = range.cursor.selectionStart() - blpos;
+ const int selEnd = range.cursor.selectionEnd() - blpos;
+ if (selStart < bllen && selEnd > 0
+ && selEnd > selStart) {
+ QTextLayout::FormatRange o;
+ o.start = selStart;
+ o.length = selEnd - selStart;
+ o.format = range.format;
+ selections.append(o);
+ } else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
+ && block.contains(range.cursor.position())) {
+ // for full width selections we don't require an actual selection, just
+ // a position to specify the line. that's more convenience in usage.
+ QTextLayout::FormatRange o;
+ QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
+ o.start = l.textStart();
+ o.length = l.textLength();
+ if (o.start + o.length == bllen - 1)
+ ++o.length; // include newline
+ o.format = range.format;
+ selections.append(o);
+ }
+ }
+
+ bool drawCursor = (editable
+ && context.cursorPosition >= blpos
+ && context.cursorPosition < blpos + bllen);
+
+ bool drawCursorAsBlock = drawCursor && overwriteMode() ;
+
+ if (drawCursorAsBlock) {
+ if (context.cursorPosition == blpos + bllen - 1) {
+ drawCursorAsBlock = false;
+ } else {
+ QTextLayout::FormatRange o;
+ o.start = context.cursorPosition - blpos;
+ o.length = 1;
+ o.format.setForeground(palette().base());
+ o.format.setBackground(palette().text());
+ selections.append(o);
+ }
+ }
+
+
+ layout->draw(&painter, offset, selections, er);
+ if ((drawCursor && !drawCursorAsBlock)
+ || (editable && context.cursorPosition < -1
+ && !layout->preeditAreaText().isEmpty())) {
+ int cpos = context.cursorPosition;
+ if (cpos < -1)
+ cpos = layout->preeditAreaPosition() - (cpos + 2);
+ else
+ cpos -= blpos;
+ layout->drawCursor(&painter, offset, cpos, cursorWidth());
+ }
+ }
+
+ offset.ry() += r.height();
+ if (offset.y() > viewportRect.height())
+ break;
+ block = block.next();
+ }
+
+ if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
+ && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
+ painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
+ }
+}
+
+
+void QPlainTextEditPrivate::updateDefaultTextOption()
+{
+ QTextDocument *doc = control->document();
+
+ QTextOption opt = doc->defaultTextOption();
+ QTextOption::WrapMode oldWrapMode = opt.wrapMode();
+
+ if (lineWrap == QPlainTextEdit::NoWrap)
+ opt.setWrapMode(QTextOption::NoWrap);
+ else
+ opt.setWrapMode(wordWrap);
+
+ if (opt.wrapMode() != oldWrapMode)
+ doc->setDefaultTextOption(opt);
+}
+
+
+/*! \reimp
+*/
+void QPlainTextEdit::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QPlainTextEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
+ setEditFocus(true);
+#endif
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->inDrag = false; // paranoia
+ const QPoint pos = e->pos();
+ d->sendControlEvent(e);
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+ QRect visible = d->viewport->rect();
+ if (visible.contains(pos))
+ d->autoScrollTimer.stop();
+ else if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->sendControlEvent(e);
+ if (d->autoScrollTimer.isActive()) {
+ d->autoScrollTimer.stop();
+ d->ensureCursorVisible();
+ }
+
+ if (!isReadOnly() && rect().contains(e->pos()))
+ d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
+ d->clickCausedFocus = 0;
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+bool QPlainTextEdit::focusNextPrevChild(bool next)
+{
+ Q_D(const QPlainTextEdit);
+ if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
+ return false;
+ return QAbstractScrollArea::focusNextPrevChild(next);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \fn void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
+
+ Shows the standard context menu created with createStandardContextMenu().
+
+ If you do not want the text edit to have a context menu, you can set
+ its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
+ customize the context menu, reimplement this function. If you want
+ to extend the standard context menu, reimplement this function, call
+ createStandardContextMenu() and extend the menu returned.
+
+ Information about the event is passed in the \a event object.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 0
+*/
+void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->sendControlEvent(e);
+}
+#endif // QT_NO_CONTEXTMENU
+
+#ifndef QT_NO_DRAGANDDROP
+/*! \reimp
+*/
+void QPlainTextEdit::dragEnterEvent(QDragEnterEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->inDrag = true;
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->inDrag = false;
+ d->autoScrollTimer.stop();
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::dragMoveEvent(QDragMoveEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->autoScrollDragPos = e->pos();
+ if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::dropEvent(QDropEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ d->inDrag = false;
+ d->autoScrollTimer.stop();
+ d->sendControlEvent(e);
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*! \reimp
+ */
+void QPlainTextEdit::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QPlainTextEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (d->control->textInteractionFlags() & Qt::TextEditable
+ && QApplication::keypadNavigationEnabled()
+ && !hasEditFocus()) {
+ setEditFocus(true);
+ selectAll(); // so text is replaced rather than appended to
+ }
+#endif
+ d->sendControlEvent(e);
+ ensureCursorVisible();
+}
+
+/*!\reimp
+*/
+void QPlainTextEdit::scrollContentsBy(int dx, int /*dy*/)
+{
+ Q_D(QPlainTextEdit);
+ d->setTopLine(d->vbar->value(), dx);
+}
+
+/*!\reimp
+*/
+QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QPlainTextEdit);
+ QVariant v = d->control->inputMethodQuery(property);
+ const QPoint offset(-d->horizontalOffset(), -0);
+ if (v.type() == QVariant::RectF)
+ v = v.toRectF().toRect().translated(offset);
+ else if (v.type() == QVariant::PointF)
+ v = v.toPointF().toPoint() + offset;
+ else if (v.type() == QVariant::Rect)
+ v = v.toRect().translated(offset);
+ else if (v.type() == QVariant::Point)
+ v = v.toPoint() + offset;
+ return v;
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ if (e->reason() == Qt::MouseFocusReason) {
+ d->clickCausedFocus = 1;
+ }
+ QAbstractScrollArea::focusInEvent(e);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ QAbstractScrollArea::focusOutEvent(e);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::showEvent(QShowEvent *)
+{
+ Q_D(QPlainTextEdit);
+ if (d->showCursorOnInitialShow) {
+ d->showCursorOnInitialShow = false;
+ ensureCursorVisible();
+ }
+}
+
+/*! \reimp
+*/
+void QPlainTextEdit::changeEvent(QEvent *e)
+{
+ Q_D(QPlainTextEdit);
+ QAbstractScrollArea::changeEvent(e);
+ if (e->type() == QEvent::ApplicationFontChange
+ || e->type() == QEvent::FontChange) {
+ d->control->document()->setDefaultFont(font());
+ } else if(e->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow())
+ d->autoScrollTimer.stop();
+ } else if (e->type() == QEvent::EnabledChange) {
+ e->setAccepted(isEnabled());
+ d->sendControlEvent(e);
+ } else if (e->type() == QEvent::PaletteChange) {
+ d->control->setPalette(palette());
+ } else if (e->type() == QEvent::LayoutDirectionChange) {
+ d->sendControlEvent(e);
+ }
+}
+
+/*! \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QPlainTextEdit::wheelEvent(QWheelEvent *e)
+{
+ QAbstractScrollArea::wheelEvent(e);
+ updateMicroFocus();
+}
+#endif
+
+#ifndef QT_NO_CONTEXTMENU
+/*! This function creates the standard context menu which is shown
+ when the user clicks on the line edit with the right mouse
+ button. It is called from the default contextMenuEvent() handler.
+ The popup menu's ownership is transferred to the caller.
+*/
+
+QMenu *QPlainTextEdit::createStandardContextMenu()
+{
+ Q_D(QPlainTextEdit);
+ return d->control->createStandardContextMenu(QPointF(), this);
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ returns a QTextCursor at position \a pos (in viewport coordinates).
+*/
+QTextCursor QPlainTextEdit::cursorForPosition(const QPoint &pos) const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->cursorForPosition(d->mapToContents(pos));
+}
+
+/*!
+ returns a rectangle (in viewport coordinates) that includes the
+ \a cursor.
+ */
+QRect QPlainTextEdit::cursorRect(const QTextCursor &cursor) const
+{
+ Q_D(const QPlainTextEdit);
+ if (cursor.isNull())
+ return QRect();
+
+ QRect r = d->control->cursorRect(cursor).toRect();
+ r.translate(-d->horizontalOffset(),-d->verticalOffset());
+ return r;
+}
+
+/*!
+ returns a rectangle (in viewport coordinates) that includes the
+ cursor of the text edit.
+ */
+QRect QPlainTextEdit::cursorRect() const
+{
+ Q_D(const QPlainTextEdit);
+ QRect r = d->control->cursorRect().toRect();
+ r.translate(-d->horizontalOffset(),-d->verticalOffset());
+ return r;
+}
+
+
+/*!
+ \property QPlainTextEdit::overwriteMode
+ \brief whether text entered by the user will overwrite existing text
+
+ As with many text editors, the plain text editor widget can be configured
+ to insert or overwrite existing text with new text entered by the user.
+
+ If this property is true, existing text is overwritten, character-for-character
+ by new text; otherwise, text is inserted at the cursor position, displacing
+ existing text.
+
+ By default, this property is false (new text does not overwrite existing text).
+*/
+
+bool QPlainTextEdit::overwriteMode() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->overwriteMode();
+}
+
+void QPlainTextEdit::setOverwriteMode(bool overwrite)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setOverwriteMode(overwrite);
+}
+
+/*!
+ \property QPlainTextEdit::tabStopWidth
+ \brief the tab stop width in pixels
+
+ By default, this property contains a value of 80.
+*/
+
+int QPlainTextEdit::tabStopWidth() const
+{
+ Q_D(const QPlainTextEdit);
+ return qRound(d->control->document()->defaultTextOption().tabStop());
+}
+
+void QPlainTextEdit::setTabStopWidth(int width)
+{
+ Q_D(QPlainTextEdit);
+ QTextOption opt = d->control->document()->defaultTextOption();
+ if (opt.tabStop() == width || width < 0)
+ return;
+ opt.setTabStop(width);
+ d->control->document()->setDefaultTextOption(opt);
+}
+
+/*!
+ \property QPlainTextEdit::cursorWidth
+
+ This property specifies the width of the cursor in pixels. The default value is 1.
+*/
+int QPlainTextEdit::cursorWidth() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->cursorWidth();
+}
+
+void QPlainTextEdit::setCursorWidth(int width)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setCursorWidth(width);
+}
+
+
+
+/*!
+ This function allows temporarily marking certain regions in the document
+ with a given color, specified as \a selections. This can be useful for
+ example in a programming editor to mark a whole line of text with a given
+ background color to indicate the existence of a breakpoint.
+
+ \sa QTextEdit::ExtraSelection, extraSelections()
+*/
+void QPlainTextEdit::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setExtraSelections(selections);
+}
+
+/*!
+ Returns previously set extra selections.
+
+ \sa setExtraSelections()
+*/
+QList<QTextEdit::ExtraSelection> QPlainTextEdit::extraSelections() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->extraSelections();
+}
+
+/*!
+ This function returns a new MIME data object to represent the contents
+ of the text edit's current selection. It is called when the selection needs
+ to be encapsulated into a new QMimeData object; for example, when a drag
+ and drop operation is started, or when data is copied to the clipboard.
+
+ If you reimplement this function, note that the ownership of the returned
+ QMimeData object is passed to the caller. The selection can be retrieved
+ by using the textCursor() function.
+*/
+QMimeData *QPlainTextEdit::createMimeDataFromSelection() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->QWidgetTextControl::createMimeDataFromSelection();
+}
+
+/*!
+ This function returns true if the contents of the MIME data object, specified
+ by \a source, can be decoded and inserted into the document. It is called
+ for example when during a drag operation the mouse enters this widget and it
+ is necessary to determine whether it is possible to accept the drag.
+ */
+bool QPlainTextEdit::canInsertFromMimeData(const QMimeData *source) const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->QWidgetTextControl::canInsertFromMimeData(source);
+}
+
+/*!
+ This function inserts the contents of the MIME data object, specified
+ by \a source, into the text edit at the current cursor position. It is
+ called whenever text is inserted as the result of a clipboard paste
+ operation, or when the text edit accepts data from a drag and drop
+ operation.
+*/
+void QPlainTextEdit::insertFromMimeData(const QMimeData *source)
+{
+ Q_D(QPlainTextEdit);
+ d->control->QWidgetTextControl::insertFromMimeData(source);
+}
+
+/*!
+ \property QPlainTextEdit::readOnly
+ \brief whether the text edit is read-only
+
+ In a read-only text edit the user can only navigate through the
+ text and select text; modifying the text is not possible.
+
+ This property's default is false.
+*/
+
+bool QPlainTextEdit::isReadOnly() const
+{
+ Q_D(const QPlainTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+void QPlainTextEdit::setReadOnly(bool ro)
+{
+ Q_D(QPlainTextEdit);
+ Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
+ if (ro) {
+ flags = Qt::TextSelectableByMouse;
+ } else {
+ flags = Qt::TextEditorInteraction;
+ }
+ setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
+ d->control->setTextInteractionFlags(flags);
+}
+
+/*!
+ \property QPlainTextEdit::textInteractionFlags
+
+ Specifies how the label should interact with user input if it displays text.
+
+ If the flags contain either Qt::LinksAccessibleByKeyboard or Qt::TextSelectableByKeyboard
+ then the focus policy is also automatically set to Qt::ClickFocus.
+
+ The default value depends on whether the QPlainTextEdit is read-only
+ or editable.
+*/
+
+void QPlainTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+Qt::TextInteractionFlags QPlainTextEdit::textInteractionFlags() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+/*!
+ Merges the properties specified in \a modifier into the current character
+ format by calling QTextCursor::mergeCharFormat on the editor's cursor.
+ If the editor has a selection then the properties of \a modifier are
+ directly applied to the selection.
+
+ \sa QTextCursor::mergeCharFormat()
+ */
+void QPlainTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
+{
+ Q_D(QPlainTextEdit);
+ d->control->mergeCurrentCharFormat(modifier);
+}
+
+/*!
+ Sets the char format that is be used when inserting new text to \a
+ format by calling QTextCursor::setCharFormat() on the editor's
+ cursor. If the editor has a selection then the char format is
+ directly applied to the selection.
+ */
+void QPlainTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
+{
+ Q_D(QPlainTextEdit);
+ d->control->setCurrentCharFormat(format);
+}
+
+/*!
+ Returns the char format that is used when inserting new text.
+ */
+QTextCharFormat QPlainTextEdit::currentCharFormat() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->currentCharFormat();
+}
+
+
+
+/*!
+ Convenience slot that inserts \a text at the current
+ cursor position.
+
+ It is equivalent to
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 1
+ */
+void QPlainTextEdit::insertPlainText(const QString &text)
+{
+ Q_D(QPlainTextEdit);
+ d->control->insertPlainText(text);
+}
+
+
+/*!
+ Moves the cursor by performing the given \a operation.
+
+ If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
+ This is the same effect that the user achieves when they hold down the Shift key
+ and move the cursor with the cursor keys.
+
+ \sa QTextCursor::movePosition()
+*/
+void QPlainTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
+{
+ Q_D(QPlainTextEdit);
+ d->control->moveCursor(operation, mode);
+}
+
+/*!
+ Returns whether text can be pasted from the clipboard into the textedit.
+*/
+bool QPlainTextEdit::canPaste() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->canPaste();
+}
+
+/*!
+ Convenience function to print the text edit's document to the given \a printer. This
+ is equivalent to calling the print method on the document directly except that this
+ function also supports QPrinter::Selection as print range.
+
+ \sa QTextDocument::print()
+*/
+void QPlainTextEdit::print(QPagedPaintDevice *printer) const
+{
+ Q_D(const QPlainTextEdit);
+ d->control->print(printer);
+}
+
+/*! \property QPlainTextEdit::tabChangesFocus
+ \brief whether \gui Tab changes focus or is accepted as input
+
+ In some occasions text edits should not allow the user to input
+ tabulators or change indentation using the \gui Tab key, as this breaks
+ the focus chain. The default is false.
+
+*/
+
+bool QPlainTextEdit::tabChangesFocus() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->tabChangesFocus;
+}
+
+void QPlainTextEdit::setTabChangesFocus(bool b)
+{
+ Q_D(QPlainTextEdit);
+ d->tabChangesFocus = b;
+}
+
+/*!
+ \property QPlainTextEdit::documentTitle
+ \brief the title of the document parsed from the text.
+
+ By default, this property contains an empty string.
+*/
+
+/*!
+ \property QPlainTextEdit::lineWrapMode
+ \brief the line wrap mode
+
+ The default mode is WidgetWidth which causes words to be
+ wrapped at the right edge of the text edit. Wrapping occurs at
+ whitespace, keeping whole words intact. If you want wrapping to
+ occur within words use setWordWrapMode().
+*/
+
+QPlainTextEdit::LineWrapMode QPlainTextEdit::lineWrapMode() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->lineWrap;
+}
+
+void QPlainTextEdit::setLineWrapMode(LineWrapMode wrap)
+{
+ Q_D(QPlainTextEdit);
+ if (d->lineWrap == wrap)
+ return;
+ d->lineWrap = wrap;
+ d->updateDefaultTextOption();
+ d->relayoutDocument();
+ d->_q_adjustScrollbars();
+ ensureCursorVisible();
+}
+
+/*!
+ \property QPlainTextEdit::wordWrapMode
+ \brief the mode QPlainTextEdit will use when wrapping text by words
+
+ By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
+
+ \sa QTextOption::WrapMode
+*/
+
+QTextOption::WrapMode QPlainTextEdit::wordWrapMode() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->wordWrap;
+}
+
+void QPlainTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
+{
+ Q_D(QPlainTextEdit);
+ if (mode == d->wordWrap)
+ return;
+ d->wordWrap = mode;
+ d->updateDefaultTextOption();
+}
+
+/*!
+ \property QPlainTextEdit::backgroundVisible
+ \brief whether the palette background is visible outside the document area
+
+ If set to true, the plain text edit paints the palette background
+ on the viewport area not covered by the text document. Otherwise,
+ if set to false, it won't. The feature makes it possible for
+ the user to visually distinguish between the area of the document,
+ painted with the base color of the palette, and the empty
+ area not covered by any document.
+
+ The default is false.
+*/
+
+bool QPlainTextEdit::backgroundVisible() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->backgroundVisible;
+}
+
+void QPlainTextEdit::setBackgroundVisible(bool visible)
+{
+ Q_D(QPlainTextEdit);
+ if (visible == d->backgroundVisible)
+ return;
+ d->backgroundVisible = visible;
+ d->updateViewport();
+}
+
+/*!
+ \property QPlainTextEdit::centerOnScroll
+ \brief whether the cursor should be centered on screen
+
+ If set to true, the plain text edit scrolls the document
+ vertically to make the cursor visible at the center of the
+ viewport. This also allows the text edit to scroll below the end
+ of the document. Otherwise, if set to false, the plain text edit
+ scrolls the smallest amount possible to ensure the cursor is
+ visible. The same algorithm is applied to any new line appended
+ through appendPlainText().
+
+ The default is false.
+
+ \sa centerCursor(), ensureCursorVisible()
+*/
+
+bool QPlainTextEdit::centerOnScroll() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->centerOnScroll;
+}
+
+void QPlainTextEdit::setCenterOnScroll(bool enabled)
+{
+ Q_D(QPlainTextEdit);
+ if (enabled == d->centerOnScroll)
+ return;
+ d->centerOnScroll = enabled;
+}
+
+
+
+/*!
+ Finds the next occurrence of the string, \a exp, using the given
+ \a options. Returns true if \a exp was found and changes the
+ cursor to select the match; otherwise returns false.
+*/
+bool QPlainTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
+{
+ Q_D(QPlainTextEdit);
+ return d->control->find(exp, options);
+}
+
+/*!
+ \fn void QPlainTextEdit::copyAvailable(bool yes)
+
+ This signal is emitted when text is selected or de-selected in the
+ text edit.
+
+ When text is selected this signal will be emitted with \a yes set
+ to true. If no text has been selected or if the selected text is
+ de-selected this signal is emitted with \a yes set to false.
+
+ If \a yes is true then copy() can be used to copy the selection to
+ the clipboard. If \a yes is false then copy() does nothing.
+
+ \sa selectionChanged()
+*/
+
+
+/*!
+ \fn void QPlainTextEdit::selectionChanged()
+
+ This signal is emitted whenever the selection changes.
+
+ \sa copyAvailable()
+*/
+
+/*!
+ \fn void QPlainTextEdit::cursorPositionChanged()
+
+ This signal is emitted whenever the position of the
+ cursor changed.
+*/
+
+
+
+/*!
+ \fn void QPlainTextEdit::updateRequest(const QRect &rect, int dy)
+
+ This signal is emitted when the text document needs an update of
+ the specified \a rect. If the text is scrolled, \a rect will cover
+ the entire viewport area. If the text is scrolled vertically, \a
+ dy carries the amount of pixels the viewport was scrolled.
+
+ The purpose of the signal is to support extra widgets in plain
+ text edit subclasses that e.g. show line numbers, breakpoints, or
+ other extra information.
+*/
+
+/*! \fn void QPlainTextEdit::blockCountChanged(int newBlockCount);
+
+ This signal is emitted whenever the block count changes. The new
+ block count is passed in \a newBlockCount.
+*/
+
+/*! \fn void QPlainTextEdit::modificationChanged(bool changed);
+
+ This signal is emitted whenever the content of the document
+ changes in a way that affects the modification state. If \a
+ changed is true, the document has been modified; otherwise it is
+ false.
+
+ For example, calling setModified(false) on a document and then
+ inserting text causes the signal to get emitted. If you undo that
+ operation, causing the document to return to its original
+ unmodified state, the signal will get emitted again.
+*/
+
+
+
+
+void QPlainTextEditPrivate::append(const QString &text, Qt::TextFormat format)
+{
+ Q_Q(QPlainTextEdit);
+
+ QTextDocument *document = control->document();
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ int maximumBlockCount = document->maximumBlockCount();
+ if (maximumBlockCount)
+ document->setMaximumBlockCount(0);
+
+ const bool atBottom = q->isVisible()
+ && (control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
+ <= viewport->rect().bottom());
+
+ if (!q->isVisible())
+ showCursorOnInitialShow = true;
+
+ bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
+ documentLayout->priv()->blockDocumentSizeChanged = true;
+
+ if (format == Qt::RichText)
+ control->appendHtml(text);
+ else if (format == Qt::PlainText)
+ control->appendPlainText(text);
+ else
+ control->append(text);
+
+ if (maximumBlockCount > 0) {
+ if (document->blockCount() > maximumBlockCount) {
+ bool blockUpdate = false;
+ if (control->topBlock) {
+ control->topBlock--;
+ blockUpdate = true;
+ emit q->updateRequest(viewport->rect(), 0);
+ }
+
+ bool updatesBlocked = documentLayout->priv()->blockUpdate;
+ documentLayout->priv()->blockUpdate = blockUpdate;
+ QTextCursor cursor(document);
+ cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ documentLayout->priv()->blockUpdate = updatesBlocked;
+ }
+ document->setMaximumBlockCount(maximumBlockCount);
+ }
+
+ documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
+ _q_adjustScrollbars();
+
+
+ if (atBottom) {
+ const bool needScroll = !centerOnScroll
+ || control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
+ > viewport->rect().bottom();
+ if (needScroll)
+ vbar->setValue(vbar->maximum());
+ }
+}
+
+
+/*!
+ Appends a new paragraph with \a text to the end of the text edit.
+
+ \sa appendHtml()
+*/
+
+void QPlainTextEdit::appendPlainText(const QString &text)
+{
+ Q_D(QPlainTextEdit);
+ d->append(text, Qt::PlainText);
+}
+
+/*!
+ Appends a new paragraph with \a html to the end of the text edit.
+
+ appendPlainText()
+*/
+
+void QPlainTextEdit::appendHtml(const QString &html)
+{
+ Q_D(QPlainTextEdit);
+ d->append(html, Qt::RichText);
+}
+
+void QPlainTextEditPrivate::ensureCursorVisible(bool center)
+{
+ Q_Q(QPlainTextEdit);
+ QRect visible = viewport->rect();
+ QRect cr = q->cursorRect();
+ if (cr.top() < visible.top() || cr.bottom() > visible.bottom()) {
+ ensureVisible(control->textCursor().position(), center);
+ }
+
+ const bool rtl = q->isRightToLeft();
+ if (cr.left() < visible.left() || cr.right() > visible.right()) {
+ int x = cr.center().x() + horizontalOffset() - visible.width()/2;
+ hbar->setValue(rtl ? hbar->maximum() - x : x);
+ }
+}
+
+/*!
+ Ensures that the cursor is visible by scrolling the text edit if
+ necessary.
+
+ \sa centerCursor(), centerOnScroll
+*/
+void QPlainTextEdit::ensureCursorVisible()
+{
+ Q_D(QPlainTextEdit);
+ d->ensureCursorVisible(d->centerOnScroll);
+}
+
+
+/*! Scrolls the document in order to center the cursor vertically.
+
+\sa ensureCursorVisible(), centerOnScroll
+ */
+void QPlainTextEdit::centerCursor()
+{
+ Q_D(QPlainTextEdit);
+ d->ensureVisible(textCursor().position(), true, true);
+}
+
+/*!
+ Returns the first visible block.
+
+ \sa blockBoundingRect()
+ */
+QTextBlock QPlainTextEdit::firstVisibleBlock() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->firstVisibleBlock();
+}
+
+/*! Returns the content's origin in viewport coordinates.
+
+ The origin of the content of a plain text edit is always the top
+ left corner of the first visible text block. The content offset
+ is different from (0,0) when the text has been scrolled
+ horizontally, or when the first visible block has been scrolled
+ partially off the screen, i.e. the visible text does not start
+ with the first line of the first visible block, or when the first
+ visible block is the very first block and the editor displays a
+ margin.
+
+ \sa firstVisibleBlock(), horizontalScrollBar(), verticalScrollBar()
+ */
+QPointF QPlainTextEdit::contentOffset() const
+{
+ Q_D(const QPlainTextEdit);
+ return QPointF(-d->horizontalOffset(), -d->verticalOffset());
+}
+
+
+/*! Returns the bounding rectangle of the text \a block in content
+ coordinates. Translate the rectangle with the contentOffset() to get
+ visual coordinates on the viewport.
+
+ \sa firstVisibleBlock(), blockBoundingRect()
+ */
+QRectF QPlainTextEdit::blockBoundingGeometry(const QTextBlock &block) const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->blockBoundingRect(block);
+}
+
+/*!
+ Returns the bounding rectangle of the text \a block in the block's own coordinates.
+
+ \sa blockBoundingGeometry()
+ */
+QRectF QPlainTextEdit::blockBoundingRect(const QTextBlock &block) const
+{
+ QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+ return documentLayout->blockBoundingRect(block);
+}
+
+/*!
+ \property QPlainTextEdit::blockCount
+ \brief the number of text blocks in the document.
+
+ By default, in an empty document, this property contains a value of 1.
+*/
+int QPlainTextEdit::blockCount() const
+{
+ return document()->blockCount();
+}
+
+/*! Returns the paint context for the viewport(), useful only when
+ reimplementing paintEvent().
+ */
+QAbstractTextDocumentLayout::PaintContext QPlainTextEdit::getPaintContext() const
+{
+ Q_D(const QPlainTextEdit);
+ return d->control->getPaintContext(d->viewport);
+}
+
+/*!
+ \property QPlainTextEdit::maximumBlockCount
+ \brief the limit for blocks in the document.
+
+ Specifies the maximum number of blocks the document may have. If there are
+ more blocks in the document that specified with this property blocks are removed
+ from the beginning of the document.
+
+ A negative or zero value specifies that the document may contain an unlimited
+ amount of blocks.
+
+ The default value is 0.
+
+ Note that setting this property will apply the limit immediately to the document
+ contents. Setting this property also disables the undo redo history.
+
+*/
+
+
+/*!
+ \fn void QPlainTextEdit::textChanged()
+
+ This signal is emitted whenever the document's content changes; for
+ example, when text is inserted or deleted, or when formatting is applied.
+*/
+
+/*!
+ \fn void QPlainTextEdit::undoAvailable(bool available)
+
+ This signal is emitted whenever undo operations become available
+ (\a available is true) or unavailable (\a available is false).
+*/
+
+/*!
+ \fn void QPlainTextEdit::redoAvailable(bool available)
+
+ This signal is emitted whenever redo operations become available
+ (\a available is true) or unavailable (\a available is false).
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qplaintextedit.cpp"
+#include "moc_qplaintextedit_p.cpp"
+
+#endif // QT_NO_TEXTEDIT
diff --git a/src/widgets/widgets/qplaintextedit.h b/src/widgets/widgets/qplaintextedit.h
new file mode 100644
index 0000000000..d5fa71bbb7
--- /dev/null
+++ b/src/widgets/widgets/qplaintextedit.h
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLAINTEXTEDIT_H
+#define QPLAINTEXTEDIT_H
+
+#include <QtWidgets/qtextedit.h>
+
+#include <QtWidgets/qabstractscrollarea.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextoption.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qtextformat.h>
+#include <QtGui/qabstracttextdocumentlayout.h>
+
+#ifndef QT_NO_TEXTEDIT
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QStyleSheet;
+class QTextDocument;
+class QMenu;
+class QPlainTextEditPrivate;
+class QMimeData;
+class QPagedPaintDevice;
+
+class Q_WIDGETS_EXPORT QPlainTextEdit : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPlainTextEdit)
+ Q_ENUMS(LineWrapMode)
+ Q_PROPERTY(bool tabChangesFocus READ tabChangesFocus WRITE setTabChangesFocus)
+ Q_PROPERTY(QString documentTitle READ documentTitle WRITE setDocumentTitle)
+ Q_PROPERTY(bool undoRedoEnabled READ isUndoRedoEnabled WRITE setUndoRedoEnabled)
+ Q_PROPERTY(LineWrapMode lineWrapMode READ lineWrapMode WRITE setLineWrapMode)
+ QDOC_PROPERTY(QTextOption::WrapMode wordWrapMode READ wordWrapMode WRITE setWordWrapMode)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(QString plainText READ toPlainText WRITE setPlainText NOTIFY textChanged USER true)
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
+ Q_PROPERTY(int tabStopWidth READ tabStopWidth WRITE setTabStopWidth)
+ Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
+ Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
+ Q_PROPERTY(int blockCount READ blockCount)
+ Q_PROPERTY(int maximumBlockCount READ maximumBlockCount WRITE setMaximumBlockCount)
+ Q_PROPERTY(bool backgroundVisible READ backgroundVisible WRITE setBackgroundVisible)
+ Q_PROPERTY(bool centerOnScroll READ centerOnScroll WRITE setCenterOnScroll)
+public:
+ enum LineWrapMode {
+ NoWrap,
+ WidgetWidth
+ };
+
+ explicit QPlainTextEdit(QWidget *parent = 0);
+ explicit QPlainTextEdit(const QString &text, QWidget *parent = 0);
+ virtual ~QPlainTextEdit();
+
+ void setDocument(QTextDocument *document);
+ QTextDocument *document() const;
+
+ void setTextCursor(const QTextCursor &cursor);
+ QTextCursor textCursor() const;
+
+ bool isReadOnly() const;
+ void setReadOnly(bool ro);
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ void mergeCurrentCharFormat(const QTextCharFormat &modifier);
+ void setCurrentCharFormat(const QTextCharFormat &format);
+ QTextCharFormat currentCharFormat() const;
+
+ bool tabChangesFocus() const;
+ void setTabChangesFocus(bool b);
+
+ inline void setDocumentTitle(const QString &title)
+ { document()->setMetaInformation(QTextDocument::DocumentTitle, title); }
+ inline QString documentTitle() const
+ { return document()->metaInformation(QTextDocument::DocumentTitle); }
+
+ inline bool isUndoRedoEnabled() const
+ { return document()->isUndoRedoEnabled(); }
+ inline void setUndoRedoEnabled(bool enable)
+ { document()->setUndoRedoEnabled(enable); }
+
+ inline void setMaximumBlockCount(int maximum)
+ { document()->setMaximumBlockCount(maximum); }
+ inline int maximumBlockCount() const
+ { return document()->maximumBlockCount(); }
+
+
+ LineWrapMode lineWrapMode() const;
+ void setLineWrapMode(LineWrapMode mode);
+
+ QTextOption::WrapMode wordWrapMode() const;
+ void setWordWrapMode(QTextOption::WrapMode policy);
+
+ void setBackgroundVisible(bool visible);
+ bool backgroundVisible() const;
+
+ void setCenterOnScroll(bool enabled);
+ bool centerOnScroll() const;
+
+ bool find(const QString &exp, QTextDocument::FindFlags options = 0);
+
+ inline QString toPlainText() const
+ { return document()->toPlainText(); }
+
+ void ensureCursorVisible();
+
+ virtual QVariant loadResource(int type, const QUrl &name);
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *createStandardContextMenu();
+#endif
+
+ QTextCursor cursorForPosition(const QPoint &pos) const;
+ QRect cursorRect(const QTextCursor &cursor) const;
+ QRect cursorRect() const;
+
+ QString anchorAt(const QPoint &pos) const;
+
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
+
+ int tabStopWidth() const;
+ void setTabStopWidth(int width);
+
+ int cursorWidth() const;
+ void setCursorWidth(int width);
+
+ void setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections);
+ QList<QTextEdit::ExtraSelection> extraSelections() const;
+
+ void moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+
+ bool canPaste() const;
+
+ void print(QPagedPaintDevice *printer) const;
+
+ int blockCount() const;
+
+public Q_SLOTS:
+
+ void setPlainText(const QString &text);
+
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+ void undo();
+ void redo();
+
+ void clear();
+ void selectAll();
+
+ void insertPlainText(const QString &text);
+
+ void appendPlainText(const QString &text);
+ void appendHtml(const QString &html);
+
+ void centerCursor();
+
+Q_SIGNALS:
+ void textChanged();
+ void undoAvailable(bool b);
+ void redoAvailable(bool b);
+ void copyAvailable(bool b);
+ void selectionChanged();
+ void cursorPositionChanged();
+
+ void updateRequest(const QRect &rect, int dy);
+ void blockCountChanged(int newBlockCount);
+ void modificationChanged(bool);
+
+protected:
+ virtual bool event(QEvent *e);
+ virtual void timerEvent(QTimerEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+ virtual void keyReleaseEvent(QKeyEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void paintEvent(QPaintEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void mouseDoubleClickEvent(QMouseEvent *e);
+ virtual bool focusNextPrevChild(bool next);
+#ifndef QT_NO_CONTEXTMENU
+ virtual void contextMenuEvent(QContextMenuEvent *e);
+#endif
+#ifndef QT_NO_DRAGANDDROP
+ virtual void dragEnterEvent(QDragEnterEvent *e);
+ virtual void dragLeaveEvent(QDragLeaveEvent *e);
+ virtual void dragMoveEvent(QDragMoveEvent *e);
+ virtual void dropEvent(QDropEvent *e);
+#endif
+ virtual void focusInEvent(QFocusEvent *e);
+ virtual void focusOutEvent(QFocusEvent *e);
+ virtual void showEvent(QShowEvent *);
+ virtual void changeEvent(QEvent *e);
+#ifndef QT_NO_WHEELEVENT
+ virtual void wheelEvent(QWheelEvent *e);
+#endif
+
+ virtual QMimeData *createMimeDataFromSelection() const;
+ virtual bool canInsertFromMimeData(const QMimeData *source) const;
+ virtual void insertFromMimeData(const QMimeData *source);
+
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ QPlainTextEdit(QPlainTextEditPrivate &dd, QWidget *parent);
+
+ virtual void scrollContentsBy(int dx, int dy);
+
+ QTextBlock firstVisibleBlock() const;
+ QPointF contentOffset() const;
+ QRectF blockBoundingRect(const QTextBlock &block) const;
+ QRectF blockBoundingGeometry(const QTextBlock &block) const;
+ QAbstractTextDocumentLayout::PaintContext getPaintContext() const;
+
+
+private:
+ Q_DISABLE_COPY(QPlainTextEdit)
+ Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r))
+ Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars())
+ Q_PRIVATE_SLOT(d_func(), void _q_verticalScrollbarActionTriggered(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged())
+
+ friend class QPlainTextEditControl;
+};
+
+
+class QPlainTextDocumentLayoutPrivate;
+class Q_WIDGETS_EXPORT QPlainTextDocumentLayout : public QAbstractTextDocumentLayout
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPlainTextDocumentLayout)
+ Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
+
+public:
+ QPlainTextDocumentLayout(QTextDocument *document);
+ ~QPlainTextDocumentLayout();
+
+ void draw(QPainter *, const PaintContext &);
+ int hitTest(const QPointF &, Qt::HitTestAccuracy ) const;
+
+ int pageCount() const;
+ QSizeF documentSize() const;
+
+ QRectF frameBoundingRect(QTextFrame *) const;
+ QRectF blockBoundingRect(const QTextBlock &block) const;
+
+ void ensureBlockLayout(const QTextBlock &block) const;
+
+ void setCursorWidth(int width);
+ int cursorWidth() const;
+
+ void requestUpdate();
+
+protected:
+ void documentChanged(int from, int /*charsRemoved*/, int charsAdded);
+
+
+private:
+ void setTextWidth(qreal newWidth);
+ qreal textWidth() const;
+ void layoutBlock(const QTextBlock &block);
+ qreal blockWidth(const QTextBlock &block);
+
+ QPlainTextDocumentLayoutPrivate *priv() const;
+
+ friend class QPlainTextEdit;
+ friend class QPlainTextEditPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+
+#endif // QT_NO_TEXTEDIT
+
+#endif // QPLAINTEXTEDIT_H
diff --git a/src/widgets/widgets/qplaintextedit_p.h b/src/widgets/widgets/qplaintextedit_p.h
new file mode 100644
index 0000000000..190156a684
--- /dev/null
+++ b/src/widgets/widgets/qplaintextedit_p.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLAINTEXTEDIT_P_H
+#define QPLAINTEXTEDIT_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/qabstractscrollarea_p.h"
+#include "QtGui/qtextdocumentfragment.h"
+#include "QtWidgets/qscrollbar.h"
+#include "QtGui/qtextcursor.h"
+#include "QtGui/qtextformat.h"
+#include "QtWidgets/qmenu.h"
+#include "QtGui/qabstracttextdocumentlayout.h"
+#include "QtCore/qbasictimer.h"
+#include "private/qwidgettextcontrol_p.h"
+#include "qplaintextedit.h"
+
+#ifndef QT_NO_TEXTEDIT
+
+QT_BEGIN_NAMESPACE
+
+class QMimeData;
+
+class QPlainTextEdit;
+class ExtraArea;
+
+class QPlainTextEditControl : public QWidgetTextControl
+{
+ Q_OBJECT
+public:
+ QPlainTextEditControl(QPlainTextEdit *parent);
+
+
+ QMimeData *createMimeDataFromSelection() const;
+ bool canInsertFromMimeData(const QMimeData *source) const;
+ void insertFromMimeData(const QMimeData *source);
+ int hitTest(const QPointF &point, Qt::HitTestAccuracy = Qt::FuzzyHit) const;
+ QRectF blockBoundingRect(const QTextBlock &block) const;
+ inline QRectF cursorRect(const QTextCursor &cursor) const {
+ QRectF r = QWidgetTextControl::cursorRect(cursor);
+ r.setLeft(qMax(r.left(), (qreal) 0.));
+ return r;
+ }
+ inline QRectF cursorRect() { return cursorRect(textCursor()); }
+ void ensureCursorVisible() {
+ textEdit->ensureCursorVisible();
+ emit microFocusChanged();
+ }
+
+
+ QPlainTextEdit *textEdit;
+ int topBlock;
+ QTextBlock firstVisibleBlock() const;
+
+ QVariant loadResource(int type, const QUrl &name) {
+ return textEdit->loadResource(type, name);
+ }
+
+};
+
+
+class QPlainTextEditPrivate : public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QPlainTextEdit)
+public:
+ QPlainTextEditPrivate();
+
+ void init(const QString &txt = QString());
+ void _q_repaintContents(const QRectF &contentsRect);
+
+ inline QPoint mapToContents(const QPoint &point) const
+ { return QPoint(point.x() + horizontalOffset(), point.y() + verticalOffset()); }
+
+ void _q_adjustScrollbars();
+ void _q_verticalScrollbarActionTriggered(int action);
+ void ensureViewportLayouted();
+ void relayoutDocument();
+
+ void pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode, bool moveCursor = true);
+
+ inline int horizontalOffset() const
+ { return (q_func()->isRightToLeft() ? (hbar->maximum() - hbar->value()) : hbar->value()); }
+ int verticalOffset(int topBlock, int topLine) const;
+ int verticalOffset() const;
+
+ inline void sendControlEvent(QEvent *e)
+ { control->processEvent(e, QPointF(horizontalOffset(), verticalOffset()), viewport); }
+
+ void updateDefaultTextOption();
+
+ QPlainTextEditControl *control;
+
+ bool tabChangesFocus;
+
+ QBasicTimer autoScrollTimer;
+ QPoint autoScrollDragPos;
+
+ QPlainTextEdit::LineWrapMode lineWrap;
+ QTextOption::WrapMode wordWrap;
+
+ uint showCursorOnInitialShow : 1;
+ uint backgroundVisible : 1;
+ uint centerOnScroll : 1;
+ uint inDrag : 1;
+ uint clickCausedFocus : 1;
+
+ int topLine;
+
+ void setTopLine(int visualTopLine, int dx = 0);
+ void setTopBlock(int newTopBlock, int newTopLine, int dx = 0);
+
+ void ensureVisible(int position, bool center, bool forceCenter = false);
+ void ensureCursorVisible(bool center = false);
+ void updateViewport();
+
+ QPointer<QPlainTextDocumentLayout> documentLayoutPtr;
+
+ void append(const QString &text, Qt::TextFormat format = Qt::AutoText);
+
+ qreal pageUpDownLastCursorY;
+ bool pageUpDownLastCursorYIsValid;
+
+
+#ifdef QT_KEYPAD_NAVIGATION
+ QBasicTimer deleteAllTimer;
+#endif
+
+ void _q_cursorPositionChanged();
+ void _q_modificationChanged(bool);
+
+ int originalOffsetY;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TEXTEDIT
+
+#endif // QPLAINTEXTEDIT_P_H
diff --git a/src/widgets/widgets/qprogressbar.cpp b/src/widgets/widgets/qprogressbar.cpp
new file mode 100644
index 0000000000..dd92bda993
--- /dev/null
+++ b/src/widgets/widgets/qprogressbar.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qprogressbar.h"
+#ifndef QT_NO_PROGRESSBAR
+#include <qevent.h>
+#include <qpainter.h>
+#include <qstylepainter.h>
+#include <qstyleoption.h>
+#include <private/qwidget_p.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include <qaccessible.h>
+#endif
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+class QProgressBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QProgressBar)
+
+public:
+ QProgressBarPrivate();
+
+ void init();
+ inline void resetLayoutItemMargins();
+
+ int minimum;
+ int maximum;
+ int value;
+ Qt::Alignment alignment;
+ uint textVisible : 1;
+ int lastPaintedValue;
+ Qt::Orientation orientation;
+ bool invertedAppearance;
+ QProgressBar::Direction textDirection;
+ QString format;
+ inline int bound(int val) const { return qMax(minimum-1, qMin(maximum, val)); }
+ bool repaintRequired() const;
+};
+
+QProgressBarPrivate::QProgressBarPrivate()
+ : minimum(0), maximum(100), value(-1), alignment(Qt::AlignLeft), textVisible(true),
+ lastPaintedValue(-1), orientation(Qt::Horizontal), invertedAppearance(false),
+ textDirection(QProgressBar::TopToBottom), format(QLatin1String("%p%"))
+{
+}
+
+void QProgressBarPrivate::init()
+{
+ Q_Q(QProgressBar);
+ QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ if (orientation == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ resetLayoutItemMargins();
+}
+
+void QProgressBarPrivate::resetLayoutItemMargins()
+{
+ Q_Q(QProgressBar);
+ QStyleOptionProgressBar option;
+ q->initStyleOption(&option);
+ setLayoutItemMargins(QStyle::SE_ProgressBarLayoutItem, &option);
+}
+
+/*!
+ Initialize \a option with the values from this QProgressBar. This method is useful
+ for subclasses when they need a QStyleOptionProgressBar or QStyleOptionProgressBarV2,
+ but don't want to fill in all the information themselves. This function will check the version
+ of the QStyleOptionProgressBar and fill in the additional values for a
+ QStyleOptionProgressBarV2.
+
+ \sa QStyleOption::initFrom()
+*/
+void QProgressBar::initStyleOption(QStyleOptionProgressBar *option) const
+{
+ if (!option)
+ return;
+ Q_D(const QProgressBar);
+ option->initFrom(this);
+
+ if (d->orientation == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+ option->minimum = d->minimum;
+ option->maximum = d->maximum;
+ option->progress = d->value;
+ option->textAlignment = d->alignment;
+ option->textVisible = d->textVisible;
+ option->text = text();
+
+ if (QStyleOptionProgressBarV2 *optionV2
+ = qstyleoption_cast<QStyleOptionProgressBarV2 *>(option)) {
+ optionV2->orientation = d->orientation; // ### Qt 5: use State_Horizontal instead
+ optionV2->invertedAppearance = d->invertedAppearance;
+ optionV2->bottomToTop = (d->textDirection == QProgressBar::BottomToTop);
+ }
+}
+
+bool QProgressBarPrivate::repaintRequired() const
+{
+ Q_Q(const QProgressBar);
+ if (value == lastPaintedValue)
+ return false;
+
+ int valueDifference = qAbs(value - lastPaintedValue);
+
+ // Check if the text needs to be repainted
+ if (value == minimum || value == maximum)
+ return true;
+ if (textVisible) {
+ if ((format.contains(QLatin1String("%v"))))
+ return true;
+ if ((format.contains(QLatin1String("%p"))
+ && valueDifference >= qAbs((maximum - minimum) / 100)))
+ return true;
+ }
+
+ // Check if the bar needs to be repainted
+ QStyleOptionProgressBarV2 opt;
+ q->initStyleOption(&opt);
+ int cw = q->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, q);
+ QRect groove = q->style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, q);
+ // This expression is basically
+ // (valueDifference / (maximum - minimum) > cw / groove.width())
+ // transformed to avoid integer division.
+ int grooveBlock = (q->orientation() == Qt::Horizontal) ? groove.width() : groove.height();
+ return (valueDifference * grooveBlock > cw * (maximum - minimum));
+}
+
+/*!
+ \class QProgressBar
+ \brief The QProgressBar widget provides a horizontal or vertical progress bar.
+
+ \ingroup basicwidgets
+
+
+ A progress bar is used to give the user an indication of the
+ progress of an operation and to reassure them that the application
+ is still running.
+
+ The progress bar uses the concept of \e steps. You set it up by
+ specifying the minimum and maximum possible step values, and it
+ will display the percentage of steps that have been completed
+ when you later give it the current step value. The percentage is
+ calculated by dividing the progress (value() - minimum()) divided
+ by maximum() - minimum().
+
+ You can specify the minimum and maximum number of steps with
+ setMinimum() and setMaximum. The current number of steps is set
+ with setValue(). The progress bar can be rewound to the
+ beginning with reset().
+
+ If minimum and maximum both are set to 0, the bar shows a busy
+ indicator instead of a percentage of steps. This is useful, for
+ example, when using QFtp or QNetworkAccessManager to download
+ items when they are unable to determine the size of the item being
+ downloaded.
+
+ \table
+ \row \o \inlineimage macintosh-progressbar.png Screenshot of a Macintosh style progress bar
+ \o A progress bar shown in the Macintosh widget style.
+ \row \o \inlineimage windowsxp-progressbar.png Screenshot of a Windows XP style progress bar
+ \o A progress bar shown in the Windows XP widget style.
+ \row \o \inlineimage plastique-progressbar.png Screenshot of a Plastique style progress bar
+ \o A progress bar shown in the Plastique widget style.
+ \endtable
+
+ \sa QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
+*/
+
+/*!
+ \since 4.1
+ \enum QProgressBar::Direction
+ \brief Specifies the reading direction of the \l text for vertical progress bars.
+
+ \value TopToBottom The text is rotated 90 degrees clockwise.
+ \value BottomToTop The text is rotated 90 degrees counter-clockwise.
+
+ Note that whether or not the text is drawn is dependent on the style.
+ Currently CDE, CleanLooks, Motif, and Plastique draw the text. Mac, Windows
+ and WindowsXP style do not.
+
+ \sa textDirection
+*/
+
+/*!
+ \fn void QProgressBar::valueChanged(int value)
+
+ This signal is emitted when the value shown in the progress bar changes.
+ \a value is the new value shown by the progress bar.
+*/
+
+/*!
+ Constructs a progress bar with the given \a parent.
+
+ By default, the minimum step value is set to 0, and the maximum to 100.
+
+ \sa setRange()
+*/
+
+QProgressBar::QProgressBar(QWidget *parent)
+ : QWidget(*(new QProgressBarPrivate), parent, 0)
+{
+ d_func()->init();
+}
+
+/*!
+ Reset the progress bar. The progress bar "rewinds" and shows no
+ progress.
+*/
+
+void QProgressBar::reset()
+{
+ Q_D(QProgressBar);
+ d->value = d->minimum - 1;
+ if (d->minimum == INT_MIN)
+ d->value = INT_MIN;
+ repaint();
+}
+
+/*!
+ \property QProgressBar::minimum
+ \brief the progress bar's minimum value
+
+ When setting this property, the \l maximum is adjusted if
+ necessary to ensure that the range remains valid. If the
+ current value falls outside the new range, the progress bar is reset
+ with reset().
+*/
+void QProgressBar::setMinimum(int minimum)
+{
+ setRange(minimum, qMax(d_func()->maximum, minimum));
+}
+
+int QProgressBar::minimum() const
+{
+ return d_func()->minimum;
+}
+
+
+/*!
+ \property QProgressBar::maximum
+ \brief the progress bar's maximum value
+
+ When setting this property, the \l minimum is adjusted if
+ necessary to ensure that the range remains valid. If the
+ current value falls outside the new range, the progress bar is reset
+ with reset().
+*/
+
+void QProgressBar::setMaximum(int maximum)
+{
+ setRange(qMin(d_func()->minimum, maximum), maximum);
+}
+
+int QProgressBar::maximum() const
+{
+ return d_func()->maximum;
+}
+
+/*!
+ \property QProgressBar::value
+ \brief the progress bar's current value
+
+ Attempting to change the current value to one outside
+ the minimum-maximum range has no effect on the current value.
+*/
+void QProgressBar::setValue(int value)
+{
+ Q_D(QProgressBar);
+ if (d->value == value
+ || ((value > d->maximum || value < d->minimum)
+ && (d->maximum != 0 || d->minimum != 0)))
+ return;
+ d->value = value;
+ emit valueChanged(value);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
+#endif
+ if (d->repaintRequired())
+ repaint();
+}
+
+int QProgressBar::value() const
+{
+ return d_func()->value;
+}
+
+/*!
+ Sets the progress bar's minimum and maximum values to \a minimum and
+ \a maximum respectively.
+
+ If \a maximum is smaller than \a minimum, \a minimum becomes the only
+ legal value.
+
+ If the current value falls outside the new range, the progress bar is reset
+ with reset().
+
+ \sa minimum maximum
+*/
+void QProgressBar::setRange(int minimum, int maximum)
+{
+ Q_D(QProgressBar);
+ d->minimum = minimum;
+ d->maximum = qMax(minimum, maximum);
+ if ( d->value <(d->minimum-1) || d->value > d->maximum)
+ reset();
+}
+/*!
+ \property QProgressBar::textVisible
+ \brief whether the current completed percentage should be displayed
+
+ This property may be ignored by the style (e.g., QMacStyle never draws the text).
+
+ \sa textDirection
+*/
+void QProgressBar::setTextVisible(bool visible)
+{
+ Q_D(QProgressBar);
+ if (d->textVisible != visible) {
+ d->textVisible = visible;
+ repaint();
+ }
+}
+
+bool QProgressBar::isTextVisible() const
+{
+ return d_func()->textVisible;
+}
+
+/*!
+ \property QProgressBar::alignment
+ \brief the alignment of the progress bar
+*/
+void QProgressBar::setAlignment(Qt::Alignment alignment)
+{
+ if (d_func()->alignment != alignment) {
+ d_func()->alignment = alignment;
+ repaint();
+ }
+}
+
+Qt::Alignment QProgressBar::alignment() const
+{
+ return d_func()->alignment;
+}
+
+/*!
+ \reimp
+*/
+void QProgressBar::paintEvent(QPaintEvent *)
+{
+ QStylePainter paint(this);
+ QStyleOptionProgressBarV2 opt;
+ initStyleOption(&opt);
+ paint.drawControl(QStyle::CE_ProgressBar, opt);
+ d_func()->lastPaintedValue = d_func()->value;
+}
+
+/*!
+ \reimp
+*/
+QSize QProgressBar::sizeHint() const
+{
+ ensurePolished();
+ QFontMetrics fm = fontMetrics();
+ QStyleOptionProgressBarV2 opt;
+ initStyleOption(&opt);
+ int cw = style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, this);
+ QSize size = QSize(qMax(9, cw) * 7 + fm.width(QLatin1Char('0')) * 4, fm.height() + 8);
+ if (opt.orientation == Qt::Vertical)
+ size.transpose();
+ return style()->sizeFromContents(QStyle::CT_ProgressBar, &opt, size, this);
+}
+
+/*!
+ \reimp
+*/
+QSize QProgressBar::minimumSizeHint() const
+{
+ QSize size;
+ if (orientation() == Qt::Horizontal)
+ size = QSize(sizeHint().width(), fontMetrics().height() + 2);
+ else
+ size = QSize(fontMetrics().height() + 2, sizeHint().height());
+ return size;
+}
+
+/*!
+ \property QProgressBar::text
+ \brief the descriptive text shown with the progress bar
+
+ The text returned is the same as the text displayed in the center
+ (or in some styles, to the left) of the progress bar.
+
+ The progress shown in the text may be smaller than the minimum value,
+ indicating that the progress bar is in the "reset" state before any
+ progress is set.
+
+ In the default implementation, the text either contains a percentage
+ value that indicates the progress so far, or it is blank because the
+ progress bar is in the reset state.
+*/
+QString QProgressBar::text() const
+{
+ Q_D(const QProgressBar);
+ if ((d->maximum == 0 && d->minimum == 0) || d->value < d->minimum
+ || (d->value == INT_MIN && d->minimum == INT_MIN))
+ return QString();
+
+ qint64 totalSteps = qint64(d->maximum) - d->minimum;
+
+ QString result = d->format;
+ result.replace(QLatin1String("%m"), QString::number(totalSteps));
+ result.replace(QLatin1String("%v"), QString::number(d->value));
+
+ // If max and min are equal and we get this far, it means that the
+ // progress bar has one step and that we are on that step. Return
+ // 100% here in order to avoid division by zero further down.
+ if (totalSteps == 0) {
+ result.replace(QLatin1String("%p"), QString::number(100));
+ return result;
+ }
+
+ int progress = (qreal(d->value) - d->minimum) * 100.0 / totalSteps;
+ result.replace(QLatin1String("%p"), QString::number(progress));
+ return result;
+}
+
+/*!
+ \since 4.1
+ \property QProgressBar::orientation
+ \brief the orientation of the progress bar
+
+ The orientation must be \l Qt::Horizontal (the default) or \l
+ Qt::Vertical.
+
+ \sa invertedAppearance, textDirection
+*/
+
+void QProgressBar::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QProgressBar);
+ if (d->orientation == orientation)
+ return;
+ d->orientation = orientation;
+ if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy(sp);
+ setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ }
+ d->resetLayoutItemMargins();
+ update();
+ updateGeometry();
+}
+
+Qt::Orientation QProgressBar::orientation() const
+{
+ Q_D(const QProgressBar);
+ return d->orientation;
+}
+
+/*!
+ \since 4.1
+ \property QProgressBar::invertedAppearance
+ \brief whether or not a progress bar shows its progress inverted
+
+ If this property is false, the progress bar grows in the other
+ direction (e.g. from right to left). By default, the progress bar
+ is not inverted.
+
+ \sa orientation, layoutDirection
+*/
+
+void QProgressBar::setInvertedAppearance(bool invert)
+{
+ Q_D(QProgressBar);
+ d->invertedAppearance = invert;
+ update();
+}
+
+bool QProgressBar::invertedAppearance()
+{
+ Q_D(QProgressBar);
+ return d->invertedAppearance;
+}
+
+/*!
+ \since 4.1
+ \property QProgressBar::textDirection
+ \brief the reading direction of the \l text for vertical progress bars
+
+ This property has no impact on horizontal progress bars.
+ By default, the reading direction is QProgressBar::TopToBottom.
+
+ \sa orientation, textVisible
+*/
+void QProgressBar::setTextDirection(QProgressBar::Direction textDirection)
+{
+ Q_D(QProgressBar);
+ d->textDirection = textDirection;
+ update();
+}
+
+QProgressBar::Direction QProgressBar::textDirection()
+{
+ Q_D(QProgressBar);
+ return d->textDirection;
+}
+
+/*! \reimp */
+bool QProgressBar::event(QEvent *e)
+{
+ Q_D(QProgressBar);
+ if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->resetLayoutItemMargins();
+ return QWidget::event(e);
+}
+
+/*!
+ \since 4.2
+ \property QProgressBar::format
+ \brief the string used to generate the current text
+
+ %p - is replaced by the percentage completed.
+ %v - is replaced by the current value.
+ %m - is replaced by the total number of steps.
+
+ The default value is "%p%".
+
+ \sa text()
+*/
+void QProgressBar::setFormat(const QString &format)
+{
+ Q_D(QProgressBar);
+ if (d->format == format)
+ return;
+ d->format = format;
+ update();
+}
+
+QString QProgressBar::format() const
+{
+ Q_D(const QProgressBar);
+ return d->format;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PROGRESSBAR
diff --git a/src/widgets/widgets/qprogressbar.h b/src/widgets/widgets/qprogressbar.h
new file mode 100644
index 0000000000..ac34f64a2e
--- /dev/null
+++ b/src/widgets/widgets/qprogressbar.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROGRESSBAR_H
+#define QPROGRESSBAR_H
+
+#include <QtWidgets/qframe.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PROGRESSBAR
+
+class QProgressBarPrivate;
+class QStyleOptionProgressBar;
+
+class Q_WIDGETS_EXPORT QProgressBar : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS(Direction)
+ Q_PROPERTY(int minimum READ minimum WRITE setMinimum)
+ Q_PROPERTY(int maximum READ maximum WRITE setMaximum)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+ Q_PROPERTY(bool textVisible READ isTextVisible WRITE setTextVisible)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(bool invertedAppearance READ invertedAppearance WRITE setInvertedAppearance)
+ Q_PROPERTY(Direction textDirection READ textDirection WRITE setTextDirection)
+ Q_PROPERTY(QString format READ format WRITE setFormat)
+
+public:
+ enum Direction { TopToBottom, BottomToTop };
+
+ explicit QProgressBar(QWidget *parent = 0);
+
+ int minimum() const;
+ int maximum() const;
+
+ int value() const;
+
+ virtual QString text() const;
+ void setTextVisible(bool visible);
+ bool isTextVisible() const;
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment alignment);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ Qt::Orientation orientation() const;
+
+ void setInvertedAppearance(bool invert);
+ bool invertedAppearance(); //### Qt5 make const
+ bool invertedAppearance() const { return const_cast<QProgressBar *>(this)->invertedAppearance(); }
+ void setTextDirection(QProgressBar::Direction textDirection);
+ QProgressBar::Direction textDirection(); //### Qt5 make const
+ QProgressBar::Direction textDirection() const { return const_cast<QProgressBar *>(this)->textDirection(); }
+
+ void setFormat(const QString &format);
+ QString format() const;
+
+public Q_SLOTS:
+ void reset();
+ void setRange(int minimum, int maximum);
+ void setMinimum(int minimum);
+ void setMaximum(int maximum);
+ void setValue(int value);
+ void setOrientation(Qt::Orientation);
+
+Q_SIGNALS:
+ void valueChanged(int value);
+
+protected:
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *);
+ void initStyleOption(QStyleOptionProgressBar *option) const;
+
+private:
+ Q_DECLARE_PRIVATE(QProgressBar)
+ Q_DISABLE_COPY(QProgressBar)
+};
+
+#endif // QT_NO_PROGRESSBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPROGRESSBAR_H
diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp
new file mode 100644
index 0000000000..a1bc4d9cb9
--- /dev/null
+++ b/src/widgets/widgets/qpushbutton.cpp
@@ -0,0 +1,784 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdesktopwidget.h"
+#include "qdialog.h"
+#include <private/qdialog_p.h>
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qfontmetrics.h"
+#include "qmenu.h"
+#include "qstylepainter.h"
+#include "qpixmap.h"
+#include "qpointer.h"
+#include "qpushbutton.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtoolbar.h"
+#include "qdebug.h"
+#include "qlayoutitem.h"
+#include "qdialogbuttonbox.h"
+#ifdef Q_WS_MAC
+#include "qmacstyle_mac.h"
+#include "private/qmacstyle_mac_p.h"
+#endif // Q_WS_MAC
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+#include "private/qmenu_p.h"
+#include "private/qpushbutton_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \class QPushButton
+ \brief The QPushButton widget provides a command button.
+
+ \ingroup basicwidgets
+
+
+ The push button, or command button, is perhaps the most commonly
+ used widget in any graphical user interface. Push (click) a button
+ to command the computer to perform some action, or to answer a
+ question. Typical buttons are OK, Apply, Cancel, Close, Yes, No
+ and Help.
+
+ A command button is rectangular and typically displays a text
+ label describing its action. A shortcut key can be specified by
+ preceding the preferred character with an ampersand in the
+ text. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qpushbutton.cpp 0
+
+ In this example the shortcut is \e{Alt+D}. See the \l
+ {QShortcut#mnemonic}{QShortcut} documentation for details (to
+ display an actual ampersand, use '&&').
+
+ Push buttons display a textual label, and optionally a small
+ icon. These can be set using the constructors and changed later
+ using setText() and setIcon(). If the button is disabled the
+ appearance of the text and icon will be manipulated with respect
+ to the GUI style to make the button look "disabled".
+
+ A push button emits the signal clicked() when it is activated by
+ the mouse, the Spacebar or by a keyboard shortcut. Connect to
+ this signal to perform the button's action. Push buttons also
+ provide less commonly used signals, for example, pressed() and
+ released().
+
+ Command buttons in dialogs are by default auto-default buttons,
+ i.e. they become the default push button automatically when they
+ receive the keyboard input focus. A default button is a push
+ button that is activated when the user presses the Enter or Return
+ key in a dialog. You can change this with setAutoDefault(). Note
+ that auto-default buttons reserve a little extra space which is
+ necessary to draw a default-button indicator. If you do not want
+ this space around your buttons, call setAutoDefault(false).
+
+ Being so central, the button widget has grown to accommodate a
+ great many variations in the past decade. The Microsoft style
+ guide now shows about ten different states of Windows push buttons
+ and the text implies that there are dozens more when all the
+ combinations of features are taken into consideration.
+
+ The most important modes or states are:
+ \list
+ \i Available or not (grayed out, disabled).
+ \i Standard push button, toggling push button or menu button.
+ \i On or off (only for toggling push buttons).
+ \i Default or normal. The default button in a dialog can generally
+ be "clicked" using the Enter or Return key.
+ \i Auto-repeat or not.
+ \i Pressed down or not.
+ \endlist
+
+ As a general rule, use a push button when the application or
+ dialog window performs an action when the user clicks on it (such
+ as Apply, Cancel, Close and Help) \e and when the widget is
+ supposed to have a wide, rectangular shape with a text label.
+ Small, typically square buttons that change the state of the
+ window rather than performing an action (such as the buttons in
+ the top-right corner of the QFileDialog) are not command buttons,
+ but tool buttons. Qt provides a special class (QToolButton) for
+ these buttons.
+
+ If you need toggle behavior (see setCheckable()) or a button
+ that auto-repeats the activation signal when being pushed down
+ like the arrows in a scroll bar (see setAutoRepeat()), a command
+ button is probably not what you want. When in doubt, use a tool
+ button.
+
+ A variation of a command button is a menu button. These provide
+ not just one command, but several, since when they are clicked
+ they pop up a menu of options. Use the method setMenu() to
+ associate a popup menu with a push button.
+
+ Other classes of buttons are option buttons (see QRadioButton) and
+ check boxes (see QCheckBox).
+
+ \table 100%
+ \row \o \inlineimage macintosh-pushbutton.png Screenshot of a Macintosh style push button
+ \o A push button shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+
+ Note that when a button's width becomes smaller than 50 or
+ its height becomes smaller than 30, the button's corners are
+ changed from round to square. Use the setMinimumSize()
+ function to prevent this behavior.
+
+ \row \o \inlineimage windowsxp-pushbutton.png Screenshot of a Windows XP style push button
+ \o A push button shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-pushbutton.png Screenshot of a Plastique style push button
+ \o A push button shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ In Qt, the QAbstractButton base class provides most of the modes
+ and other API, and QPushButton provides GUI logic.
+ See QAbstractButton for more information about the API.
+
+ \sa QToolButton, QRadioButton, QCheckBox, {fowler}{GUI Design Handbook: Push Button}
+*/
+
+/*!
+ \property QPushButton::autoDefault
+ \brief whether the push button is an auto default button
+
+ If this property is set to true then the push button is an auto
+ default button.
+
+ In some GUI styles a default button is drawn with an extra frame
+ around it, up to 3 pixels or more. Qt automatically keeps this
+ space free around auto-default buttons, i.e. auto-default buttons
+ may have a slightly larger size hint.
+
+ This property's default is true for buttons that have a QDialog
+ parent; otherwise it defaults to false.
+
+ See the \l default property for details of how \l default and
+ auto-default interact.
+*/
+
+/*!
+ \property QPushButton::default
+ \brief whether the push button is the default button
+
+ Default and autodefault buttons decide what happens when the user
+ presses enter in a dialog.
+
+ A button with this property set to true (i.e., the dialog's
+ \e default button,) will automatically be pressed when the user presses enter,
+ with one exception: if an \a autoDefault button currently has focus, the autoDefault
+ button is pressed. When the dialog has \l autoDefault buttons but no default button,
+ pressing enter will press either the \l autoDefault button that currently has focus, or if no
+ button has focus, the next \l autoDefault button in the focus chain.
+
+ In a dialog, only one push button at a time can be the default
+ button. This button is then displayed with an additional frame
+ (depending on the GUI style).
+
+ The default button behavior is provided only in dialogs. Buttons
+ can always be clicked from the keyboard by pressing Spacebar when
+ the button has focus.
+
+ If the default property is set to false on the current default button
+ while the dialog is visible, a new default will automatically be
+ assigned the next time a pushbutton in the dialog receives focus.
+
+ This property's default is false.
+*/
+
+/*!
+ \property QPushButton::flat
+ \brief whether the button border is raised
+
+ This property's default is false. If this property is set, most
+ styles will not paint the button background unless the button is
+ being pressed. setAutoFillBackground() can be used to ensure that
+ the background is filled using the QPalette::Button brush.
+*/
+
+/*!
+ Constructs a push button with no text and a \a parent.
+*/
+
+QPushButton::QPushButton(QWidget *parent)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ d->init();
+}
+
+/*!
+ Constructs a push button with the parent \a parent and the text \a
+ text.
+*/
+
+QPushButton::QPushButton(const QString &text, QWidget *parent)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ setText(text);
+ d->init();
+}
+
+
+/*!
+ Constructs a push button with an \a icon and a \a text, and a \a parent.
+
+ Note that you can also pass a QPixmap object as an icon (thanks to
+ the implicit type conversion provided by C++).
+
+*/
+QPushButton::QPushButton(const QIcon& icon, const QString &text, QWidget *parent)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ setText(text);
+ setIcon(icon);
+ d->init();
+}
+
+/*! \internal
+ */
+QPushButton::QPushButton(QPushButtonPrivate &dd, QWidget *parent)
+ : QAbstractButton(dd, parent)
+{
+ Q_D(QPushButton);
+ d->init();
+}
+
+/*!
+ Destroys the push button.
+*/
+QPushButton::~QPushButton()
+{
+}
+
+QDialog *QPushButtonPrivate::dialogParent() const
+{
+ Q_Q(const QPushButton);
+ const QWidget *p = q;
+ while (p && !p->isWindow()) {
+ p = p->parentWidget();
+ if (const QDialog *dialog = qobject_cast<const QDialog *>(p))
+ return const_cast<QDialog *>(dialog);
+ }
+ return 0;
+}
+
+/*!
+ Initialize \a option with the values from this QPushButton. This method is useful
+ for subclasses when they need a QStyleOptionButton, but don't want to fill
+ in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QPushButton::initStyleOption(QStyleOptionButton *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QPushButton);
+ option->initFrom(this);
+ option->features = QStyleOptionButton::None;
+ if (d->flat)
+ option->features |= QStyleOptionButton::Flat;
+#ifndef QT_NO_MENU
+ if (d->menu)
+ option->features |= QStyleOptionButton::HasMenu;
+#endif
+ if (autoDefault() || d->defaultButton)
+ option->features |= QStyleOptionButton::AutoDefaultButton;
+ if (d->defaultButton)
+ option->features |= QStyleOptionButton::DefaultButton;
+ if (d->down || d->menuOpen)
+ option->state |= QStyle::State_Sunken;
+ if (d->checked)
+ option->state |= QStyle::State_On;
+ if (!d->flat && !d->down)
+ option->state |= QStyle::State_Raised;
+ option->text = d->text;
+ option->icon = d->icon;
+ option->iconSize = iconSize();
+}
+
+void QPushButton::setAutoDefault(bool enable)
+{
+ Q_D(QPushButton);
+ uint state = enable ? QPushButtonPrivate::On : QPushButtonPrivate::Off;
+ if (d->autoDefault != QPushButtonPrivate::Auto && d->autoDefault == state)
+ return;
+ d->autoDefault = state;
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+}
+
+bool QPushButton::autoDefault() const
+{
+ Q_D(const QPushButton);
+ if(d->autoDefault == QPushButtonPrivate::Auto)
+ return ( d->dialogParent() != 0 );
+ return d->autoDefault;
+}
+
+void QPushButton::setDefault(bool enable)
+{
+ Q_D(QPushButton);
+ if (d->defaultButton == enable)
+ return;
+ d->defaultButton = enable;
+ if (d->defaultButton) {
+ if (QDialog *dlg = d->dialogParent())
+ dlg->d_func()->setMainDefault(this);
+ }
+ update();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::StateChanged);
+#endif
+}
+
+bool QPushButton::isDefault() const
+{
+ Q_D(const QPushButton);
+ return d->defaultButton;
+}
+
+/*!
+ \reimp
+*/
+QSize QPushButton::sizeHint() const
+{
+ Q_D(const QPushButton);
+ if (d->sizeHint.isValid() && d->lastAutoDefault == autoDefault())
+ return d->sizeHint;
+ d->lastAutoDefault = autoDefault();
+ ensurePolished();
+
+ int w = 0, h = 0;
+
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+
+ // calculate contents size...
+#ifndef QT_NO_ICON
+
+ bool showButtonBoxIcons = qobject_cast<QDialogButtonBox*>(parentWidget())
+ && style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons);
+
+ if (!icon().isNull() || showButtonBoxIcons) {
+ int ih = opt.iconSize.height();
+ int iw = opt.iconSize.width() + 4;
+ w += iw;
+ h = qMax(h, ih);
+ }
+#endif
+ QString s(text());
+ bool empty = s.isEmpty();
+ if (empty)
+ s = QString::fromLatin1("XXXX");
+ QFontMetrics fm = fontMetrics();
+ QSize sz = fm.size(Qt::TextShowMnemonic, s);
+ if(!empty || !w)
+ w += sz.width();
+ if(!empty || !h)
+ h = qMax(h, sz.height());
+ opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
+#ifndef QT_NO_MENU
+ if (menu())
+ w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
+#endif
+ d->sizeHint = (style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h), this).
+ expandedTo(QApplication::globalStrut()));
+ return d->sizeHint;
+}
+
+/*!
+ \reimp
+ */
+QSize QPushButton::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+
+/*!\reimp
+*/
+void QPushButton::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionButton option;
+ initStyleOption(&option);
+ p.drawControl(QStyle::CE_PushButton, option);
+}
+
+
+/*! \reimp */
+void QPushButton::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QPushButton);
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (autoDefault() || d->defaultButton) {
+ click();
+ break;
+ }
+ // fall through
+ default:
+ QAbstractButton::keyPressEvent(e);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QPushButton);
+ if (e->reason() != Qt::PopupFocusReason && autoDefault() && !d->defaultButton) {
+ d->defaultButton = true;
+ QDialog *dlg = qobject_cast<QDialog*>(window());
+ if (dlg)
+ dlg->d_func()->setDefault(this);
+ }
+ QAbstractButton::focusInEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QPushButton);
+ if (e->reason() != Qt::PopupFocusReason && autoDefault() && d->defaultButton) {
+ QDialog *dlg = qobject_cast<QDialog*>(window());
+ if (dlg)
+ dlg->d_func()->setDefault(0);
+ else
+ d->defaultButton = false;
+ }
+
+ QAbstractButton::focusOutEvent(e);
+#ifndef QT_NO_MENU
+ if (d->menu && d->menu->isVisible()) // restore pressed status
+ setDown(true);
+#endif
+}
+
+#ifndef QT_NO_MENU
+/*!
+ Associates the popup menu \a menu with this push button. This
+ turns the button into a menu button, which in some styles will
+ produce a small triangle to the right of the button's text.
+
+ Ownership of the menu is \e not transferred to the push button.
+
+ \table 100%
+ \row
+ \o \inlineimage plastique-pushbutton-menu.png Screenshot of a Plastique style push button with popup menu.
+ \o \inlineimage cleanlooks-pushbutton-menu.png Screenshot of a Cleanlooks style push button with popup menu.
+ \o Push buttons with popup menus shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}
+ (left) and \l{Cleanlooks Style Widget Gallery}{Cleanlooks widget style} (right).
+ \endtable
+
+ \sa menu()
+*/
+void QPushButton::setMenu(QMenu* menu)
+{
+ Q_D(QPushButton);
+ if (menu == d->menu)
+ return;
+
+ if (menu && !d->menu) {
+ connect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed()), Qt::UniqueConnection);
+ }
+ if (d->menu)
+ removeAction(d->menu->menuAction());
+ d->menu = menu;
+ if (d->menu)
+ addAction(d->menu->menuAction());
+
+ d->resetLayoutItemMargins();
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+}
+
+/*!
+ Returns the button's associated popup menu or 0 if no popup menu
+ has been set.
+
+ \sa setMenu()
+*/
+QMenu* QPushButton::menu() const
+{
+ Q_D(const QPushButton);
+ return d->menu;
+}
+
+/*!
+ Shows (pops up) the associated popup menu. If there is no such
+ menu, this function does nothing. This function does not return
+ until the popup menu has been closed by the user.
+*/
+void QPushButton::showMenu()
+{
+ Q_D(QPushButton);
+ if (!d || !d->menu)
+ return;
+ setDown(true);
+ d->_q_popupPressed();
+}
+
+void QPushButtonPrivate::_q_popupPressed()
+{
+ Q_Q(QPushButton);
+ if (!down || !menu)
+ return;
+
+ menu->setNoReplayFor(q);
+
+ QPoint menuPos = adjustedMenuPosition();
+
+ QPointer<QPushButton> guard(q);
+ QMenuPrivate::get(menu)->causedPopup.widget = guard;
+
+ //Because of a delay in menu effects, we must keep track of the
+ //menu visibility to avoid flicker on button release
+ menuOpen = true;
+ menu->exec(menuPos);
+ if (guard) {
+ menuOpen = false;
+ q->setDown(false);
+ }
+}
+
+QPoint QPushButtonPrivate::adjustedMenuPosition()
+{
+ Q_Q(QPushButton);
+
+ bool horizontal = true;
+#if !defined(QT_NO_TOOLBAR)
+ QToolBar *tb = qobject_cast<QToolBar*>(parent);
+ if (tb && tb->orientation() == Qt::Vertical)
+ horizontal = false;
+#endif
+
+ QWidgetItem item(q);
+ QRect rect = item.geometry();
+ rect.setRect(rect.x() - q->x(), rect.y() - q->y(), rect.width(), rect.height());
+
+ QSize menuSize = menu->sizeHint();
+ QPoint globalPos = q->mapToGlobal(rect.topLeft());
+ int x = globalPos.x();
+ int y = globalPos.y();
+ if (horizontal) {
+ if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->availableGeometry(q).height()) {
+ y += rect.height();
+ } else {
+ y -= menuSize.height();
+ }
+ if (q->layoutDirection() == Qt::RightToLeft)
+ x += rect.width() - menuSize.width();
+ } else {
+ if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->availableGeometry(q).width())
+ x += rect.width();
+ else
+ x -= menuSize.width();
+ }
+
+ return QPoint(x,y);
+}
+
+#endif // QT_NO_MENU
+
+void QPushButtonPrivate::resetLayoutItemMargins()
+{
+ Q_Q(QPushButton);
+ QStyleOptionButton opt;
+ q->initStyleOption(&opt);
+ setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem, &opt);
+}
+
+void QPushButton::setFlat(bool flat)
+{
+ Q_D(QPushButton);
+ if (d->flat == flat)
+ return;
+ d->flat = flat;
+ d->resetLayoutItemMargins();
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+}
+
+bool QPushButton::isFlat() const
+{
+ Q_D(const QPushButton);
+ return d->flat;
+}
+
+/*! \reimp */
+bool QPushButton::event(QEvent *e)
+{
+ Q_D(QPushButton);
+ if (e->type() == QEvent::ParentChange) {
+ if (QDialog *dialog = d->dialogParent()) {
+ if (d->defaultButton)
+ dialog->d_func()->setMainDefault(this);
+ }
+ } else if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ ) {
+ d->resetLayoutItemMargins();
+ updateGeometry();
+ } else if (e->type() == QEvent::PolishRequest) {
+ updateGeometry();
+ }
+ return QAbstractButton::event(e);
+}
+
+#ifdef Q_WS_MAC
+/*! \reimp */
+bool QPushButton::hitButton(const QPoint &pos) const
+{
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ if (qt_mac_buttonIsRenderedFlat(this, &opt))
+ return QAbstractButton::hitButton(pos);
+
+ // Now that we know we are using the native style, let's proceed.
+ Q_D(const QPushButton);
+ QPushButtonPrivate *nonConst = const_cast<QPushButtonPrivate *>(d);
+ // In OSX buttons are round, which causes the hit method to be special.
+ // We cannot simply relay on detecting if something is inside the rect or not,
+ // we need to check if it is inside the "rounded area" or not. A point might
+ // be inside the rect but not inside the rounded area.
+ // Notice this method is only reimplemented for OSX.
+ return nonConst->hitButton(pos);
+}
+
+bool QPushButtonPrivate::hitButton(const QPoint &pos)
+{
+ Q_Q(QPushButton);
+ QRect roundedRect(q->rect().left() + QMacStylePrivate::PushButtonLeftOffset,
+ q->rect().top() + QMacStylePrivate::PushButtonContentPadding,
+ q->rect().width() - QMacStylePrivate::PushButtonRightOffset,
+ q->rect().height() - QMacStylePrivate::PushButtonBottomOffset);
+ return roundedRect.contains(pos);
+}
+#endif // Q_WS_MAC
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QPushButton::QPushButton(QWidget *parent, const char *name)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QPushButton::QPushButton(const QString &text, QWidget *parent, const char *name)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ setObjectName(QString::fromAscii(name));
+ setText(text);
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QPushButton::QPushButton(const QIcon& icon, const QString &text, QWidget *parent, const char *name)
+ : QAbstractButton(*new QPushButtonPrivate, parent)
+{
+ Q_D(QPushButton);
+ setObjectName(QString::fromAscii(name));
+ setText(text);
+ setIcon(icon);
+ d->init();
+}
+#endif
+
+/*!
+ \fn void QPushButton::openPopup()
+
+ Use showMenu() instead.
+*/
+
+/*!
+ \fn bool QPushButton::isMenuButton() const
+
+ Use menu() != 0 instead.
+*/
+
+/*!
+ \fn void QPushButton::setPopup(QMenu* popup)
+
+ Use setMenu() instead.
+*/
+
+/*!
+ \fn QMenu* QPushButton::popup() const
+
+ Use menu() instead.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qpushbutton.cpp"
diff --git a/src/widgets/widgets/qpushbutton.h b/src/widgets/widgets/qpushbutton.h
new file mode 100644
index 0000000000..4f1f85dea4
--- /dev/null
+++ b/src/widgets/widgets/qpushbutton.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPUSHBUTTON_H
+#define QPUSHBUTTON_H
+
+#include <QtWidgets/qabstractbutton.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QPushButtonPrivate;
+class QMenu;
+class QStyleOptionButton;
+
+class Q_WIDGETS_EXPORT QPushButton : public QAbstractButton
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool autoDefault READ autoDefault WRITE setAutoDefault)
+ Q_PROPERTY(bool default READ isDefault WRITE setDefault)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat)
+
+public:
+ explicit QPushButton(QWidget *parent=0);
+ explicit QPushButton(const QString &text, QWidget *parent=0);
+ QPushButton(const QIcon& icon, const QString &text, QWidget *parent=0);
+ ~QPushButton();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ bool autoDefault() const;
+ void setAutoDefault(bool);
+ bool isDefault() const;
+ void setDefault(bool);
+
+#ifndef QT_NO_MENU
+ void setMenu(QMenu* menu);
+ QMenu* menu() const;
+#endif
+
+ void setFlat(bool);
+ bool isFlat() const;
+
+public Q_SLOTS:
+#ifndef QT_NO_MENU
+ void showMenu();
+#endif
+
+protected:
+ bool event(QEvent *e);
+#ifdef Q_WS_MAC
+ bool hitButton(const QPoint &pos) const;
+#endif // Q_WS_MAC
+ void paintEvent(QPaintEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void focusInEvent(QFocusEvent *);
+ void focusOutEvent(QFocusEvent *);
+ void initStyleOption(QStyleOptionButton *option) const;
+ QPushButton(QPushButtonPrivate &dd, QWidget* parent = 0);
+
+public:
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QPushButton(QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QPushButton(const QString &text, QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QPushButton(const QIcon& icon, const QString &text, QWidget *parent, const char* name);
+ inline QT3_SUPPORT void openPopup() { showMenu(); }
+ inline QT3_SUPPORT bool isMenuButton() const { return menu() != 0; }
+ inline QT3_SUPPORT void setPopup(QMenu* popup) {setMenu(popup); }
+ inline QT3_SUPPORT QMenu* popup() const { return menu(); }
+#endif
+
+private:
+ Q_DISABLE_COPY(QPushButton)
+ Q_DECLARE_PRIVATE(QPushButton)
+#ifndef QT_NO_MENU
+ Q_PRIVATE_SLOT(d_func(), void _q_popupPressed())
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPUSHBUTTON_H
diff --git a/src/widgets/widgets/qpushbutton_p.h b/src/widgets/widgets/qpushbutton_p.h
new file mode 100644
index 0000000000..0056288a98
--- /dev/null
+++ b/src/widgets/widgets/qpushbutton_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qabstractbutton_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_NAMESPACE
+
+class QDialog;
+class QPushButton;
+
+class QPushButtonPrivate : public QAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QPushButton)
+public:
+ enum AutoDefaultValue { Off = 0, On = 1, Auto = 2 };
+
+ QPushButtonPrivate()
+ : QAbstractButtonPrivate(QSizePolicy::PushButton), autoDefault(Auto),
+ defaultButton(false), flat(false), menuOpen(false), lastAutoDefault(false) {}
+
+ inline void init() { resetLayoutItemMargins(); }
+ static QPushButtonPrivate* get(QPushButton *b) { return b->d_func(); }
+#ifdef Q_WS_MAC
+ bool hitButton(const QPoint &pos);
+#endif
+#ifndef QT_NO_MENU
+ QPoint adjustedMenuPosition();
+#endif
+ void resetLayoutItemMargins();
+ void _q_popupPressed();
+ QDialog *dialogParent() const;
+
+ QPointer<QMenu> menu;
+ uint autoDefault : 2;
+ uint defaultButton : 1;
+ uint flat : 1;
+ uint menuOpen : 1;
+ mutable uint lastAutoDefault : 1;
+};
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qradiobutton.cpp b/src/widgets/widgets/qradiobutton.cpp
new file mode 100644
index 0000000000..eeef40e00a
--- /dev/null
+++ b/src/widgets/widgets/qradiobutton.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qradiobutton.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qbuttongroup.h"
+#include "qstylepainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qevent.h"
+
+#include "private/qabstractbutton_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRadioButtonPrivate : public QAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QRadioButton)
+
+public:
+ QRadioButtonPrivate() : QAbstractButtonPrivate(QSizePolicy::RadioButton), hovering(true) {}
+ void init();
+ uint hovering : 1;
+};
+
+/*
+ Initializes the radio button.
+*/
+void QRadioButtonPrivate::init()
+{
+ Q_Q(QRadioButton);
+ q->setCheckable(true);
+ q->setAutoExclusive(true);
+ q->setMouseTracking(true);
+ q->setForegroundRole(QPalette::WindowText);
+ setLayoutItemMargins(QStyle::SE_RadioButtonLayoutItem);
+}
+
+/*!
+ \class QRadioButton
+ \brief The QRadioButton widget provides a radio button with a text label.
+
+ \ingroup basicwidgets
+
+
+ A QRadioButton is an option button that can be switched on (checked) or
+ off (unchecked). Radio buttons typically present the user with a "one
+ of many" choice. In a group of radio buttons only one radio button at
+ a time can be checked; if the user selects another button, the
+ previously selected button is switched off.
+
+ Radio buttons are autoExclusive by default. If auto-exclusive is
+ enabled, radio buttons that belong to the same parent widget
+ behave as if they were part of the same exclusive button group. If
+ you need multiple exclusive button groups for radio buttons that
+ belong to the same parent widget, put them into a QButtonGroup.
+
+ Whenever a button is switched on or off it emits the toggled() signal.
+ Connect to this signal if you want to trigger an action each time the
+ button changes state. Use isChecked() to see if a particular button is
+ selected.
+
+ Just like QPushButton, a radio button displays text, and
+ optionally a small icon. The icon is set with setIcon(). The text
+ can be set in the constructor or with setText(). A shortcut key
+ can be specified by preceding the preferred character with an
+ ampersand in the text. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qradiobutton.cpp 0
+
+ In this example the shortcut is \e{Alt+c}. See the \l
+ {QShortcut#mnemonic}{QShortcut} documentation for details (to
+ display an actual ampersand, use '&&').
+
+ Important inherited members: text(), setText(), text(),
+ setDown(), isDown(), autoRepeat(), group(), setAutoRepeat(),
+ toggle(), pressed(), released(), clicked(), and toggled().
+
+ \table 100%
+ \row \o \inlineimage plastique-radiobutton.png Screenshot of a Plastique radio button
+ \o A radio button shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \row \o \inlineimage windows-radiobutton.png Screenshot of a Windows XP radio button
+ \o A radio button shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage macintosh-radiobutton.png Screenshot of a Macintosh radio button
+ \o A radio button shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \endtable
+
+ \sa QPushButton, QToolButton, QCheckBox, {fowler}{GUI Design Handbook: Radio Button},
+ {Group Box Example}
+*/
+
+
+/*!
+ Constructs a radio button with the given \a parent, but with no text or
+ pixmap.
+
+ The \a parent argument is passed on to the QAbstractButton constructor.
+*/
+
+QRadioButton::QRadioButton(QWidget *parent)
+ : QAbstractButton(*new QRadioButtonPrivate, parent)
+{
+ Q_D(QRadioButton);
+ d->init();
+}
+
+/*!
+ Constructs a radio button with the given \a parent and a \a text string.
+
+ The \a parent argument is passed on to the QAbstractButton constructor.
+*/
+
+QRadioButton::QRadioButton(const QString &text, QWidget *parent)
+ : QAbstractButton(*new QRadioButtonPrivate, parent)
+{
+ Q_D(QRadioButton);
+ d->init();
+ setText(text);
+}
+
+/*!
+ Initialize \a option with the values from this QRadioButton. This method is useful
+ for subclasses when they need a QStyleOptionButton, but don't want to fill
+ in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QRadioButton::initStyleOption(QStyleOptionButton *option) const
+{
+ if (!option)
+ return;
+ Q_D(const QRadioButton);
+ option->initFrom(this);
+ option->text = d->text;
+ option->icon = d->icon;
+ option->iconSize = iconSize();
+ if (d->down)
+ option->state |= QStyle::State_Sunken;
+ option->state |= (d->checked) ? QStyle::State_On : QStyle::State_Off;
+ if (testAttribute(Qt::WA_Hover) && underMouse()) {
+ if (d->hovering)
+ option->state |= QStyle::State_MouseOver;
+ else
+ option->state &= ~QStyle::State_MouseOver;
+ }
+}
+
+/*!
+ \reimp
+*/
+QSize QRadioButton::sizeHint() const
+{
+ Q_D(const QRadioButton);
+ if (d->sizeHint.isValid())
+ return d->sizeHint;
+ ensurePolished();
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ QSize sz = style()->itemTextRect(fontMetrics(), QRect(), Qt::TextShowMnemonic,
+ false, text()).size();
+ if (!opt.icon.isNull())
+ sz = QSize(sz.width() + opt.iconSize.width() + 4, qMax(sz.height(), opt.iconSize.height()));
+ d->sizeHint = (style()->sizeFromContents(QStyle::CT_RadioButton, &opt, sz, this).
+ expandedTo(QApplication::globalStrut()));
+ return d->sizeHint;
+}
+
+/*!
+ \reimp
+*/
+QSize QRadioButton::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \reimp
+*/
+bool QRadioButton::hitButton(const QPoint &pos) const
+{
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ return style()->subElementRect(QStyle::SE_RadioButtonClickRect, &opt, this).contains(pos);
+}
+
+/*!
+ \reimp
+*/
+void QRadioButton::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QRadioButton);
+ if (testAttribute(Qt::WA_Hover)) {
+ bool hit = false;
+ if (underMouse())
+ hit = hitButton(e->pos());
+
+ if (hit != d->hovering) {
+ update();
+ d->hovering = hit;
+ }
+ }
+
+ QAbstractButton::mouseMoveEvent(e);
+}
+
+/*!\reimp
+ */
+void QRadioButton::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ p.drawControl(QStyle::CE_RadioButton, opt);
+}
+
+/*! \reimp */
+bool QRadioButton::event(QEvent *e)
+{
+ Q_D(QRadioButton);
+ if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->setLayoutItemMargins(QStyle::SE_RadioButtonLayoutItem);
+ return QAbstractButton::event(e);
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QRadioButton::QRadioButton(QWidget *parent, const char* name)
+ : QAbstractButton(*new QRadioButtonPrivate, parent)
+{
+ Q_D(QRadioButton);
+ d->init();
+ setObjectName(QString::fromAscii(name));
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QRadioButton::QRadioButton(const QString &text, QWidget *parent, const char* name)
+ : QAbstractButton(*new QRadioButtonPrivate, parent)
+{
+ Q_D(QRadioButton);
+ d->init();
+ setObjectName(QString::fromAscii(name));
+ setText(text);
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qradiobutton.h b/src/widgets/widgets/qradiobutton.h
new file mode 100644
index 0000000000..e3837253c8
--- /dev/null
+++ b/src/widgets/widgets/qradiobutton.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRADIOBUTTON_H
+#define QRADIOBUTTON_H
+
+#include <QtWidgets/qabstractbutton.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QRadioButtonPrivate;
+class QStyleOptionButton;
+
+class Q_WIDGETS_EXPORT QRadioButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ explicit QRadioButton(QWidget *parent=0);
+ explicit QRadioButton(const QString &text, QWidget *parent=0);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+protected:
+ bool event(QEvent *e);
+ bool hitButton(const QPoint &) const;
+ void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void initStyleOption(QStyleOptionButton *button) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QRadioButton(QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QRadioButton(const QString &text, QWidget *parent, const char* name);
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QRadioButton)
+ Q_DISABLE_COPY(QRadioButton)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QRADIOBUTTON_H
diff --git a/src/widgets/widgets/qrubberband.cpp b/src/widgets/widgets/qrubberband.cpp
new file mode 100644
index 0000000000..e288835609
--- /dev/null
+++ b/src/widgets/widgets/qrubberband.cpp
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbitmap.h"
+#include "qevent.h"
+#include "qstylepainter.h"
+#include "qrubberband.h"
+#include "qtimer.h"
+
+#ifndef QT_NO_RUBBERBAND
+
+#include "qstyle.h"
+#include "qstyleoption.h"
+#ifdef Q_WS_MAC
+# include <private/qt_mac_p.h>
+# include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#include <qdebug.h>
+
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//### a rubberband window type would be a more elegant solution
+#define RUBBERBAND_WINDOW_TYPE Qt::ToolTip
+
+class QRubberBandPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QRubberBand)
+public:
+ QRect rect;
+ QRubberBand::Shape shape;
+ QRegion clipping;
+ void updateMask();
+};
+
+/*!
+ Initialize \a option with the values from this QRubberBand. This method
+ is useful for subclasses when they need a QStyleOptionRubberBand, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QRubberBand::initStyleOption(QStyleOptionRubberBand *option) const
+{
+ if (!option)
+ return;
+ option->initFrom(this);
+ option->shape = d_func()->shape;
+#ifndef Q_WS_MAC
+ option->opaque = true;
+#else
+ option->opaque = windowFlags() & RUBBERBAND_WINDOW_TYPE;
+#endif
+}
+
+/*!
+ \class QRubberBand
+ \brief The QRubberBand class provides a rectangle or line that can
+ indicate a selection or a boundary.
+
+ A rubber band is often used to show a new bounding area (as in a
+ QSplitter or a QDockWidget that is undocking). Historically this has
+ been implemented using a QPainter and XOR, but this approach
+ doesn't always work properly since rendering can happen in the
+ window below the rubber band, but before the rubber band has been
+ "erased".
+
+ You can create a QRubberBand whenever you need to render a rubber band
+ around a given area (or to represent a single line), then call
+ setGeometry(), move() or resize() to position and size it. A common
+ pattern is to do this in conjunction with mouse events. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qrubberband.cpp 0
+
+ If you pass a parent to QRubberBand's constructor, the rubber band will
+ display only inside its parent, but stays on top of other child widgets.
+ If no parent is passed, QRubberBand will act as a top-level widget.
+
+ Call show() to make the rubber band visible; also when the
+ rubber band is not a top-level. Hiding or destroying
+ the widget will make the rubber band disappear. The rubber band
+ can be a \l Rectangle or a \l Line (vertical or horizontal),
+ depending on the shape() it was given when constructed.
+*/
+
+// ### DOC: How about some nice convenience constructors?
+//QRubberBand::QRubberBand(QRubberBand::Type t, const QRect &rect, QWidget *p)
+//QRubberBand::QRubberBand(QRubberBand::Type t, int x, int y, int w, int h, QWidget *p)
+
+/*!
+ Constructs a rubber band of shape \a s, with parent \a p.
+
+ By default a rectangular rubber band (\a s is \c Rectangle) will
+ use a mask, so that a small border of the rectangle is all
+ that is visible. Some styles (e.g., native Mac OS X) will
+ change this and call QWidget::setWindowOpacity() to make a
+ semi-transparent filled selection rectangle.
+*/
+QRubberBand::QRubberBand(Shape s, QWidget *p)
+ : QWidget(*new QRubberBandPrivate, p, (p && p->windowType() != Qt::Desktop) ? Qt::Widget : RUBBERBAND_WINDOW_TYPE)
+{
+ Q_D(QRubberBand);
+ d->shape = s;
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+#ifndef Q_WS_WIN
+ setAttribute(Qt::WA_NoSystemBackground);
+#endif //Q_WS_WIN
+ setAttribute(Qt::WA_WState_ExplicitShowHide);
+ setVisible(false);
+#ifdef Q_WS_MAC
+ if (isWindow()) {
+ createWinId();
+ extern OSWindowRef qt_mac_window_for(const QWidget *); //qwidget_mac.cpp
+ macWindowSetHasShadow(qt_mac_window_for(this), false);
+ }
+#endif
+}
+
+/*!
+ Destructor.
+*/
+QRubberBand::~QRubberBand()
+{
+}
+
+/*!
+ \enum QRubberBand::Shape
+
+ This enum specifies what shape a QRubberBand should have. This is
+ a drawing hint that is passed down to the style system, and can be
+ interpreted by each QStyle.
+
+ \value Line A QRubberBand can represent a vertical or horizontal
+ line. Geometry is still given in rect() and the line
+ will fill the given geometry on most styles.
+
+ \value Rectangle A QRubberBand can represent a rectangle. Some
+ styles will interpret this as a filled (often
+ semi-transparent) rectangle, or a rectangular
+ outline.
+*/
+
+/*!
+ Returns the shape of this rubber band. The shape can only be set
+ upon construction.
+*/
+QRubberBand::Shape QRubberBand::shape() const
+{
+ Q_D(const QRubberBand);
+ return d->shape;
+}
+
+/*!
+ \internal
+*/
+void QRubberBandPrivate::updateMask()
+{
+ Q_Q(QRubberBand);
+ QStyleHintReturnMask mask;
+ QStyleOptionRubberBand opt;
+ q->initStyleOption(&opt);
+ if (q->style()->styleHint(QStyle::SH_RubberBand_Mask, &opt, q, &mask)) {
+ q->setMask(mask.region);
+ } else {
+ q->clearMask();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QRubberBand::paintEvent(QPaintEvent *)
+{
+ QStylePainter painter(this);
+ QStyleOptionRubberBand option;
+ initStyleOption(&option);
+ painter.drawControl(QStyle::CE_RubberBand, option);
+}
+
+/*!
+ \reimp
+*/
+void QRubberBand::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::ParentChange:
+ if (parent()) {
+ setWindowFlags(windowFlags() & ~RUBBERBAND_WINDOW_TYPE);
+ } else {
+ setWindowFlags(windowFlags() | RUBBERBAND_WINDOW_TYPE);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (e->type() == QEvent::ZOrderChange)
+ raise();
+}
+
+/*!
+ \reimp
+*/
+void QRubberBand::showEvent(QShowEvent *e)
+{
+ raise();
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QRubberBand::resizeEvent(QResizeEvent *)
+{
+ Q_D(QRubberBand);
+ d->updateMask();
+}
+
+/*!
+ \reimp
+*/
+void QRubberBand::moveEvent(QMoveEvent *)
+{
+ Q_D(QRubberBand);
+ d->updateMask();
+}
+
+/*!
+ \fn void QRubberBand::move(const QPoint &p);
+
+ \overload
+
+ Moves the rubberband to point \a p.
+
+ \sa resize()
+*/
+
+/*!
+ \fn void QRubberBand::move(int x, int y);
+
+ Moves the rubberband to point (\a x, \a y).
+
+ \sa resize()
+*/
+
+/*!
+ \fn void QRubberBand::resize(const QSize &size);
+
+ \overload
+
+ Resizes the rubberband so that its new size is \a size.
+
+ \sa move()
+*/
+
+/*!
+ \fn void QRubberBand::resize(int width, int height);
+
+ Resizes the rubberband so that its width is \a width, and its
+ height is \a height.
+
+ \sa move()
+*/
+
+/*!
+ \fn void QRubberBand::setGeometry(const QRect &rect)
+
+ Sets the geometry of the rubber band to \a rect, specified in the coordinate system
+ of its parent widget.
+
+ \sa QWidget::geometry
+*/
+void QRubberBand::setGeometry(const QRect &geom)
+{
+ QWidget::setGeometry(geom);
+}
+
+/*!
+ \fn void QRubberBand::setGeometry(int x, int y, int width, int height)
+ \overload
+
+ Sets the geometry of the rubberband to the rectangle whose top-left corner lies at
+ the point (\a x, \a y), and with dimensions specified by \a width and \a height.
+ The geometry is specified in the parent widget's coordinate system.
+*/
+
+/*! \reimp */
+bool QRubberBand::event(QEvent *e)
+{
+ return QWidget::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RUBBERBAND
diff --git a/src/widgets/widgets/qrubberband.h b/src/widgets/widgets/qrubberband.h
new file mode 100644
index 0000000000..3d30004770
--- /dev/null
+++ b/src/widgets/widgets/qrubberband.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRUBBERBAND_H
+#define QRUBBERBAND_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_RUBBERBAND
+
+class QRubberBandPrivate;
+class QStyleOptionRubberBand;
+
+class Q_WIDGETS_EXPORT QRubberBand : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum Shape { Line, Rectangle };
+ explicit QRubberBand(Shape, QWidget * =0);
+ ~QRubberBand();
+
+ Shape shape() const;
+
+ void setGeometry(const QRect &r);
+
+ inline void setGeometry(int x, int y, int w, int h);
+ inline void move(int x, int y);
+ inline void move(const QPoint &p)
+ { move(p.x(), p.y()); }
+ inline void resize(int w, int h)
+ { setGeometry(geometry().x(), geometry().y(), w, h); }
+ inline void resize(const QSize &s)
+ { resize(s.width(), s.height()); }
+
+protected:
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *);
+ void changeEvent(QEvent *);
+ void showEvent(QShowEvent *);
+ void resizeEvent(QResizeEvent *);
+ void moveEvent(QMoveEvent *);
+ void initStyleOption(QStyleOptionRubberBand *option) const;
+
+private:
+ Q_DECLARE_PRIVATE(QRubberBand)
+};
+
+inline void QRubberBand::setGeometry(int ax, int ay, int aw, int ah)
+{ setGeometry(QRect(ax, ay, aw, ah)); }
+inline void QRubberBand::move(int ax, int ay)
+{ setGeometry(ax, ay, width(), height()); }
+
+#endif // QT_NO_RUBBERBAND
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QRUBBERBAND_H
diff --git a/src/widgets/widgets/qscrollarea.cpp b/src/widgets/widgets/qscrollarea.cpp
new file mode 100644
index 0000000000..5d03c07472
--- /dev/null
+++ b/src/widgets/widgets/qscrollarea.cpp
@@ -0,0 +1,522 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscrollarea.h"
+#include "private/qscrollarea_p.h"
+
+#ifndef QT_NO_SCROLLAREA
+
+#include "qscrollbar.h"
+#include "qlayout.h"
+#include "qstyle.h"
+#include "qapplication.h"
+#include "qvariant.h"
+#include "qdebug.h"
+#include "private/qlayoutengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QScrollArea
+
+ \brief The QScrollArea class provides a scrolling view onto
+ another widget.
+
+ \ingroup basicwidgets
+
+
+ A scroll area is used to display the contents of a child widget
+ within a frame. If the widget exceeds the size of the frame, the
+ view can provide scroll bars so that the entire area of the child
+ widget can be viewed. The child widget must be specified with
+ setWidget(). For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qscrollarea.cpp 0
+
+ The code above creates a scroll area (shown in the images below)
+ containing an image label. When scaling the image, the scroll area
+ can provide the necessary scroll bars:
+
+ \table
+ \row
+ \o \inlineimage qscrollarea-noscrollbars.png
+ \o \inlineimage qscrollarea-onescrollbar.png
+ \o \inlineimage qscrollarea-twoscrollbars.png
+ \endtable
+
+ The scroll bars appearance depends on the currently set \l
+ {Qt::ScrollBarPolicy}{scroll bar policies}. You can control the
+ appearance of the scroll bars using the inherited functionality
+ from QAbstractScrollArea.
+
+ For example, you can set the
+ QAbstractScrollArea::horizontalScrollBarPolicy and
+ QAbstractScrollArea::verticalScrollBarPolicy properties. Or if you
+ want the scroll bars to adjust dynamically when the contents of
+ the scroll area changes, you can use the \l
+ {QAbstractScrollArea::horizontalScrollBar()}{horizontalScrollBar()}
+ and \l
+ {QAbstractScrollArea::verticalScrollBar()}{verticalScrollBar()}
+ functions (which enable you to access the scroll bars) and set the
+ scroll bars' values whenever the scroll area's contents change,
+ using the QScrollBar::setValue() function.
+
+ You can retrieve the child widget using the widget() function. The
+ view can be made to be resizable with the setWidgetResizable()
+ function. The alignment of the widget can be specified with
+ setAlignment().
+
+ Two convenience functions ensureVisible() and
+ ensureWidgetVisible() ensure a certain region of the contents is
+ visible inside the viewport, by scrolling the contents if
+ necessary.
+
+ \section1 Size Hints and Layouts
+
+ When using a scroll area to display the contents of a custom
+ widget, it is important to ensure that the
+ \l{QWidget::sizeHint}{size hint} of the child widget is set to a
+ suitable value. If a standard QWidget is used for the child
+ widget, it may be necessary to call QWidget::setMinimumSize() to
+ ensure that the contents of the widget are shown correctly within
+ the scroll area.
+
+ If a scroll area is used to display the contents of a widget that
+ contains child widgets arranged in a layout, it is important to
+ realize that the size policy of the layout will also determine the
+ size of the widget. This is especially useful to know if you intend
+ to dynamically change the contents of the layout. In such cases,
+ setting the layout's \l{QLayout::sizeConstraint}{size constraint}
+ property to one which provides constraints on the minimum and/or
+ maximum size of the layout (e.g., QLayout::SetMinAndMaxSize) will
+ cause the size of the scroll area to be updated whenever the
+ contents of the layout changes.
+
+ For a complete example using the QScrollArea class, see the \l
+ {widgets/imageviewer}{Image Viewer} example. The example shows how
+ to combine QLabel and QScrollArea to display an image.
+
+ \sa QAbstractScrollArea, QScrollBar, {Image Viewer Example}
+*/
+
+
+/*!
+ Constructs an empty scroll area with the given \a parent.
+
+ \sa setWidget()
+*/
+QScrollArea::QScrollArea(QWidget *parent)
+ : QAbstractScrollArea(*new QScrollAreaPrivate,parent)
+{
+ Q_D(QScrollArea);
+ d->viewport->setBackgroundRole(QPalette::NoRole);
+ d->vbar->setSingleStep(20);
+ d->hbar->setSingleStep(20);
+ d->layoutChildren();
+}
+
+/*!
+ \internal
+*/
+QScrollArea::QScrollArea(QScrollAreaPrivate &dd, QWidget *parent)
+ : QAbstractScrollArea(dd, parent)
+{
+ Q_D(QScrollArea);
+ d->viewport->setBackgroundRole(QPalette::NoRole);
+ d->vbar->setSingleStep(20);
+ d->hbar->setSingleStep(20);
+ d->layoutChildren();
+}
+
+/*!
+ Destroys the scroll area and its child widget.
+
+ \sa setWidget()
+*/
+QScrollArea::~QScrollArea()
+{
+}
+
+void QScrollAreaPrivate::updateWidgetPosition()
+{
+ Q_Q(QScrollArea);
+ Qt::LayoutDirection dir = q->layoutDirection();
+ QRect scrolled = QStyle::visualRect(dir, viewport->rect(), QRect(QPoint(-hbar->value(), -vbar->value()), widget->size()));
+ QRect aligned = QStyle::alignedRect(dir, alignment, widget->size(), viewport->rect());
+ widget->move(widget->width() < viewport->width() ? aligned.x() : scrolled.x(),
+ widget->height() < viewport->height() ? aligned.y() : scrolled.y());
+}
+
+void QScrollAreaPrivate::updateScrollBars()
+{
+ Q_Q(QScrollArea);
+ if (!widget)
+ return;
+ QSize p = viewport->size();
+ QSize m = q->maximumViewportSize();
+
+ QSize min = qSmartMinSize(widget);
+ QSize max = qSmartMaxSize(widget);
+
+ if (resizable) {
+ if ((widget->layout() ? widget->layout()->hasHeightForWidth() : widget->sizePolicy().hasHeightForWidth())) {
+ QSize p_hfw = p.expandedTo(min).boundedTo(max);
+ int h = widget->heightForWidth( p_hfw.width() );
+ min = QSize(p_hfw.width(), qMax(p_hfw.height(), h));
+ }
+ }
+
+ if ((resizable && m.expandedTo(min) == m && m.boundedTo(max) == m)
+ || (!resizable && m.expandedTo(widget->size()) == m))
+ p = m; // no scroll bars needed
+
+ if (resizable)
+ widget->resize(p.expandedTo(min).boundedTo(max));
+ QSize v = widget->size();
+
+ hbar->setRange(0, v.width() - p.width());
+ hbar->setPageStep(p.width());
+ vbar->setRange(0, v.height() - p.height());
+ vbar->setPageStep(p.height());
+ updateWidgetPosition();
+
+}
+
+/*!
+ Returns the scroll area's widget, or 0 if there is none.
+
+ \sa setWidget()
+*/
+
+QWidget *QScrollArea::widget() const
+{
+ Q_D(const QScrollArea);
+ return d->widget;
+}
+
+/*!
+ \fn void QScrollArea::setWidget(QWidget *widget)
+
+ Sets the scroll area's \a widget.
+
+ The \a widget becomes a child of the scroll area, and will be
+ destroyed when the scroll area is deleted or when a new widget is
+ set.
+
+ The widget's \l{QWidget::setAutoFillBackground()}{autoFillBackground}
+ property will be set to \c{true}.
+
+ If the scroll area is visible when the \a widget is
+ added, you must \l{QWidget::}{show()} it explicitly.
+
+ Note that You must add the layout of \a widget before you call
+ this function; if you add it later, the \a widget will not be
+ visible - regardless of when you \l{QWidget::}{show()} the scroll
+ area. In this case, you can also not \l{QWidget::}{show()} the \a
+ widget later.
+
+ \sa widget()
+*/
+void QScrollArea::setWidget(QWidget *widget)
+{
+ Q_D(QScrollArea);
+ if (widget == d->widget || !widget)
+ return;
+
+ delete d->widget;
+ d->widget = 0;
+ d->hbar->setValue(0);
+ d->vbar->setValue(0);
+ if (widget->parentWidget() != d->viewport)
+ widget->setParent(d->viewport);
+ if (!widget->testAttribute(Qt::WA_Resized))
+ widget->resize(widget->sizeHint());
+ d->widget = widget;
+ d->widget->setAutoFillBackground(true);
+ widget->installEventFilter(this);
+ d->widgetSize = QSize();
+ d->updateScrollBars();
+ d->widget->show();
+
+}
+
+/*!
+ Removes the scroll area's widget, and passes ownership of the
+ widget to the caller.
+
+ \sa widget()
+ */
+QWidget *QScrollArea::takeWidget()
+{
+ Q_D(QScrollArea);
+ QWidget *w = d->widget;
+ d->widget = 0;
+ if (w)
+ w->setParent(0);
+ return w;
+}
+
+/*!
+ \reimp
+ */
+bool QScrollArea::event(QEvent *e)
+{
+ Q_D(QScrollArea);
+ if (e->type() == QEvent::StyleChange || e->type() == QEvent::LayoutRequest) {
+ d->updateScrollBars();
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ else if (QApplication::keypadNavigationEnabled()) {
+ if (e->type() == QEvent::Show)
+ QApplication::instance()->installEventFilter(this);
+ else if (e->type() == QEvent::Hide)
+ QApplication::instance()->removeEventFilter(this);
+ }
+#endif
+ return QAbstractScrollArea::event(e);
+}
+
+
+/*!
+ \reimp
+ */
+bool QScrollArea::eventFilter(QObject *o, QEvent *e)
+{
+ Q_D(QScrollArea);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (d->widget && o != d->widget && e->type() == QEvent::FocusIn
+ && QApplication::keypadNavigationEnabled()) {
+ if (o->isWidgetType())
+ ensureWidgetVisible(static_cast<QWidget *>(o));
+ }
+#endif
+ if (o == d->widget && e->type() == QEvent::Resize)
+ d->updateScrollBars();
+
+ return false;
+}
+
+/*!
+ \reimp
+ */
+void QScrollArea::resizeEvent(QResizeEvent *)
+{
+ Q_D(QScrollArea);
+ d->updateScrollBars();
+
+}
+
+
+/*!\reimp
+ */
+void QScrollArea::scrollContentsBy(int, int)
+{
+ Q_D(QScrollArea);
+ if (!d->widget)
+ return;
+ d->updateWidgetPosition();
+}
+
+
+/*!
+ \property QScrollArea::widgetResizable
+ \brief whether the scroll area should resize the view widget
+
+ If this property is set to false (the default), the scroll area
+ honors the size of its widget. Regardless of this property, you
+ can programmatically resize the widget using widget()->resize(),
+ and the scroll area will automatically adjust itself to the new
+ size.
+
+ If this property is set to true, the scroll area will
+ automatically resize the widget in order to avoid scroll bars
+ where they can be avoided, or to take advantage of extra space.
+*/
+bool QScrollArea::widgetResizable() const
+{
+ Q_D(const QScrollArea);
+ return d->resizable;
+}
+
+void QScrollArea::setWidgetResizable(bool resizable)
+{
+ Q_D(QScrollArea);
+ d->resizable = resizable;
+ updateGeometry();
+ d->updateScrollBars();
+}
+
+/*!
+ \reimp
+ */
+QSize QScrollArea::sizeHint() const
+{
+ Q_D(const QScrollArea);
+ int f = 2 * d->frameWidth;
+ QSize sz(f, f);
+ int h = fontMetrics().height();
+ if (d->widget) {
+ if (!d->widgetSize.isValid())
+ d->widgetSize = d->resizable ? d->widget->sizeHint() : d->widget->size();
+ sz += d->widgetSize;
+ } else {
+ sz += QSize(12 * h, 8 * h);
+ }
+ if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
+ sz.setWidth(sz.width() + d->vbar->sizeHint().width());
+ if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
+ sz.setHeight(sz.height() + d->hbar->sizeHint().height());
+ return sz.boundedTo(QSize(36 * h, 24 * h));
+}
+
+
+
+/*!
+ \reimp
+ */
+bool QScrollArea::focusNextPrevChild(bool next)
+{
+ if (QWidget::focusNextPrevChild(next)) {
+ if (QWidget *fw = focusWidget())
+ ensureWidgetVisible(fw);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Scrolls the contents of the scroll area so that the point (\a x, \a y) is visible
+ inside the region of the viewport with margins specified in pixels by \a xmargin and
+ \a ymargin. If the specified point cannot be reached, the contents are scrolled to
+ the nearest valid position. The default value for both margins is 50 pixels.
+*/
+void QScrollArea::ensureVisible(int x, int y, int xmargin, int ymargin)
+{
+ Q_D(QScrollArea);
+
+ int logicalX = QStyle::visualPos(layoutDirection(), d->viewport->rect(), QPoint(x, y)).x();
+
+ if (logicalX - xmargin < d->hbar->value()) {
+ d->hbar->setValue(qMax(0, logicalX - xmargin));
+ } else if (logicalX > d->hbar->value() + d->viewport->width() - xmargin) {
+ d->hbar->setValue(qMin(logicalX - d->viewport->width() + xmargin, d->hbar->maximum()));
+ }
+
+ if (y - ymargin < d->vbar->value()) {
+ d->vbar->setValue(qMax(0, y - ymargin));
+ } else if (y > d->vbar->value() + d->viewport->height() - ymargin) {
+ d->vbar->setValue(qMin(y - d->viewport->height() + ymargin, d->vbar->maximum()));
+ }
+}
+
+/*!
+ \since 4.2
+
+ Scrolls the contents of the scroll area so that the \a childWidget
+ of QScrollArea::widget() is visible inside the viewport with
+ margins specified in pixels by \a xmargin and \a ymargin. If the
+ specified point cannot be reached, the contents are scrolled to
+ the nearest valid position. The default value for both margins is
+ 50 pixels.
+
+*/
+void QScrollArea::ensureWidgetVisible(QWidget *childWidget, int xmargin, int ymargin)
+{
+ Q_D(QScrollArea);
+
+ if (!d->widget->isAncestorOf(childWidget))
+ return;
+
+ const QRect microFocus = childWidget->inputMethodQuery(Qt::ImCursorRectangle).toRect();
+ const QRect defaultMicroFocus =
+ childWidget->QWidget::inputMethodQuery(Qt::ImCursorRectangle).toRect();
+ QRect focusRect = (microFocus != defaultMicroFocus)
+ ? QRect(childWidget->mapTo(d->widget, microFocus.topLeft()), microFocus.size())
+ : QRect(childWidget->mapTo(d->widget, QPoint(0,0)), childWidget->size());
+ const QRect visibleRect(-d->widget->pos(), d->viewport->size());
+
+ if (visibleRect.contains(focusRect))
+ return;
+
+ focusRect.adjust(-xmargin, -ymargin, xmargin, ymargin);
+
+ if (focusRect.width() > visibleRect.width())
+ d->hbar->setValue(focusRect.center().x() - d->viewport->width() / 2);
+ else if (focusRect.right() > visibleRect.right())
+ d->hbar->setValue(focusRect.right() - d->viewport->width());
+ else if (focusRect.left() < visibleRect.left())
+ d->hbar->setValue(focusRect.left());
+
+ if (focusRect.height() > visibleRect.height())
+ d->vbar->setValue(focusRect.center().y() - d->viewport->height() / 2);
+ else if (focusRect.bottom() > visibleRect.bottom())
+ d->vbar->setValue(focusRect.bottom() - d->viewport->height());
+ else if (focusRect.top() < visibleRect.top())
+ d->vbar->setValue(focusRect.top());
+}
+
+
+/*!
+ \property QScrollArea::alignment
+ \brief the alignment of the scroll area's widget
+ \since 4.2
+
+ By default, the widget stays rooted to the top-left corner of the
+ scroll area.
+*/
+
+void QScrollArea::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QScrollArea);
+ d->alignment = alignment;
+ if (d->widget)
+ d->updateWidgetPosition();
+}
+
+Qt::Alignment QScrollArea::alignment() const
+{
+ Q_D(const QScrollArea);
+ return d->alignment;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCROLLAREA
diff --git a/src/widgets/widgets/qscrollarea.h b/src/widgets/widgets/qscrollarea.h
new file mode 100644
index 0000000000..2d62cc1bc4
--- /dev/null
+++ b/src/widgets/widgets/qscrollarea.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCROLLAREA_H
+#define QSCROLLAREA_H
+
+#include <QtWidgets/qabstractscrollarea.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SCROLLAREA
+
+class QScrollAreaPrivate;
+
+class Q_WIDGETS_EXPORT QScrollArea : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_PROPERTY(bool widgetResizable READ widgetResizable WRITE setWidgetResizable)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
+
+public:
+ explicit QScrollArea(QWidget* parent=0);
+ ~QScrollArea();
+
+ QWidget *widget() const;
+ void setWidget(QWidget *widget);
+ QWidget *takeWidget();
+
+ bool widgetResizable() const;
+ void setWidgetResizable(bool resizable);
+
+ QSize sizeHint() const;
+ bool focusNextPrevChild(bool next);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment);
+
+ void ensureVisible(int x, int y, int xmargin = 50, int ymargin = 50);
+ void ensureWidgetVisible(QWidget *childWidget, int xmargin = 50, int ymargin = 50);
+
+protected:
+ QScrollArea(QScrollAreaPrivate &dd, QWidget *parent = 0);
+ bool event(QEvent *);
+ bool eventFilter(QObject *, QEvent *);
+ void resizeEvent(QResizeEvent *);
+ void scrollContentsBy(int dx, int dy);
+
+private:
+ Q_DECLARE_PRIVATE(QScrollArea)
+ Q_DISABLE_COPY(QScrollArea)
+};
+
+#endif // QT_NO_SCROLLAREA
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSCROLLAREA_H
diff --git a/src/widgets/widgets/qscrollarea_p.h b/src/widgets/widgets/qscrollarea_p.h
new file mode 100644
index 0000000000..0e5e21b7c0
--- /dev/null
+++ b/src/widgets/widgets/qscrollarea_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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCROLLAREA_P_H
+#define QSCROLLAREA_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.
+//
+
+#ifndef QT_NO_SCROLLAREA
+
+#include "private/qabstractscrollarea_p.h"
+#include <QtWidgets/qscrollbar.h>
+
+QT_BEGIN_NAMESPACE
+
+class QScrollAreaPrivate: public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QScrollArea)
+
+public:
+ QScrollAreaPrivate(): resizable(false), alignment(0){}
+ void updateScrollBars();
+ void updateWidgetPosition();
+ QPointer<QWidget> widget;
+ mutable QSize widgetSize;
+ bool resizable;
+ Qt::Alignment alignment;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/widgets/qscrollbar.cpp b/src/widgets/widgets/qscrollbar.cpp
new file mode 100644
index 0000000000..534ff6e619
--- /dev/null
+++ b/src/widgets/widgets/qscrollbar.cpp
@@ -0,0 +1,764 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+#include "qcursor.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qscrollbar.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qmenu.h"
+#include <QtCore/qelapsedtimer.h>
+
+#ifndef QT_NO_SCROLLBAR
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include <limits.h>
+#include "qabstractslider_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QScrollBar
+ \brief The QScrollBar widget provides a vertical or horizontal scroll bar.
+
+ \ingroup basicwidgets
+
+ A scroll bar is a control that enables the user to access parts of a
+ document that is larger than the widget used to display it. It provides
+ a visual indication of the user's current position within the document
+ and the amount of the document that is visible. Scroll bars are usually
+ equipped with other controls that enable more accurate navigation.
+ Qt displays scroll bars in a way that is appropriate for each platform.
+
+ If you need to provide a scrolling view onto another widget, it may be
+ more convenient to use the QScrollArea class because this provides a
+ viewport widget and scroll bars. QScrollBar is useful if you need to
+ implement similar functionality for specialized widgets using QAbstractScrollArea;
+ for example, if you decide to subclass QAbstractItemView.
+ For most other situations where a slider control is used to obtain a value
+ within a given range, the QSlider class may be more appropriate for your
+ needs.
+
+ \table
+ \row \o \image qscrollbar-picture.png
+ \o Scroll bars typically include four separate controls: a slider,
+ scroll arrows, and a page control.
+
+ \list
+ \o a. The slider provides a way to quickly go to any part of the
+ document, but does not support accurate navigation within large
+ documents.
+ \o b. The scroll arrows are push buttons which can be used to accurately
+ navigate to a particular place in a document. For a vertical scroll bar
+ connected to a text editor, these typically move the current position one
+ "line" up or down, and adjust the position of the slider by a small
+ amount. In editors and list boxes a "line" might mean one line of text;
+ in an image viewer it might mean 20 pixels.
+ \o c. The page control is the area over which the slider is dragged (the
+ scroll bar's background). Clicking here moves the scroll bar towards
+ the click by one "page". This value is usually the same as the length of
+ the slider.
+ \endlist
+ \endtable
+
+ Each scroll bar has a value that indicates how far the slider is from
+ the start of the scroll bar; this is obtained with value() and set
+ with setValue(). This value always lies within the range of values
+ defined for the scroll bar, from \l{QAbstractSlider::minimum()}{minimum()}
+ to \l{QAbstractSlider::minimum()}{maximum()} inclusive. The range of
+ acceptable values can be set with setMinimum() and setMaximum().
+ At the minimum value, the top edge of the slider (for a vertical scroll
+ bar) or left edge (for a horizontal scroll bar) will be at the top (or
+ left) end of the scroll bar. At the maximum value, the bottom (or right)
+ edge of the slider will be at the bottom (or right) end of the scroll bar.
+
+ The length of the slider is usually related to the value of the page step,
+ and typically represents the proportion of the document area shown in a
+ scrolling view. The page step is the amount that the value changes by
+ when the user presses the \key{Page Up} and \key{Page Down} keys, and is
+ set with setPageStep(). Smaller changes to the value defined by the
+ line step are made using the cursor keys, and this quantity is set with
+ \l{QAbstractSlider::}{setSingleStep()}.
+
+ Note that the range of values used is independent of the actual size
+ of the scroll bar widget. You do not need to take this into account when
+ you choose values for the range and the page step.
+
+ The range of values specified for the scroll bar are often determined
+ differently to those for a QSlider because the length of the slider
+ needs to be taken into account. If we have a document with 100 lines,
+ and we can only show 20 lines in a widget, we may wish to construct a
+ scroll bar with a page step of 20, a minimum value of 0, and a maximum
+ value of 80. This would give us a scroll bar with five "pages".
+
+ \table
+ \row \o \inlineimage qscrollbar-values.png
+ \o The relationship between a document length, the range of values used
+ in a scroll bar, and the page step is simple in many common situations.
+ The scroll bar's range of values is determined by subtracting a
+ chosen page step from some value representing the length of the document.
+ In such cases, the following equation is useful:
+ \e{document length} = maximum() - minimum() + pageStep().
+ \endtable
+
+ QScrollBar only provides integer ranges. Note that although
+ QScrollBar handles very large numbers, scroll bars on current
+ screens cannot usefully represent ranges above about 100,000 pixels.
+ Beyond that, it becomes difficult for the user to control the
+ slider using either the keyboard or the mouse, and the scroll
+ arrows will have limited use.
+
+ ScrollBar inherits a comprehensive set of signals from QAbstractSlider:
+ \list
+ \o \l{QAbstractSlider::valueChanged()}{valueChanged()} is emitted when the
+ scroll bar's value has changed. The tracking() determines whether this
+ signal is emitted during user interaction.
+ \o \l{QAbstractSlider::rangeChanged()}{rangeChanged()} is emitted when the
+ scroll bar's range of values has changed.
+ \o \l{QAbstractSlider::sliderPressed()}{sliderPressed()} is emitted when
+ the user starts to drag the slider.
+ \o \l{QAbstractSlider::sliderMoved()}{sliderMoved()} is emitted when the user
+ drags the slider.
+ \o \l{QAbstractSlider::sliderReleased()}{sliderReleased()} is emitted when
+ the user releases the slider.
+ \o \l{QAbstractSlider::actionTriggered()}{actionTriggered()} is emitted
+ when the scroll bar is changed by user interaction or via the
+ \l{QAbstractSlider::triggerAction()}{triggerAction()} function.
+ \endlist
+
+ A scroll bar can be controlled by the keyboard, but it has a
+ default focusPolicy() of Qt::NoFocus. Use setFocusPolicy() to
+ enable keyboard interaction with the scroll bar:
+ \list
+ \o Left/Right move a horizontal scroll bar by one single step.
+ \o Up/Down move a vertical scroll bar by one single step.
+ \o PageUp moves up one page.
+ \o PageDown moves down one page.
+ \o Home moves to the start (mininum).
+ \o End moves to the end (maximum).
+ \endlist
+
+ The slider itself can be controlled by using the
+ \l{QAbstractSlider::triggerAction()}{triggerAction()} function to simulate
+ user interaction with the scroll bar controls. This is useful if you have
+ many different widgets that use a common range of values.
+
+ Most GUI styles use the pageStep() value to calculate the size of the
+ slider.
+
+ \table 100%
+ \row \o \inlineimage macintosh-horizontalscrollbar.png Screenshot of a Macintosh style scroll bar
+ \o A scroll bar shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage windowsxp-horizontalscrollbar.png Screenshot of a Windows XP style scroll bar
+ \o A scroll bar shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-horizontalscrollbar.png Screenshot of a Plastique style scroll bar
+ \o A scroll bar shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QScrollArea, QSlider, QDial, QSpinBox, {fowler}{GUI Design Handbook: Scroll Bar}, {Sliders Example}
+*/
+
+class QScrollBarPrivate : public QAbstractSliderPrivate
+{
+ Q_DECLARE_PUBLIC(QScrollBar)
+public:
+ QStyle::SubControl pressedControl;
+ bool pointerOutsidePressedControl;
+
+ int clickOffset, snapBackPosition;
+
+ void activateControl(uint control, int threshold = 500);
+ void stopRepeatAction();
+ int pixelPosToRangeValue(int pos) const;
+ void init();
+ bool updateHoverControl(const QPoint &pos);
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+};
+
+bool QScrollBarPrivate::updateHoverControl(const QPoint &pos)
+{
+ Q_Q(QScrollBar);
+ QRect lastHoverRect = hoverRect;
+ QStyle::SubControl lastHoverControl = hoverControl;
+ bool doesHover = q->testAttribute(Qt::WA_Hover);
+ if (lastHoverControl != newHoverControl(pos) && doesHover) {
+ q->update(lastHoverRect);
+ q->update(hoverRect);
+ return true;
+ }
+ return !doesHover;
+}
+
+QStyle::SubControl QScrollBarPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QScrollBar);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, pos, q);
+ if (hoverControl == QStyle::SC_None)
+ hoverRect = QRect();
+ else
+ hoverRect = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, hoverControl, q);
+ return hoverControl;
+}
+
+void QScrollBarPrivate::activateControl(uint control, int threshold)
+{
+ QAbstractSlider::SliderAction action = QAbstractSlider::SliderNoAction;
+ switch (control) {
+ case QStyle::SC_ScrollBarAddPage:
+ action = QAbstractSlider::SliderPageStepAdd;
+ break;
+ case QStyle::SC_ScrollBarSubPage:
+ action = QAbstractSlider::SliderPageStepSub;
+ break;
+ case QStyle::SC_ScrollBarAddLine:
+ action = QAbstractSlider::SliderSingleStepAdd;
+ break;
+ case QStyle::SC_ScrollBarSubLine:
+ action = QAbstractSlider::SliderSingleStepSub;
+ break;
+ case QStyle::SC_ScrollBarFirst:
+ action = QAbstractSlider::SliderToMinimum;
+ break;
+ case QStyle::SC_ScrollBarLast:
+ action = QAbstractSlider::SliderToMaximum;
+ break;
+ default:
+ break;
+ }
+
+ if (action) {
+ q_func()->setRepeatAction(action, threshold);
+ q_func()->triggerAction(action);
+ }
+}
+
+void QScrollBarPrivate::stopRepeatAction()
+{
+ Q_Q(QScrollBar);
+ QStyle::SubControl tmp = pressedControl;
+ q->setRepeatAction(QAbstractSlider::SliderNoAction);
+ pressedControl = QStyle::SC_None;
+
+ if (tmp == QStyle::SC_ScrollBarSlider)
+ q->setSliderDown(false);
+
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ q->repaint(q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, tmp, q));
+}
+
+/*!
+ Initialize \a option with the values from this QScrollBar. This method
+ is useful for subclasses when they need a QStyleOptionSlider, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QScrollBar::initStyleOption(QStyleOptionSlider *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QScrollBar);
+ option->initFrom(this);
+ option->subControls = QStyle::SC_None;
+ option->activeSubControls = QStyle::SC_None;
+ option->orientation = d->orientation;
+ option->minimum = d->minimum;
+ option->maximum = d->maximum;
+ option->sliderPosition = d->position;
+ option->sliderValue = d->value;
+ option->singleStep = d->singleStep;
+ option->pageStep = d->pageStep;
+ option->upsideDown = d->invertedAppearance;
+ if (d->orientation == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+}
+
+
+#define HORIZONTAL (d_func()->orientation == Qt::Horizontal)
+#define VERTICAL !HORIZONTAL
+
+/*!
+ Constructs a vertical scroll bar.
+
+ The \a parent argument is sent to the QWidget constructor.
+
+ The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the
+ \l {QAbstractSlider::maximum} {maximum} to 99, with a
+ \l {QAbstractSlider::singleStep} {singleStep} size of 1 and a
+ \l {QAbstractSlider::pageStep} {pageStep} size of 10, and an
+ initial \l {QAbstractSlider::value} {value} of 0.
+*/
+QScrollBar::QScrollBar(QWidget *parent)
+ : QAbstractSlider(*new QScrollBarPrivate, parent)
+{
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Constructs a scroll bar with the given \a orientation.
+
+ The \a parent argument is passed to the QWidget constructor.
+
+ The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the
+ \l {QAbstractSlider::maximum} {maximum} to 99, with a
+ \l {QAbstractSlider::singleStep} {singleStep} size of 1 and a
+ \l {QAbstractSlider::pageStep} {pageStep} size of 10, and an
+ initial \l {QAbstractSlider::value} {value} of 0.
+*/
+QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent)
+ : QAbstractSlider(*new QScrollBarPrivate, parent)
+{
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QScrollBar::QScrollBar(QWidget *parent, const char *name)
+ : QAbstractSlider(*new QScrollBarPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent, const char *name)
+ : QAbstractSlider(*new QScrollBarPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QScrollBar::QScrollBar(int minimum, int maximum, int lineStep, int pageStep,
+ int value, Qt::Orientation orientation,
+ QWidget *parent, const char *name)
+ : QAbstractSlider(*new QScrollBarPrivate, parent)
+{
+ Q_D(QScrollBar);
+ setObjectName(QString::fromAscii(name));
+ d->minimum = minimum;
+ d->maximum = maximum;
+ d->singleStep = lineStep;
+ d->pageStep = pageStep;
+ d->value = value;
+ d->orientation = orientation;
+ d->init();
+}
+#endif // QT3_SUPPORT
+
+/*!
+ Destroys the scroll bar.
+*/
+QScrollBar::~QScrollBar()
+{
+}
+
+void QScrollBarPrivate::init()
+{
+ Q_Q(QScrollBar);
+ invertedControls = true;
+ pressedControl = hoverControl = QStyle::SC_None;
+ pointerOutsidePressedControl = false;
+ q->setFocusPolicy(Qt::NoFocus);
+ QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Slider);
+ if (orientation == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ q->setAttribute(Qt::WA_OpaquePaintEvent);
+
+#if !defined(QT_NO_CONTEXTMENU) && defined(Q_WS_WINCE)
+ if (!q->style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, q)) {
+ q->setContextMenuPolicy(Qt::PreventContextMenu);
+ }
+#endif
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*! \reimp */
+void QScrollBar::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (!style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, this)) {
+ QAbstractSlider::contextMenuEvent(event);
+ return ;
+ }
+
+#ifndef QT_NO_MENU
+ bool horiz = HORIZONTAL;
+ QPointer<QMenu> menu = new QMenu(this);
+ QAction *actScrollHere = menu->addAction(tr("Scroll here"));
+ menu->addSeparator();
+ QAction *actScrollTop = menu->addAction(horiz ? tr("Left edge") : tr("Top"));
+ QAction *actScrollBottom = menu->addAction(horiz ? tr("Right edge") : tr("Bottom"));
+ menu->addSeparator();
+ QAction *actPageUp = menu->addAction(horiz ? tr("Page left") : tr("Page up"));
+ QAction *actPageDn = menu->addAction(horiz ? tr("Page right") : tr("Page down"));
+ menu->addSeparator();
+ QAction *actScrollUp = menu->addAction(horiz ? tr("Scroll left") : tr("Scroll up"));
+ QAction *actScrollDn = menu->addAction(horiz ? tr("Scroll right") : tr("Scroll down"));
+ QAction *actionSelected = menu->exec(event->globalPos());
+ delete menu;
+ if (actionSelected == 0)
+ /* do nothing */ ;
+ else if (actionSelected == actScrollHere)
+ setValue(d_func()->pixelPosToRangeValue(horiz ? event->pos().x() : event->pos().y()));
+ else if (actionSelected == actScrollTop)
+ triggerAction(QAbstractSlider::SliderToMinimum);
+ else if (actionSelected == actScrollBottom)
+ triggerAction(QAbstractSlider::SliderToMaximum);
+ else if (actionSelected == actPageUp)
+ triggerAction(QAbstractSlider::SliderPageStepSub);
+ else if (actionSelected == actPageDn)
+ triggerAction(QAbstractSlider::SliderPageStepAdd);
+ else if (actionSelected == actScrollUp)
+ triggerAction(QAbstractSlider::SliderSingleStepSub);
+ else if (actionSelected == actScrollDn)
+ triggerAction(QAbstractSlider::SliderSingleStepAdd);
+#endif // QT_NO_MENU
+}
+#endif // QT_NO_CONTEXTMENU
+
+
+/*! \reimp */
+QSize QScrollBar::sizeHint() const
+{
+ ensurePolished();
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+
+ int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this);
+ int scrollBarSliderMin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &opt, this);
+ QSize size;
+ if (opt.orientation == Qt::Horizontal)
+ size = QSize(scrollBarExtent * 2 + scrollBarSliderMin, scrollBarExtent);
+ else
+ size = QSize(scrollBarExtent, scrollBarExtent * 2 + scrollBarSliderMin);
+
+ return style()->sizeFromContents(QStyle::CT_ScrollBar, &opt, size, this)
+ .expandedTo(QApplication::globalStrut());
+ }
+
+/*!\reimp */
+void QScrollBar::sliderChange(SliderChange change)
+{
+ QAbstractSlider::sliderChange(change);
+}
+
+/*!
+ \reimp
+*/
+bool QScrollBar::event(QEvent *event)
+{
+ switch(event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d_func()->updateHoverControl(he->pos());
+ break;
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel: {
+ event->ignore();
+ // override wheel event without adding virtual function override
+ QWheelEvent *ev = static_cast<QWheelEvent *>(event);
+ int delta = ev->delta();
+ // scrollbar is a special case - in vertical mode it reaches minimum
+ // value in the upper position, however QSlider's minimum value is on
+ // the bottom. So we need to invert a value, but since the scrollbar is
+ // inverted by default, we need to inverse the delta value for the
+ // horizontal orientation.
+ if (ev->orientation() == Qt::Horizontal)
+ delta = -delta;
+ Q_D(QScrollBar);
+ if (d->scrollByDelta(ev->orientation(), ev->modifiers(), delta))
+ event->accept();
+ return true;
+ }
+#endif
+ default:
+ break;
+ }
+ return QAbstractSlider::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QScrollBar::paintEvent(QPaintEvent *)
+{
+ Q_D(QScrollBar);
+ QPainter p(this);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ if (d->pressedControl) {
+ opt.activeSubControls = (QStyle::SubControl)d->pressedControl;
+ if (!d->pointerOutsidePressedControl)
+ opt.state |= QStyle::State_Sunken;
+ } else {
+ opt.activeSubControls = (QStyle::SubControl)d->hoverControl;
+ }
+ style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);
+}
+
+/*!
+ \reimp
+*/
+void QScrollBar::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QScrollBar);
+
+ if (d->repeatActionTimer.isActive())
+ d->stopRepeatAction();
+
+ bool midButtonAbsPos = style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition,
+ 0, this);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+
+ if (d->maximum == d->minimum // no range
+ || (e->buttons() & (~e->button())) // another button was clicked before
+ || !(e->button() == Qt::LeftButton || (midButtonAbsPos && e->button() == Qt::MidButton)))
+ return;
+
+ d->pressedControl = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);
+ d->pointerOutsidePressedControl = false;
+
+ QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt,
+ QStyle::SC_ScrollBarSlider, this);
+ QPoint click = e->pos();
+ QPoint pressValue = click - sr.center() + sr.topLeft();
+ d->pressValue = d->orientation == Qt::Horizontal ? d->pixelPosToRangeValue(pressValue.x()) :
+ d->pixelPosToRangeValue(pressValue.y());
+ if (d->pressedControl == QStyle::SC_ScrollBarSlider) {
+ d->clickOffset = HORIZONTAL ? (click.x()-sr.x()) : (click.y()-sr.y());
+ d->snapBackPosition = d->position;
+ }
+
+ if ((d->pressedControl == QStyle::SC_ScrollBarAddPage
+ || d->pressedControl == QStyle::SC_ScrollBarSubPage)
+ && ((midButtonAbsPos && e->button() == Qt::MidButton)
+ || (style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition, &opt, this)
+ && e->button() == Qt::LeftButton))) {
+ int sliderLength = HORIZONTAL ? sr.width() : sr.height();
+ setSliderPosition(d->pixelPosToRangeValue((HORIZONTAL ? e->pos().x()
+ : e->pos().y()) - sliderLength / 2));
+ d->pressedControl = QStyle::SC_ScrollBarSlider;
+ d->clickOffset = sliderLength / 2;
+ }
+ const int initialDelay = 500; // default threshold
+ d->activateControl(d->pressedControl, initialDelay);
+ QElapsedTimer time;
+ time.start();
+ repaint(style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this));
+ if (time.elapsed() >= initialDelay && d->repeatActionTimer.isActive()) {
+ // It took more than 500ms (the initial timer delay) to process the repaint(), we
+ // therefore need to restart the timer in case we have a pending mouse release event;
+ // otherwise we'll get a timer event right before the release event,
+ // causing the repeat action to be invoked twice on a single mouse click.
+ // 50ms is the default repeat time (see activateControl/setRepeatAction).
+ d->repeatActionTimer.start(50, this);
+ }
+ if (d->pressedControl == QStyle::SC_ScrollBarSlider)
+ setSliderDown(true);
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QScrollBar);
+ if (!d->pressedControl)
+ return;
+
+ if (e->buttons() & (~e->button())) // some other button is still pressed
+ return;
+
+ d->stopRepeatAction();
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QScrollBar);
+ if (!d->pressedControl)
+ return;
+
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ if (!(e->buttons() & Qt::LeftButton
+ || ((e->buttons() & Qt::MidButton)
+ && style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition, &opt, this))))
+ return;
+
+ if (d->pressedControl == QStyle::SC_ScrollBarSlider) {
+ QPoint click = e->pos();
+ int newPosition = d->pixelPosToRangeValue((HORIZONTAL ? click.x() : click.y()) -d->clickOffset);
+ int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
+ if (m >= 0) {
+ QRect r = rect();
+ r.adjust(-m, -m, m, m);
+ if (! r.contains(e->pos()))
+ newPosition = d->snapBackPosition;
+ }
+ setSliderPosition(newPosition);
+ } else if (!style()->styleHint(QStyle::SH_ScrollBar_ScrollWhenPointerLeavesControl, &opt, this)) {
+
+ if (style()->styleHint(QStyle::SH_ScrollBar_RollBetweenButtons, &opt, this)
+ && d->pressedControl & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {
+ QStyle::SubControl newSc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);
+ if (newSc == d->pressedControl && !d->pointerOutsidePressedControl)
+ return; // nothing to do
+ if (newSc & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {
+ d->pointerOutsidePressedControl = false;
+ QRect scRect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, newSc, this);
+ scRect |= style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);
+ d->pressedControl = newSc;
+ d->activateControl(d->pressedControl, 0);
+ update(scRect);
+ return;
+ }
+ }
+
+ // stop scrolling when the mouse pointer leaves a control
+ // similar to push buttons
+ QRect pr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);
+ if (pr.contains(e->pos()) == d->pointerOutsidePressedControl) {
+ if ((d->pointerOutsidePressedControl = !d->pointerOutsidePressedControl)) {
+ d->pointerOutsidePressedControl = true;
+ setRepeatAction(SliderNoAction);
+ repaint(pr);
+ } else {
+ d->activateControl(d->pressedControl);
+ }
+ }
+ }
+}
+
+
+int QScrollBarPrivate::pixelPosToRangeValue(int pos) const
+{
+ Q_Q(const QScrollBar);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ QRect gr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,
+ QStyle::SC_ScrollBarGroove, q);
+ QRect sr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,
+ QStyle::SC_ScrollBarSlider, q);
+ int sliderMin, sliderMax, sliderLength;
+
+ if (orientation == Qt::Horizontal) {
+ sliderLength = sr.width();
+ sliderMin = gr.x();
+ sliderMax = gr.right() - sliderLength + 1;
+ if (q->layoutDirection() == Qt::RightToLeft)
+ opt.upsideDown = !opt.upsideDown;
+ } else {
+ sliderLength = sr.height();
+ sliderMin = gr.y();
+ sliderMax = gr.bottom() - sliderLength + 1;
+ }
+
+ return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,
+ sliderMax - sliderMin, opt.upsideDown);
+}
+
+/*! \reimp
+*/
+void QScrollBar::hideEvent(QHideEvent *)
+{
+ Q_D(QScrollBar);
+ if (d->pressedControl) {
+ d->pressedControl = QStyle::SC_None;
+ setRepeatAction(SliderNoAction);
+ }
+}
+
+/*!
+ \fn bool QScrollBar::draggingSlider()
+
+ Use isSliderDown() instead.
+*/
+
+/*! \internal
+ Returns the style option for scroll bar.
+*/
+Q_WIDGETS_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollbar)
+{
+ QStyleOptionSlider opt;
+ scrollbar->initStyleOption(&opt);
+ return opt;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCROLLBAR
diff --git a/src/widgets/widgets/qscrollbar.h b/src/widgets/widgets/qscrollbar.h
new file mode 100644
index 0000000000..2fd00de522
--- /dev/null
+++ b/src/widgets/widgets/qscrollbar.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCROLLBAR_H
+#define QSCROLLBAR_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qabstractslider.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SCROLLBAR
+
+class QScrollBarPrivate;
+class QStyleOptionSlider;
+
+class Q_WIDGETS_EXPORT QScrollBar : public QAbstractSlider
+{
+ Q_OBJECT
+public:
+ explicit QScrollBar(QWidget *parent=0);
+ explicit QScrollBar(Qt::Orientation, QWidget *parent=0);
+ ~QScrollBar();
+
+ QSize sizeHint() const;
+ bool event(QEvent *event);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void hideEvent(QHideEvent*);
+ void sliderChange(SliderChange change);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *);
+#endif
+ void initStyleOption(QStyleOptionSlider *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QScrollBar(QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QScrollBar(Qt::Orientation, QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QScrollBar(int minValue, int maxValue, int lineStep, int pageStep,
+ int value, Qt::Orientation, QWidget *parent=0, const char* name = 0);
+ inline QT3_SUPPORT bool draggingSlider() { return isSliderDown(); }
+#endif
+
+private:
+ friend Q_WIDGETS_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollBar);
+
+ Q_DISABLE_COPY(QScrollBar)
+ Q_DECLARE_PRIVATE(QScrollBar)
+};
+
+#endif // QT_NO_SCROLLBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSCROLLBAR_H
diff --git a/src/widgets/widgets/qsizegrip.cpp b/src/widgets/widgets/qsizegrip.cpp
new file mode 100644
index 0000000000..10e99ba135
--- /dev/null
+++ b/src/widgets/widgets/qsizegrip.cpp
@@ -0,0 +1,570 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsizegrip.h"
+
+#ifndef QT_NO_SIZEGRIP
+
+#include "qapplication.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qlayout.h"
+#include "qdebug.h"
+#include <QDesktopWidget>
+
+#if defined(Q_WS_X11)
+#include <private/qt_x11_p.h>
+#elif defined (Q_WS_WIN)
+#include "qt_windows.h"
+#endif
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#endif
+
+#include <private/qwidget_p.h>
+#include <QtWidgets/qabstractscrollarea.h>
+
+#define SZ_SIZEBOTTOMRIGHT 0xf008
+#define SZ_SIZEBOTTOMLEFT 0xf007
+#define SZ_SIZETOPLEFT 0xf004
+#define SZ_SIZETOPRIGHT 0xf005
+
+QT_BEGIN_NAMESPACE
+
+static QWidget *qt_sizegrip_topLevelWidget(QWidget* w)
+{
+ while (w && !w->isWindow() && w->windowType() != Qt::SubWindow)
+ w = w->parentWidget();
+ return w;
+}
+
+class QSizeGripPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QSizeGrip)
+public:
+ void init();
+ QPoint p;
+ QRect r;
+ int d;
+ int dxMax;
+ int dyMax;
+ Qt::Corner m_corner;
+ bool gotMousePress;
+ QWidget *tlw;
+#ifdef Q_WS_MAC
+ void updateMacSizer(bool hide) const;
+#endif
+ Qt::Corner corner() const;
+ inline bool atBottom() const
+ {
+ return m_corner == Qt::BottomRightCorner || m_corner == Qt::BottomLeftCorner;
+ }
+
+ inline bool atLeft() const
+ {
+ return m_corner == Qt::BottomLeftCorner || m_corner == Qt::TopLeftCorner;
+ }
+
+ void updateTopLevelWidget()
+ {
+ Q_Q(QSizeGrip);
+ QWidget *w = qt_sizegrip_topLevelWidget(q);
+ if (tlw == w)
+ return;
+ if (tlw)
+ tlw->removeEventFilter(q);
+ tlw = w;
+ if (tlw)
+ tlw->installEventFilter(q);
+ }
+
+ // This slot is invoked by QLayout when the size grip is added to
+ // a layout or reparented after the tlw is shown. This re-implementation is basically
+ // the same as QWidgetPrivate::_q_showIfNotHidden except that it checks
+ // for Qt::WindowFullScreen and Qt::WindowMaximized as well.
+ void _q_showIfNotHidden()
+ {
+ Q_Q(QSizeGrip);
+ bool showSizeGrip = !(q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ updateTopLevelWidget();
+ if (tlw && showSizeGrip) {
+ Qt::WindowStates sizeGripNotVisibleState = Qt::WindowFullScreen;
+#ifndef Q_WS_MAC
+ sizeGripNotVisibleState |= Qt::WindowMaximized;
+#endif
+ // Don't show the size grip if the tlw is maximized or in full screen mode.
+ showSizeGrip = !(tlw->windowState() & sizeGripNotVisibleState);
+ }
+ if (showSizeGrip)
+ q->setVisible(true);
+ }
+};
+
+#ifdef Q_WS_MAC
+void QSizeGripPrivate::updateMacSizer(bool hide) const
+{
+ Q_Q(const QSizeGrip);
+ if (QApplication::closingDown() || !parent)
+ return;
+ QWidget *topLevelWindow = qt_sizegrip_topLevelWidget(const_cast<QSizeGrip *>(q));
+ if(topLevelWindow && topLevelWindow->isWindow())
+ QWidgetPrivate::qt_mac_update_sizer(topLevelWindow, hide ? -1 : 1);
+}
+#endif
+
+Qt::Corner QSizeGripPrivate::corner() const
+{
+ Q_Q(const QSizeGrip);
+ QWidget *tlw = qt_sizegrip_topLevelWidget(const_cast<QSizeGrip *>(q));
+ const QPoint sizeGripPos = q->mapTo(tlw, QPoint(0, 0));
+ bool isAtBottom = sizeGripPos.y() >= tlw->height() / 2;
+ bool isAtLeft = sizeGripPos.x() <= tlw->width() / 2;
+ if (isAtLeft)
+ return isAtBottom ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
+ else
+ return isAtBottom ? Qt::BottomRightCorner : Qt::TopRightCorner;
+}
+
+/*!
+ \class QSizeGrip
+
+ \brief The QSizeGrip class provides a resize handle for resizing top-level windows.
+
+ \ingroup mainwindow-classes
+ \ingroup basicwidgets
+
+ This widget works like the standard Windows resize handle. In the
+ X11 version this resize handle generally works differently from
+ the one provided by the system if the X11 window manager does not
+ support necessary modern post-ICCCM specifications.
+
+ Put this widget anywhere in a widget tree and the user can use it
+ to resize the top-level window or any widget with the Qt::SubWindow
+ flag set. Generally, this should be in the lower right-hand corner.
+ Note that QStatusBar already uses this widget, so if you have a
+ status bar (e.g., you are using QMainWindow), then you don't need
+ to use this widget explicitly.
+
+ On some platforms the size grip automatically hides itself when the
+ window is shown full screen or maximised.
+
+ \table 50%
+ \row \o \inlineimage plastique-sizegrip.png Screenshot of a Plastique style size grip
+ \o A size grip widget at the bottom-right corner of a main window, shown in the
+ \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ The QSizeGrip class inherits QWidget and reimplements the \l
+ {QWidget::mousePressEvent()}{mousePressEvent()} and \l
+ {QWidget::mouseMoveEvent()}{mouseMoveEvent()} functions to feature
+ the resize functionality, and the \l
+ {QWidget::paintEvent()}{paintEvent()} function to render the
+ size grip widget.
+
+ \sa QStatusBar QWidget::windowState()
+*/
+
+
+/*!
+ Constructs a resize corner as a child widget of the given \a
+ parent.
+*/
+QSizeGrip::QSizeGrip(QWidget * parent)
+ : QWidget(*new QSizeGripPrivate, parent, 0)
+{
+ Q_D(QSizeGrip);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \obsolete
+
+ Constructs a resize corner with the given \a name, as a child
+ widget of the given \a parent.
+*/
+QSizeGrip::QSizeGrip(QWidget * parent, const char* name)
+ : QWidget(*new QSizeGripPrivate, parent, 0)
+{
+ Q_D(QSizeGrip);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+#endif
+
+void QSizeGripPrivate::init()
+{
+ Q_Q(QSizeGrip);
+ dxMax = 0;
+ dyMax = 0;
+ tlw = 0;
+ m_corner = q->isLeftToRight() ? Qt::BottomRightCorner : Qt::BottomLeftCorner;
+ gotMousePress = false;
+
+#if !defined(QT_NO_CURSOR) && !defined(Q_WS_MAC)
+ q->setCursor(m_corner == Qt::TopLeftCorner || m_corner == Qt::BottomRightCorner
+ ? Qt::SizeFDiagCursor : Qt::SizeBDiagCursor);
+#endif
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
+ updateTopLevelWidget();
+}
+
+
+/*!
+ Destroys this size grip.
+*/
+QSizeGrip::~QSizeGrip()
+{
+}
+
+/*!
+ \reimp
+*/
+QSize QSizeGrip::sizeHint() const
+{
+ QStyleOption opt(0);
+ opt.init(this);
+ return (style()->sizeFromContents(QStyle::CT_SizeGrip, &opt, QSize(13, 13), this).
+ expandedTo(QApplication::globalStrut()));
+}
+
+/*!
+ Paints the resize grip.
+
+ Resize grips are usually rendered as small diagonal textured lines
+ in the lower-right corner. The paint event is passed in the \a
+ event parameter.
+*/
+void QSizeGrip::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ Q_D(QSizeGrip);
+ QPainter painter(this);
+ QStyleOptionSizeGrip opt;
+ opt.init(this);
+ opt.corner = d->m_corner;
+ style()->drawControl(QStyle::CE_SizeGrip, &opt, &painter, this);
+}
+
+/*!
+ \fn void QSizeGrip::mousePressEvent(QMouseEvent * event)
+
+ Receives the mouse press events for the widget, and primes the
+ resize operation. The mouse press event is passed in the \a event
+ parameter.
+*/
+void QSizeGrip::mousePressEvent(QMouseEvent * e)
+{
+ if (e->button() != Qt::LeftButton) {
+ QWidget::mousePressEvent(e);
+ return;
+ }
+
+ Q_D(QSizeGrip);
+ QWidget *tlw = qt_sizegrip_topLevelWidget(this);
+ d->p = e->globalPos();
+ d->gotMousePress = true;
+ d->r = tlw->geometry();
+
+#ifdef Q_WS_X11
+ // Use a native X11 sizegrip for "real" top-level windows if supported.
+ if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE))
+ && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint)
+ && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) {
+ XEvent xev;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = ATOM(_NET_WM_MOVERESIZE);
+ xev.xclient.display = X11->display;
+ xev.xclient.window = tlw->winId();
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = e->globalPos().x();
+ xev.xclient.data.l[1] = e->globalPos().y();
+ if (d->atBottom())
+ xev.xclient.data.l[2] = d->atLeft() ? 6 : 4; // bottomleft/bottomright
+ else
+ xev.xclient.data.l[2] = d->atLeft() ? 0 : 2; // topleft/topright
+ xev.xclient.data.l[3] = Button1;
+ xev.xclient.data.l[4] = 0;
+ XUngrabPointer(X11->display, X11->time);
+ XSendEvent(X11->display, QX11Info::appRootWindow(x11Info().screen()), False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ return;
+ }
+#endif // Q_WS_X11
+#ifdef Q_WS_WIN
+ if (tlw->isWindow() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) {
+ uint orientation = 0;
+ if (d->atBottom())
+ orientation = d->atLeft() ? SZ_SIZEBOTTOMLEFT : SZ_SIZEBOTTOMRIGHT;
+ else
+ orientation = d->atLeft() ? SZ_SIZETOPLEFT : SZ_SIZETOPRIGHT;
+
+ ReleaseCapture();
+ PostMessage(tlw->winId(), WM_SYSCOMMAND, orientation, 0);
+ return;
+ }
+#endif // Q_WS_WIN
+
+ // Find available desktop/workspace geometry.
+ QRect availableGeometry;
+ bool hasVerticalSizeConstraint = true;
+ bool hasHorizontalSizeConstraint = true;
+ if (tlw->isWindow())
+ availableGeometry = QApplication::desktop()->availableGeometry(tlw);
+ else {
+ const QWidget *tlwParent = tlw->parentWidget();
+ // Check if tlw is inside QAbstractScrollArea/QScrollArea.
+ // If that's the case tlw->parentWidget() will return the viewport
+ // and tlw->parentWidget()->parentWidget() will return the scroll area.
+#ifndef QT_NO_SCROLLAREA
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(tlwParent->parentWidget());
+ if (scrollArea) {
+ hasHorizontalSizeConstraint = scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff;
+ hasVerticalSizeConstraint = scrollArea->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff;
+ }
+#endif // QT_NO_SCROLLAREA
+ availableGeometry = tlwParent->contentsRect();
+ }
+
+ // Find frame geometries, title bar height, and decoration sizes.
+ const QRect frameGeometry = tlw->frameGeometry();
+ const int titleBarHeight = qMax(tlw->geometry().y() - frameGeometry.y(), 0);
+ const int bottomDecoration = qMax(frameGeometry.height() - tlw->height() - titleBarHeight, 0);
+ const int leftRightDecoration = qMax((frameGeometry.width() - tlw->width()) / 2, 0);
+
+ // Determine dyMax depending on whether the sizegrip is at the bottom
+ // of the widget or not.
+ if (d->atBottom()) {
+ if (hasVerticalSizeConstraint)
+ d->dyMax = availableGeometry.bottom() - d->r.bottom() - bottomDecoration;
+ else
+ d->dyMax = INT_MAX;
+ } else {
+ if (hasVerticalSizeConstraint)
+ d->dyMax = availableGeometry.y() - d->r.y() + titleBarHeight;
+ else
+ d->dyMax = -INT_MAX;
+ }
+
+ // In RTL mode, the size grip is to the left; find dxMax from the desktop/workspace
+ // geometry, the size grip geometry and the width of the decoration.
+ if (d->atLeft()) {
+ if (hasHorizontalSizeConstraint)
+ d->dxMax = availableGeometry.x() - d->r.x() + leftRightDecoration;
+ else
+ d->dxMax = -INT_MAX;
+ } else {
+ if (hasHorizontalSizeConstraint)
+ d->dxMax = availableGeometry.right() - d->r.right() - leftRightDecoration;
+ else
+ d->dxMax = INT_MAX;
+ }
+}
+
+
+/*!
+ \fn void QSizeGrip::mouseMoveEvent(QMouseEvent * event)
+ Resizes the top-level widget containing this widget. The mouse
+ move event is passed in the \a event parameter.
+*/
+void QSizeGrip::mouseMoveEvent(QMouseEvent * e)
+{
+ if (e->buttons() != Qt::LeftButton) {
+ QWidget::mouseMoveEvent(e);
+ return;
+ }
+
+ Q_D(QSizeGrip);
+ QWidget* tlw = qt_sizegrip_topLevelWidget(this);
+ if (!d->gotMousePress || tlw->testAttribute(Qt::WA_WState_ConfigPending))
+ return;
+
+#ifdef Q_WS_X11
+ if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE))
+ && tlw->isTopLevel() && !(tlw->windowFlags() & Qt::X11BypassWindowManagerHint)
+ && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth())
+ return;
+#endif
+#ifdef Q_WS_WIN
+ if (tlw->isWindow() && GetSystemMenu(tlw->winId(), FALSE) != 0 && internalWinId()
+ && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !qt_widget_private(tlw)->hasHeightForWidth()) {
+ MSG msg;
+ while(PeekMessage(&msg, winId(), WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE));
+ return;
+ }
+#endif
+
+ QPoint np(e->globalPos());
+
+ // Don't extend beyond the available geometry; bound to dyMax and dxMax.
+ QSize ns;
+ if (d->atBottom())
+ ns.rheight() = d->r.height() + qMin(np.y() - d->p.y(), d->dyMax);
+ else
+ ns.rheight() = d->r.height() - qMax(np.y() - d->p.y(), d->dyMax);
+
+ if (d->atLeft())
+ ns.rwidth() = d->r.width() - qMax(np.x() - d->p.x(), d->dxMax);
+ else
+ ns.rwidth() = d->r.width() + qMin(np.x() - d->p.x(), d->dxMax);
+
+ ns = QLayout::closestAcceptableSize(tlw, ns);
+
+ QPoint p;
+ QRect nr(p, ns);
+ if (d->atBottom()) {
+ if (d->atLeft())
+ nr.moveTopRight(d->r.topRight());
+ else
+ nr.moveTopLeft(d->r.topLeft());
+ } else {
+ if (d->atLeft())
+ nr.moveBottomRight(d->r.bottomRight());
+ else
+ nr.moveBottomLeft(d->r.bottomLeft());
+ }
+
+ tlw->setGeometry(nr);
+}
+
+/*!
+ \reimp
+*/
+void QSizeGrip::mouseReleaseEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->button() == Qt::LeftButton) {
+ Q_D(QSizeGrip);
+ d->gotMousePress = false;
+ d->p = QPoint();
+ } else {
+ QWidget::mouseReleaseEvent(mouseEvent);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSizeGrip::moveEvent(QMoveEvent * /*moveEvent*/)
+{
+ Q_D(QSizeGrip);
+ // We're inside a resize operation; no update necessary.
+ if (!d->p.isNull())
+ return;
+
+ d->m_corner = d->corner();
+#if !defined(QT_NO_CURSOR) && !defined(Q_WS_MAC)
+ setCursor(d->m_corner == Qt::TopLeftCorner || d->m_corner == Qt::BottomRightCorner
+ ? Qt::SizeFDiagCursor : Qt::SizeBDiagCursor);
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QSizeGrip::showEvent(QShowEvent *showEvent)
+{
+#ifdef Q_WS_MAC
+ d_func()->updateMacSizer(false);
+#endif
+ QWidget::showEvent(showEvent);
+}
+
+/*!
+ \reimp
+*/
+void QSizeGrip::hideEvent(QHideEvent *hideEvent)
+{
+#ifdef Q_WS_MAC
+ d_func()->updateMacSizer(true);
+#endif
+ QWidget::hideEvent(hideEvent);
+}
+
+/*!
+ \reimp
+*/
+void QSizeGrip::setVisible(bool visible)
+{
+ QWidget::setVisible(visible);
+}
+
+/*! \reimp */
+bool QSizeGrip::eventFilter(QObject *o, QEvent *e)
+{
+ Q_D(QSizeGrip);
+ if ((isHidden() && testAttribute(Qt::WA_WState_ExplicitShowHide))
+ || e->type() != QEvent::WindowStateChange
+ || o != d->tlw) {
+ return QWidget::eventFilter(o, e);
+ }
+ Qt::WindowStates sizeGripNotVisibleState = Qt::WindowFullScreen;
+#ifndef Q_WS_MAC
+ sizeGripNotVisibleState |= Qt::WindowMaximized;
+#endif
+ // Don't show the size grip if the tlw is maximized or in full screen mode.
+ setVisible(!(d->tlw->windowState() & sizeGripNotVisibleState));
+ setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ return QWidget::eventFilter(o, e);
+}
+
+/*!
+ \reimp
+*/
+bool QSizeGrip::event(QEvent *event)
+{
+ return QWidget::event(event);
+}
+
+#ifdef Q_WS_WIN
+/*! \reimp */
+bool QSizeGrip::winEvent( MSG *m, long *result )
+{
+ return QWidget::winEvent(m, result);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qsizegrip.cpp"
+
+#endif //QT_NO_SIZEGRIP
diff --git a/src/widgets/widgets/qsizegrip.h b/src/widgets/widgets/qsizegrip.h
new file mode 100644
index 0000000000..9e75f38457
--- /dev/null
+++ b/src/widgets/widgets/qsizegrip.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIZEGRIP_H
+#define QSIZEGRIP_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SIZEGRIP
+class QSizeGripPrivate;
+class Q_WIDGETS_EXPORT QSizeGrip : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit QSizeGrip(QWidget *parent);
+ ~QSizeGrip();
+
+ QSize sizeHint() const;
+ void setVisible(bool);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *mouseEvent);
+ void moveEvent(QMoveEvent *moveEvent);
+ void showEvent(QShowEvent *showEvent);
+ void hideEvent(QHideEvent *hideEvent);
+ bool eventFilter(QObject *, QEvent *);
+ bool event(QEvent *);
+#ifdef Q_WS_WIN
+ bool winEvent(MSG *m, long *result);
+#endif
+
+public:
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QSizeGrip(QWidget *parent, const char *name);
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QSizeGrip)
+ Q_DISABLE_COPY(QSizeGrip)
+ Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden())
+};
+#endif // QT_NO_SIZEGRIP
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSIZEGRIP_H
diff --git a/src/widgets/widgets/qslider.cpp b/src/widgets/widgets/qslider.cpp
new file mode 100644
index 0000000000..2858b98781
--- /dev/null
+++ b/src/widgets/widgets/qslider.cpp
@@ -0,0 +1,666 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qslider.h"
+#ifndef QT_NO_SLIDER
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include "qapplication.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "private/qabstractslider_p.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSliderPrivate : public QAbstractSliderPrivate
+{
+ Q_DECLARE_PUBLIC(QSlider)
+public:
+ QStyle::SubControl pressedControl;
+ int tickInterval;
+ QSlider::TickPosition tickPosition;
+ int clickOffset;
+ void init();
+ void resetLayoutItemMargins();
+ int pixelPosToRangeValue(int pos) const;
+ inline int pick(const QPoint &pt) const;
+
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+ bool updateHoverControl(const QPoint &pos);
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+};
+
+void QSliderPrivate::init()
+{
+ Q_Q(QSlider);
+ pressedControl = QStyle::SC_None;
+ tickInterval = 0;
+ tickPosition = QSlider::NoTicks;
+ hoverControl = QStyle::SC_None;
+ q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
+ QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::Slider);
+ if (orientation == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ resetLayoutItemMargins();
+}
+
+void QSliderPrivate::resetLayoutItemMargins()
+{
+ Q_Q(QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ setLayoutItemMargins(QStyle::SE_SliderLayoutItem, &opt);
+}
+
+int QSliderPrivate::pixelPosToRangeValue(int pos) const
+{
+ Q_Q(const QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ QRect gr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
+ QRect sr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
+ int sliderMin, sliderMax, sliderLength;
+
+ if (orientation == Qt::Horizontal) {
+ sliderLength = sr.width();
+ sliderMin = gr.x();
+ sliderMax = gr.right() - sliderLength + 1;
+ } else {
+ sliderLength = sr.height();
+ sliderMin = gr.y();
+ sliderMax = gr.bottom() - sliderLength + 1;
+ }
+ return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,
+ sliderMax - sliderMin, opt.upsideDown);
+}
+
+inline int QSliderPrivate::pick(const QPoint &pt) const
+{
+ return orientation == Qt::Horizontal ? pt.x() : pt.y();
+}
+
+/*!
+ Initialize \a option with the values from this QSlider. This method
+ is useful for subclasses when they need a QStyleOptionSlider, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QSlider::initStyleOption(QStyleOptionSlider *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QSlider);
+ option->initFrom(this);
+ option->subControls = QStyle::SC_None;
+ option->activeSubControls = QStyle::SC_None;
+ option->orientation = d->orientation;
+ option->maximum = d->maximum;
+ option->minimum = d->minimum;
+ option->tickPosition = (QSlider::TickPosition)d->tickPosition;
+ option->tickInterval = d->tickInterval;
+ option->upsideDown = (d->orientation == Qt::Horizontal) ?
+ (d->invertedAppearance != (option->direction == Qt::RightToLeft))
+ : (!d->invertedAppearance);
+ option->direction = Qt::LeftToRight; // we use the upsideDown option instead
+ option->sliderPosition = d->position;
+ option->sliderValue = d->value;
+ option->singleStep = d->singleStep;
+ option->pageStep = d->pageStep;
+ if (d->orientation == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+}
+
+bool QSliderPrivate::updateHoverControl(const QPoint &pos)
+{
+ Q_Q(QSlider);
+ QRect lastHoverRect = hoverRect;
+ QStyle::SubControl lastHoverControl = hoverControl;
+ bool doesHover = q->testAttribute(Qt::WA_Hover);
+ if (lastHoverControl != newHoverControl(pos) && doesHover) {
+ q->update(lastHoverRect);
+ q->update(hoverRect);
+ return true;
+ }
+ return !doesHover;
+}
+
+QStyle::SubControl QSliderPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ QRect handleRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
+ QRect grooveRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
+ QRect tickmarksRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderTickmarks, q);
+
+ if (handleRect.contains(pos)) {
+ hoverRect = handleRect;
+ hoverControl = QStyle::SC_SliderHandle;
+ } else if (grooveRect.contains(pos)) {
+ hoverRect = grooveRect;
+ hoverControl = QStyle::SC_SliderGroove;
+ } else if (tickmarksRect.contains(pos)) {
+ hoverRect = tickmarksRect;
+ hoverControl = QStyle::SC_SliderTickmarks;
+ } else {
+ hoverRect = QRect();
+ hoverControl = QStyle::SC_None;
+ }
+
+ return hoverControl;
+}
+
+/*!
+ \class QSlider
+ \brief The QSlider widget provides a vertical or horizontal slider.
+
+ \ingroup basicwidgets
+
+
+ The slider is the classic widget for controlling a bounded value.
+ It lets the user move a slider handle along a horizontal or vertical
+ groove and translates the handle's position into an integer value
+ within the legal range.
+
+ QSlider has very few of its own functions; most of the functionality is in
+ QAbstractSlider. The most useful functions are setValue() to set
+ the slider directly to some value; triggerAction() to simulate
+ the effects of clicking (useful for shortcut keys);
+ setSingleStep(), setPageStep() to set the steps; and setMinimum()
+ and setMaximum() to define the range of the scroll bar.
+
+ QSlider provides methods for controlling tickmarks. You can use
+ setTickPosition() to indicate where you want the tickmarks to be,
+ setTickInterval() to indicate how many of them you want. the
+ currently set tick position and interval can be queried using the
+ tickPosition() and tickInterval() functions, respectively.
+
+ QSlider inherits a comprehensive set of signals:
+ \table
+ \header \o Signal \o Description
+ \row \o \l valueChanged()
+ \o Emitted when the slider's value has changed. The tracking()
+ determines whether this signal is emitted during user
+ interaction.
+ \row \o \l sliderPressed()
+ \o Emitted when the user starts to drag the slider.
+ \row \o \l sliderMoved()
+ \o Emitted when the user drags the slider.
+ \row \o \l sliderReleased()
+ \o Emitted when the user releases the slider.
+ \endtable
+
+ QSlider only provides integer ranges. Note that although
+ QSlider handles very large numbers, it becomes difficult for users
+ to use a slider accurately for very large ranges.
+
+ A slider accepts focus on Tab and provides both a mouse wheel and a
+ keyboard interface. The keyboard interface is the following:
+
+ \list
+ \o Left/Right move a horizontal slider by one single step.
+ \o Up/Down move a vertical slider by one single step.
+ \o PageUp moves up one page.
+ \o PageDown moves down one page.
+ \o Home moves to the start (mininum).
+ \o End moves to the end (maximum).
+ \endlist
+
+ \table 100%
+ \row \o \inlineimage macintosh-slider.png Screenshot of a Macintosh slider
+ \o A slider shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage windows-slider.png Screenshot of a Windows XP slider
+ \o A slider shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-slider.png Screenshot of a Plastique slider
+ \o A slider shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QScrollBar, QSpinBox, QDial, {fowler}{GUI Design Handbook: Slider}, {Sliders Example}
+*/
+
+
+/*!
+ \enum QSlider::TickPosition
+
+ This enum specifies where the tick marks are to be drawn relative
+ to the slider's groove and the handle the user moves.
+
+ \value NoTicks Do not draw any tick marks.
+ \value TicksBothSides Draw tick marks on both sides of the groove.
+ \value TicksAbove Draw tick marks above the (horizontal) slider
+ \value TicksBelow Draw tick marks below the (horizontal) slider
+ \value TicksLeft Draw tick marks to the left of the (vertical) slider
+ \value TicksRight Draw tick marks to the right of the (vertical) slider
+
+ \omitvalue NoMarks
+ \omitvalue Above
+ \omitvalue Left
+ \omitvalue Below
+ \omitvalue Right
+ \omitvalue Both
+*/
+
+
+/*!
+ Constructs a vertical slider with the given \a parent.
+*/
+QSlider::QSlider(QWidget *parent)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Constructs a slider with the given \a parent. The \a orientation
+ parameter determines whether the slider is horizontal or vertical;
+ the valid values are Qt::Vertical and Qt::Horizontal.
+*/
+
+QSlider::QSlider(Qt::Orientation orientation, QWidget *parent)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use QSlider() and QObject::setObjectName() instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(parent);
+ mySlider->setObjectName(name);
+ \endcode
+*/
+QSlider::QSlider(QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Use QSlider() and QObject::setObjectName() instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(orientation, parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(orientation, parent);
+ mySlider->setObjectName(name);
+ \endcode
+*/
+QSlider::QSlider(Qt::Orientation orientation, QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+/*!
+ Use QSlider(), QObject::setObjectName() and the functionality
+ inherited from QAbstractSlider instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(minValue, maxValue, pageStep,
+ value, orientation, parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(orientation, parent);
+ mySlider->setObjectName(name);
+ mySlider->setMinimum(minValue);
+ mySlider->setMaximum(maxValue);
+ mySlider->setPageStep(pageStep);
+ mySlider->setValue(value);
+ \endcode
+*/
+QSlider::QSlider(int minValue, int maxValue, int pageStep, int value, Qt::Orientation orientation,
+ QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ Q_D(QSlider);
+ setObjectName(QString::fromAscii(name));
+ d->minimum = minValue;
+ d->maximum = maxValue;
+ d->pageStep = pageStep;
+ d->position = d->value = value;
+ d->orientation = orientation;
+ d->init();
+}
+#endif
+
+/*!
+ Destroys this slider.
+*/
+QSlider::~QSlider()
+{
+}
+
+/*!
+ \reimp
+*/
+void QSlider::paintEvent(QPaintEvent *)
+{
+ Q_D(QSlider);
+ QPainter p(this);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+
+ opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
+ if (d->tickPosition != NoTicks)
+ opt.subControls |= QStyle::SC_SliderTickmarks;
+ if (d->pressedControl) {
+ opt.activeSubControls = d->pressedControl;
+ opt.state |= QStyle::State_Sunken;
+ } else {
+ opt.activeSubControls = d->hoverControl;
+ }
+
+ style()->drawComplexControl(QStyle::CC_Slider, &opt, &p, this);
+}
+
+/*!
+ \reimp
+*/
+
+bool QSlider::event(QEvent *event)
+{
+ Q_D(QSlider);
+
+ switch(event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d->updateHoverControl(he->pos());
+ break;
+ case QEvent::StyleChange:
+ case QEvent::MacSizeChange:
+ d->resetLayoutItemMargins();
+ break;
+ default:
+ break;
+ }
+ return QAbstractSlider::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QSlider::mousePressEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->maximum == d->minimum || (ev->buttons() ^ ev->button())) {
+ ev->ignore();
+ return;
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ setEditFocus(true);
+#endif
+ ev->accept();
+ if ((ev->button() & style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons)) == ev->button()) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ const QPoint center = sliderRect.center() - sliderRect.topLeft();
+ // to take half of the slider off for the setSliderPosition call we use the center - topLeft
+
+ setSliderPosition(d->pixelPosToRangeValue(d->pick(ev->pos() - center)));
+ triggerAction(SliderMove);
+ setRepeatAction(SliderNoAction);
+ d->pressedControl = QStyle::SC_SliderHandle;
+ update();
+ } else if ((ev->button() & style()->styleHint(QStyle::SH_Slider_PageSetButtons)) == ev->button()) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ d->pressedControl = style()->hitTestComplexControl(QStyle::CC_Slider,
+ &opt, ev->pos(), this);
+ SliderAction action = SliderNoAction;
+ if (d->pressedControl == QStyle::SC_SliderGroove) {
+ const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ int pressValue = d->pixelPosToRangeValue(d->pick(ev->pos() - sliderRect.center() + sliderRect.topLeft()));
+ d->pressValue = pressValue;
+ if (pressValue > d->value)
+ action = SliderPageStepAdd;
+ else if (pressValue < d->value)
+ action = SliderPageStepSub;
+ if (action) {
+ triggerAction(action);
+ setRepeatAction(action);
+ }
+ }
+ } else {
+ ev->ignore();
+ return;
+ }
+
+ if (d->pressedControl == QStyle::SC_SliderHandle) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ setRepeatAction(SliderNoAction);
+ QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ d->clickOffset = d->pick(ev->pos() - sr.topLeft());
+ update(sr);
+ setSliderDown(true);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSlider::mouseMoveEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->pressedControl != QStyle::SC_SliderHandle) {
+ ev->ignore();
+ return;
+ }
+ ev->accept();
+ int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ setSliderPosition(newPosition);
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::mouseReleaseEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->pressedControl == QStyle::SC_None || ev->buttons()) {
+ ev->ignore();
+ return;
+ }
+ ev->accept();
+ QStyle::SubControl oldPressed = QStyle::SubControl(d->pressedControl);
+ d->pressedControl = QStyle::SC_None;
+ setRepeatAction(SliderNoAction);
+ if (oldPressed == QStyle::SC_SliderHandle)
+ setSliderDown(false);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ opt.subControls = oldPressed;
+ update(style()->subControlRect(QStyle::CC_Slider, &opt, oldPressed, this));
+}
+
+/*!
+ \reimp
+*/
+QSize QSlider::sizeHint() const
+{
+ Q_D(const QSlider);
+ ensurePolished();
+ const int SliderLength = 84, TickSpace = 5;
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ int thick = style()->pixelMetric(QStyle::PM_SliderThickness, &opt, this);
+ if (d->tickPosition & TicksAbove)
+ thick += TickSpace;
+ if (d->tickPosition & TicksBelow)
+ thick += TickSpace;
+ int w = thick, h = SliderLength;
+ if (d->orientation == Qt::Horizontal) {
+ w = SliderLength;
+ h = thick;
+ }
+ return style()->sizeFromContents(QStyle::CT_Slider, &opt, QSize(w, h), this).expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+QSize QSlider::minimumSizeHint() const
+{
+ Q_D(const QSlider);
+ QSize s = sizeHint();
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ int length = style()->pixelMetric(QStyle::PM_SliderLength, &opt, this);
+ if (d->orientation == Qt::Horizontal)
+ s.setWidth(length);
+ else
+ s.setHeight(length);
+ return s;
+}
+
+/*!
+ \property QSlider::tickPosition
+ \brief the tickmark position for this slider
+
+ The valid values are described by the QSlider::TickPosition enum.
+
+ The default value is \l QSlider::NoTicks.
+
+ \sa tickInterval
+*/
+
+void QSlider::setTickPosition(TickPosition position)
+{
+ Q_D(QSlider);
+ d->tickPosition = position;
+ d->resetLayoutItemMargins();
+ update();
+ updateGeometry();
+}
+
+QSlider::TickPosition QSlider::tickPosition() const
+{
+ return d_func()->tickPosition;
+}
+
+/*!
+ \fn TickPosition QSlider::tickmarks() const
+ \compat
+
+ Use tickPosition() instead.
+*/
+
+/*!
+ \fn QSlider::setTickmarks(TickPosition position)
+ \compat
+
+ Use setTickPosition() instead.
+*/
+
+/*!
+ \property QSlider::tickInterval
+ \brief the interval between tickmarks
+
+ This is a value interval, not a pixel interval. If it is 0, the
+ slider will choose between singleStep() and pageStep().
+
+ The default value is 0.
+
+ \sa tickPosition, lineStep(), pageStep()
+*/
+
+void QSlider::setTickInterval(int ts)
+{
+ d_func()->tickInterval = qMax(0, ts);
+ update();
+}
+
+int QSlider::tickInterval() const
+{
+ return d_func()->tickInterval;
+}
+
+/*!
+ \fn void QSlider::addStep()
+
+ Use setValue() instead.
+*/
+
+/*!
+ \fn void QSlider::subtractStep()
+
+ Use setValue() instead.
+*/
+
+/*! \internal
+ Returns the style option for slider.
+*/
+Q_WIDGETS_EXPORT QStyleOptionSlider qt_qsliderStyleOption(QSlider *slider)
+{
+ QStyleOptionSlider sliderOption;
+ slider->initStyleOption(&sliderOption);
+ return sliderOption;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qslider.h b/src/widgets/widgets/qslider.h
new file mode 100644
index 0000000000..907548fcb2
--- /dev/null
+++ b/src/widgets/widgets/qslider.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSLIDER_H
+#define QSLIDER_H
+
+#include <QtWidgets/qabstractslider.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SLIDER
+
+class QSliderPrivate;
+class QStyleOptionSlider;
+class Q_WIDGETS_EXPORT QSlider : public QAbstractSlider
+{
+ Q_OBJECT
+
+ Q_ENUMS(TickPosition)
+ Q_PROPERTY(TickPosition tickPosition READ tickPosition WRITE setTickPosition)
+ Q_PROPERTY(int tickInterval READ tickInterval WRITE setTickInterval)
+
+public:
+ enum TickPosition {
+ NoTicks = 0,
+ TicksAbove = 1,
+ TicksLeft = TicksAbove,
+ TicksBelow = 2,
+ TicksRight = TicksBelow,
+ TicksBothSides = 3
+
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ ,NoMarks = NoTicks,
+ Above = TicksAbove,
+ Left = TicksAbove,
+ Below = TicksBelow,
+ Right = TicksRight,
+ Both = TicksBothSides
+#endif
+ };
+
+ explicit QSlider(QWidget *parent = 0);
+ explicit QSlider(Qt::Orientation orientation, QWidget *parent = 0);
+
+ ~QSlider();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setTickPosition(TickPosition position);
+ TickPosition tickPosition() const;
+
+ void setTickInterval(int ti);
+ int tickInterval() const;
+
+ bool event(QEvent *event);
+
+protected:
+ void paintEvent(QPaintEvent *ev);
+ void mousePressEvent(QMouseEvent *ev);
+ void mouseReleaseEvent(QMouseEvent *ev);
+ void mouseMoveEvent(QMouseEvent *ev);
+ void initStyleOption(QStyleOptionSlider *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QSlider(QWidget *parent, const char *name);
+ QT3_SUPPORT_CONSTRUCTOR QSlider(Qt::Orientation, QWidget *parent, const char *name);
+ QT3_SUPPORT_CONSTRUCTOR QSlider(int minValue, int maxValue, int pageStep, int value,
+ Qt::Orientation orientation,
+ QWidget *parent = 0, const char *name = 0);
+ inline QT3_SUPPORT void setTickmarks(TickPosition position) { setTickPosition(position); }
+ inline QT3_SUPPORT TickPosition tickmarks() const { return tickPosition(); }
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void addStep() { triggerAction(SliderSingleStepAdd); }
+ inline QT_MOC_COMPAT void subtractStep() { triggerAction(SliderSingleStepSub); }
+#endif
+
+private:
+ friend Q_WIDGETS_EXPORT QStyleOptionSlider qt_qsliderStyleOption(QSlider *slider);
+
+ Q_DISABLE_COPY(QSlider)
+ Q_DECLARE_PRIVATE(QSlider)
+};
+
+#endif // QT_NO_SLIDER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSLIDER_H
diff --git a/src/widgets/widgets/qspinbox.cpp b/src/widgets/widgets/qspinbox.cpp
new file mode 100644
index 0000000000..952f9e2728
--- /dev/null
+++ b/src/widgets/widgets/qspinbox.cpp
@@ -0,0 +1,1327 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qabstractspinbox_p.h>
+#include <qspinbox.h>
+
+#ifndef QT_NO_SPINBOX
+
+#include <qlineedit.h>
+#include <qlocale.h>
+#include <qvalidator.h>
+#include <qdebug.h>
+
+#include <math.h>
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QSPINBOX_QSBDEBUG
+#ifdef QSPINBOX_QSBDEBUG
+# define QSBDEBUG qDebug
+#else
+# define QSBDEBUG if (false) qDebug
+#endif
+
+class QSpinBoxPrivate : public QAbstractSpinBoxPrivate
+{
+ Q_DECLARE_PUBLIC(QSpinBox)
+public:
+ QSpinBoxPrivate();
+ void emitSignals(EmitPolicy ep, const QVariant &);
+
+ virtual QVariant valueFromText(const QString &n) const;
+ virtual QString textFromValue(const QVariant &n) const;
+ QVariant validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const;
+
+ inline void init() {
+ Q_Q(QSpinBox);
+ q->setInputMethodHints(Qt::ImhDigitsOnly);
+ setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
+ }
+};
+
+class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate
+{
+ Q_DECLARE_PUBLIC(QDoubleSpinBox)
+public:
+ QDoubleSpinBoxPrivate();
+ void emitSignals(EmitPolicy ep, const QVariant &);
+
+ virtual QVariant valueFromText(const QString &n) const;
+ virtual QString textFromValue(const QVariant &n) const;
+ QVariant validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const;
+ double round(double input) const;
+ // variables
+ int decimals;
+
+ inline void init() {
+ Q_Q(QDoubleSpinBox);
+ q->setInputMethodHints(Qt::ImhFormattedNumbersOnly);
+ }
+
+ // When fiddling with the decimals property, we may lose precision in these properties.
+ double actualMin;
+ double actualMax;
+};
+
+
+/*!
+ \class QSpinBox
+ \brief The QSpinBox class provides a spin box widget.
+
+ \ingroup basicwidgets
+
+
+ QSpinBox is designed to handle integers and discrete sets of
+ values (e.g., month names); use QDoubleSpinBox for floating point
+ values.
+
+ QSpinBox allows the user to choose a value by clicking the up/down
+ buttons or pressing up/down on the keyboard to increase/decrease
+ the value currently displayed. The user can also type the value in
+ manually. The spin box supports integer values but can be extended to
+ use different strings with validate(), textFromValue() and valueFromText().
+
+ Every time the value changes QSpinBox emits the valueChanged()
+ signals. The current value can be fetched with value() and set
+ with setValue().
+
+ Clicking the up/down buttons or using the keyboard accelerator's
+ up and down arrows will increase or decrease the current value in
+ steps of size singleStep(). If you want to change this behaviour you
+ can reimplement the virtual function stepBy(). The minimum and
+ maximum value and the step size can be set using one of the
+ constructors, and can be changed later with setMinimum(),
+ setMaximum() and setSingleStep().
+
+ Most spin boxes are directional, but QSpinBox can also operate as
+ a circular spin box, i.e. if the range is 0-99 and the current
+ value is 99, clicking "up" will give 0 if wrapping() is set to
+ true. Use setWrapping() if you want circular behavior.
+
+ The displayed value can be prepended and appended with arbitrary
+ strings indicating, for example, currency or the unit of
+ measurement. See setPrefix() and setSuffix(). The text in the spin
+ box is retrieved with text() (which includes any prefix() and
+ suffix()), or with cleanText() (which has no prefix(), no suffix()
+ and no leading or trailing whitespace).
+
+ It is often desirable to give the user a special (often default)
+ choice in addition to the range of numeric values. See
+ setSpecialValueText() for how to do this with QSpinBox.
+
+ \table 100%
+ \row \o \inlineimage windowsxp-spinbox.png Screenshot of a Windows XP spin box
+ \o A spin box shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-spinbox.png Screenshot of a Plastique spin box
+ \o A spin box shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \row \o \inlineimage macintosh-spinbox.png Screenshot of a Macintosh spin box
+ \o A spin box shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \endtable
+
+ \section1 Subclassing QSpinBox
+
+ If using prefix(), suffix(), and specialValueText() don't provide
+ enough control, you subclass QSpinBox and reimplement
+ valueFromText() and textFromValue(). For example, here's the code
+ for a custom spin box that allows the user to enter icon sizes
+ (e.g., "32 x 32"):
+
+ \snippet examples/widgets/icons/iconsizespinbox.cpp 1
+ \codeline
+ \snippet examples/widgets/icons/iconsizespinbox.cpp 2
+
+ See the \l{widgets/icons}{Icons} example for the full source
+ code.
+
+ \sa QDoubleSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
+*/
+
+/*!
+ \fn void QSpinBox::valueChanged(int i)
+
+ This signal is emitted whenever the spin box's value is changed.
+ The new value's integer value is passed in \a i.
+*/
+
+/*!
+ \fn void QSpinBox::valueChanged(const QString &text)
+
+ \overload
+
+ The new value is passed literally in \a text with no prefix() or
+ suffix().
+*/
+
+/*!
+ Constructs a spin box with 0 as minimum value and 99 as maximum value, a
+ step value of 1. The value is initially set to 0. It is parented to \a
+ parent.
+
+ \sa setMinimum(), setMaximum(), setSingleStep()
+*/
+
+QSpinBox::QSpinBox(QWidget *parent)
+ : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
+{
+ Q_D(QSpinBox);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QSpinBox::QSpinBox(QWidget *parent, const char *name)
+ : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
+{
+ Q_D(QSpinBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QSpinBox::QSpinBox(int minimum, int maximum, int step, QWidget *parent, const char *name)
+ : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
+{
+ Q_D(QSpinBox);
+ d->minimum = QVariant(qMin<int>(minimum, maximum));
+ d->maximum = QVariant(qMax<int>(minimum, maximum));
+ d->singleStep = QVariant(step);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+#endif
+
+/*!
+ \property QSpinBox::value
+ \brief the value of the spin box
+
+ setValue() will emit valueChanged() if the new value is different
+ from the old one.
+*/
+
+int QSpinBox::value() const
+{
+ Q_D(const QSpinBox);
+ return d->value.toInt();
+}
+
+void QSpinBox::setValue(int value)
+{
+ Q_D(QSpinBox);
+ d->setValue(QVariant(value), EmitIfChanged);
+}
+
+/*!
+ \property QSpinBox::prefix
+ \brief the spin box's prefix
+
+ The prefix is prepended to the start of the displayed value.
+ Typical use is to display a unit of measurement or a currency
+ symbol. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 0
+
+ To turn off the prefix display, set this property to an empty
+ string. The default is no prefix. The prefix is not displayed when
+ value() == minimum() and specialValueText() is set.
+
+ If no prefix is set, prefix() returns an empty string.
+
+ \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QSpinBox::prefix() const
+{
+ Q_D(const QSpinBox);
+ return d->prefix;
+}
+
+void QSpinBox::setPrefix(const QString &prefix)
+{
+ Q_D(QSpinBox);
+
+ d->prefix = prefix;
+ d->updateEdit();
+
+ d->cachedSizeHint = QSize();
+ updateGeometry();
+}
+
+/*!
+ \property QSpinBox::suffix
+ \brief the suffix of the spin box
+
+ The suffix is appended to the end of the displayed value. Typical
+ use is to display a unit of measurement or a currency symbol. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 1
+
+ To turn off the suffix display, set this property to an empty
+ string. The default is no suffix. The suffix is not displayed for
+ the minimum() if specialValueText() is set.
+
+ If no suffix is set, suffix() returns an empty string.
+
+ \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QSpinBox::suffix() const
+{
+ Q_D(const QSpinBox);
+
+ return d->suffix;
+}
+
+void QSpinBox::setSuffix(const QString &suffix)
+{
+ Q_D(QSpinBox);
+
+ d->suffix = suffix;
+ d->updateEdit();
+
+ d->cachedSizeHint = QSize();
+ updateGeometry();
+}
+
+/*!
+ \property QSpinBox::cleanText
+
+ \brief the text of the spin box excluding any prefix, suffix,
+ or leading or trailing whitespace.
+
+ \sa text, QSpinBox::prefix, QSpinBox::suffix
+*/
+
+QString QSpinBox::cleanText() const
+{
+ Q_D(const QSpinBox);
+
+ return d->stripped(d->edit->displayText());
+}
+
+
+/*!
+ \property QSpinBox::singleStep
+ \brief the step value
+
+ When the user uses the arrows to change the spin box's value the
+ value will be incremented/decremented by the amount of the
+ singleStep. The default value is 1. Setting a singleStep value of
+ less than 0 does nothing.
+*/
+
+int QSpinBox::singleStep() const
+{
+ Q_D(const QSpinBox);
+
+ return d->singleStep.toInt();
+}
+
+void QSpinBox::setSingleStep(int value)
+{
+ Q_D(QSpinBox);
+ if (value >= 0) {
+ d->singleStep = QVariant(value);
+ d->updateEdit();
+ }
+}
+
+/*!
+ \property QSpinBox::minimum
+
+ \brief the minimum value of the spin box
+
+ When setting this property the \l maximum is adjusted
+ if necessary to ensure that the range remains valid.
+
+ The default minimum value is 0.
+
+ \sa setRange() specialValueText
+*/
+
+int QSpinBox::minimum() const
+{
+ Q_D(const QSpinBox);
+
+ return d->minimum.toInt();
+}
+
+void QSpinBox::setMinimum(int minimum)
+{
+ Q_D(QSpinBox);
+ const QVariant m(minimum);
+ d->setRange(m, (d->variantCompare(d->maximum, m) > 0 ? d->maximum : m));
+}
+
+/*!
+ \property QSpinBox::maximum
+
+ \brief the maximum value of the spin box
+
+ When setting this property the \l minimum is adjusted
+ if necessary, to ensure that the range remains valid.
+
+ The default maximum value is 99.
+
+ \sa setRange() specialValueText
+
+*/
+
+int QSpinBox::maximum() const
+{
+ Q_D(const QSpinBox);
+
+ return d->maximum.toInt();
+}
+
+void QSpinBox::setMaximum(int maximum)
+{
+ Q_D(QSpinBox);
+ const QVariant m(maximum);
+ d->setRange((d->variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
+}
+
+/*!
+ Convenience function to set the \a minimum, and \a maximum values
+ with a single function call.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 2
+ is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 3
+
+ \sa minimum maximum
+*/
+
+void QSpinBox::setRange(int minimum, int maximum)
+{
+ Q_D(QSpinBox);
+ d->setRange(QVariant(minimum), QVariant(maximum));
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ display the given \a value. The default implementation returns a
+ string containing \a value printed in the standard way using
+ QWidget::locale().toString(), but with the thousand separator
+ removed. Reimplementations may return anything. (See the example
+ in the detailed description.)
+
+ Note: QSpinBox does not call this function for specialValueText()
+ and that neither prefix() nor suffix() should be included in the
+ return value.
+
+ If you reimplement this, you may also need to reimplement
+ valueFromText() and validate()
+
+ \sa valueFromText(), validate(), QLocale::groupSeparator()
+*/
+
+QString QSpinBox::textFromValue(int value) const
+{
+ QString str = locale().toString(value);
+ if (qAbs(value) >= 1000 || value == INT_MIN) {
+ str.remove(locale().groupSeparator());
+ }
+
+ return str;
+}
+
+/*!
+ \fn int QSpinBox::valueFromText(const QString &text) const
+
+ This virtual function is used by the spin box whenever it needs to
+ interpret \a text entered by the user as a value.
+
+ Subclasses that need to display spin box values in a non-numeric
+ way need to reimplement this function.
+
+ Note: QSpinBox handles specialValueText() separately; this
+ function is only concerned with the other values.
+
+ \sa textFromValue(), validate()
+*/
+
+int QSpinBox::valueFromText(const QString &text) const
+{
+ Q_D(const QSpinBox);
+
+ QString copy = text;
+ int pos = d->edit->cursorPosition();
+ QValidator::State state = QValidator::Acceptable;
+ return d->validateAndInterpret(copy, pos, state).toInt();
+}
+
+/*!
+ \reimp
+*/
+QValidator::State QSpinBox::validate(QString &text, int &pos) const
+{
+ Q_D(const QSpinBox);
+
+ QValidator::State state;
+ d->validateAndInterpret(text, pos, state);
+ return state;
+}
+
+
+/*!
+ \reimp
+*/
+void QSpinBox::fixup(QString &input) const
+{
+ input.remove(locale().groupSeparator());
+}
+
+
+// --- QDoubleSpinBox ---
+
+/*!
+ \class QDoubleSpinBox
+ \brief The QDoubleSpinBox class provides a spin box widget that
+ takes doubles.
+
+ \ingroup basicwidgets
+
+
+ QDoubleSpinBox allows the user to choose a value by clicking the
+ up and down buttons or by pressing Up or Down on the keyboard to
+ increase or decrease the value currently displayed. The user can
+ also type the value in manually. The spin box supports double
+ values but can be extended to use different strings with
+ validate(), textFromValue() and valueFromText().
+
+ Every time the value changes QDoubleSpinBox emits the
+ valueChanged() signal. The current value can be fetched with
+ value() and set with setValue().
+
+ Note: QDoubleSpinBox will round numbers so they can be displayed
+ with the current precision. In a QDoubleSpinBox with decimals set
+ to 2, calling setValue(2.555) will cause value() to return 2.56.
+
+ Clicking the up and down buttons or using the keyboard accelerator's
+ Up and Down arrows will increase or decrease the current value in
+ steps of size singleStep(). If you want to change this behavior you
+ can reimplement the virtual function stepBy(). The minimum and
+ maximum value and the step size can be set using one of the
+ constructors, and can be changed later with setMinimum(),
+ setMaximum() and setSingleStep(). The spinbox has a default
+ precision of 2 decimal places but this can be changed using
+ setDecimals().
+
+ Most spin boxes are directional, but QDoubleSpinBox can also
+ operate as a circular spin box, i.e. if the range is 0.0-99.9 and
+ the current value is 99.9, clicking "up" will give 0 if wrapping()
+ is set to true. Use setWrapping() if you want circular behavior.
+
+ The displayed value can be prepended and appended with arbitrary
+ strings indicating, for example, currency or the unit of
+ measurement. See setPrefix() and setSuffix(). The text in the spin
+ box is retrieved with text() (which includes any prefix() and
+ suffix()), or with cleanText() (which has no prefix(), no suffix()
+ and no leading or trailing whitespace).
+
+ It is often desirable to give the user a special (often default)
+ choice in addition to the range of numeric values. See
+ setSpecialValueText() for how to do this with QDoubleSpinBox.
+
+ \sa QSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
+*/
+
+/*!
+ \fn void QDoubleSpinBox::valueChanged(double d);
+
+ This signal is emitted whenever the spin box's value is changed.
+ The new value is passed in \a d.
+*/
+
+/*!
+ \fn void QDoubleSpinBox::valueChanged(const QString &text);
+
+ \overload
+
+ The new value is passed literally in \a text with no prefix() or
+ suffix().
+*/
+
+/*!
+ Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
+ a step value of 1.0 and a precision of 2 decimal places. The value is
+ initially set to 0.00. The spin box has the given \a parent.
+
+ \sa setMinimum(), setMaximum(), setSingleStep()
+*/
+QDoubleSpinBox::QDoubleSpinBox(QWidget *parent)
+ : QAbstractSpinBox(*new QDoubleSpinBoxPrivate, parent)
+{
+ Q_D(QDoubleSpinBox);
+ d->init();
+}
+
+/*!
+ \property QDoubleSpinBox::value
+ \brief the value of the spin box
+
+ setValue() will emit valueChanged() if the new value is different
+ from the old one.
+
+ Note: The value will be rounded so it can be displayed with the
+ current setting of decimals.
+
+ \sa decimals
+*/
+double QDoubleSpinBox::value() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->value.toDouble();
+}
+
+void QDoubleSpinBox::setValue(double value)
+{
+ Q_D(QDoubleSpinBox);
+ QVariant v(d->round(value));
+ d->setValue(v, EmitIfChanged);
+}
+/*!
+ \property QDoubleSpinBox::prefix
+ \brief the spin box's prefix
+
+ The prefix is prepended to the start of the displayed value.
+ Typical use is to display a unit of measurement or a currency
+ symbol. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 4
+
+ To turn off the prefix display, set this property to an empty
+ string. The default is no prefix. The prefix is not displayed when
+ value() == minimum() and specialValueText() is set.
+
+ If no prefix is set, prefix() returns an empty string.
+
+ \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QDoubleSpinBox::prefix() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->prefix;
+}
+
+void QDoubleSpinBox::setPrefix(const QString &prefix)
+{
+ Q_D(QDoubleSpinBox);
+
+ d->prefix = prefix;
+ d->updateEdit();
+}
+
+/*!
+ \property QDoubleSpinBox::suffix
+ \brief the suffix of the spin box
+
+ The suffix is appended to the end of the displayed value. Typical
+ use is to display a unit of measurement or a currency symbol. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 5
+
+ To turn off the suffix display, set this property to an empty
+ string. The default is no suffix. The suffix is not displayed for
+ the minimum() if specialValueText() is set.
+
+ If no suffix is set, suffix() returns an empty string.
+
+ \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QDoubleSpinBox::suffix() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->suffix;
+}
+
+void QDoubleSpinBox::setSuffix(const QString &suffix)
+{
+ Q_D(QDoubleSpinBox);
+
+ d->suffix = suffix;
+ d->updateEdit();
+
+ d->cachedSizeHint = QSize();
+ updateGeometry();
+}
+
+/*!
+ \property QDoubleSpinBox::cleanText
+
+ \brief the text of the spin box excluding any prefix, suffix,
+ or leading or trailing whitespace.
+
+ \sa text, QDoubleSpinBox::prefix, QDoubleSpinBox::suffix
+*/
+
+QString QDoubleSpinBox::cleanText() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->stripped(d->edit->displayText());
+}
+
+/*!
+ \property QDoubleSpinBox::singleStep
+ \brief the step value
+
+ When the user uses the arrows to change the spin box's value the
+ value will be incremented/decremented by the amount of the
+ singleStep. The default value is 1.0. Setting a singleStep value
+ of less than 0 does nothing.
+*/
+double QDoubleSpinBox::singleStep() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->singleStep.toDouble();
+}
+
+void QDoubleSpinBox::setSingleStep(double value)
+{
+ Q_D(QDoubleSpinBox);
+
+ if (value >= 0) {
+ d->singleStep = value;
+ d->updateEdit();
+ }
+}
+
+/*!
+ \property QDoubleSpinBox::minimum
+
+ \brief the minimum value of the spin box
+
+ When setting this property the \l maximum is adjusted
+ if necessary to ensure that the range remains valid.
+
+ The default minimum value is 0.0.
+
+ Note: The minimum value will be rounded to match the decimals
+ property.
+
+ \sa decimals, setRange() specialValueText
+*/
+
+double QDoubleSpinBox::minimum() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->minimum.toDouble();
+}
+
+void QDoubleSpinBox::setMinimum(double minimum)
+{
+ Q_D(QDoubleSpinBox);
+ d->actualMin = minimum;
+ const QVariant m(d->round(minimum));
+ d->setRange(m, (d->variantCompare(d->maximum, m) > 0 ? d->maximum : m));
+}
+
+/*!
+ \property QDoubleSpinBox::maximum
+
+ \brief the maximum value of the spin box
+
+ When setting this property the \l minimum is adjusted
+ if necessary, to ensure that the range remains valid.
+
+ The default maximum value is 99.99.
+
+ Note: The maximum value will be rounded to match the decimals
+ property.
+
+ \sa decimals, setRange()
+*/
+
+double QDoubleSpinBox::maximum() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->maximum.toDouble();
+}
+
+void QDoubleSpinBox::setMaximum(double maximum)
+{
+ Q_D(QDoubleSpinBox);
+ d->actualMax = maximum;
+ const QVariant m(d->round(maximum));
+ d->setRange((d->variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
+}
+
+/*!
+ Convenience function to set the \a minimum and \a maximum values
+ with a single function call.
+
+ Note: The maximum and minimum values will be rounded to match the
+ decimals property.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 6
+ is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 7
+
+ \sa minimum maximum
+*/
+
+void QDoubleSpinBox::setRange(double minimum, double maximum)
+{
+ Q_D(QDoubleSpinBox);
+ d->actualMin = minimum;
+ d->actualMax = maximum;
+ d->setRange(QVariant(d->round(minimum)), QVariant(d->round(maximum)));
+}
+
+/*!
+ \property QDoubleSpinBox::decimals
+
+ \brief the precision of the spin box, in decimals
+
+ Sets how many decimals the spinbox will use for displaying and
+ interpreting doubles.
+
+ \warning The maximum value for \a decimals is DBL_MAX_10_EXP +
+ DBL_DIG (ie. 323) because of the limitations of the double type.
+
+ Note: The maximum, minimum and value might change as a result of
+ changing this property.
+*/
+
+int QDoubleSpinBox::decimals() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->decimals;
+}
+
+void QDoubleSpinBox::setDecimals(int decimals)
+{
+ Q_D(QDoubleSpinBox);
+ d->decimals = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG);
+
+ setRange(d->actualMin, d->actualMax); // make sure values are rounded
+ setValue(value());
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ display the given \a value. The default implementation returns a string
+ containing \a value printed using QWidget::locale().toString(\a value,
+ QLatin1Char('f'), decimals()) and will remove the thousand
+ separator. Reimplementations may return anything.
+
+ Note: QDoubleSpinBox does not call this function for
+ specialValueText() and that neither prefix() nor suffix() should
+ be included in the return value.
+
+ If you reimplement this, you may also need to reimplement
+ valueFromText().
+
+ \sa valueFromText(), QLocale::groupSeparator()
+*/
+
+
+QString QDoubleSpinBox::textFromValue(double value) const
+{
+ Q_D(const QDoubleSpinBox);
+ QString str = locale().toString(value, 'f', d->decimals);
+ if (qAbs(value) >= 1000.0) {
+ str.remove(locale().groupSeparator());
+ }
+ return str;
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ interpret \a text entered by the user as a value.
+
+ Subclasses that need to display spin box values in a non-numeric
+ way need to reimplement this function.
+
+ Note: QDoubleSpinBox handles specialValueText() separately; this
+ function is only concerned with the other values.
+
+ \sa textFromValue(), validate()
+*/
+double QDoubleSpinBox::valueFromText(const QString &text) const
+{
+ Q_D(const QDoubleSpinBox);
+
+ QString copy = text;
+ int pos = d->edit->cursorPosition();
+ QValidator::State state = QValidator::Acceptable;
+ return d->validateAndInterpret(copy, pos, state).toDouble();
+}
+
+/*!
+ \reimp
+*/
+QValidator::State QDoubleSpinBox::validate(QString &text, int &pos) const
+{
+ Q_D(const QDoubleSpinBox);
+
+ QValidator::State state;
+ d->validateAndInterpret(text, pos, state);
+ return state;
+}
+
+
+/*!
+ \reimp
+*/
+void QDoubleSpinBox::fixup(QString &input) const
+{
+ input.remove(locale().groupSeparator());
+}
+
+// --- QSpinBoxPrivate ---
+
+/*!
+ \internal
+ Constructs a QSpinBoxPrivate object
+*/
+
+QSpinBoxPrivate::QSpinBoxPrivate()
+{
+ minimum = QVariant((int)0);
+ maximum = QVariant((int)99);
+ value = minimum;
+ singleStep = QVariant((int)1);
+ type = QVariant::Int;
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+void QSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
+{
+ Q_Q(QSpinBox);
+ if (ep != NeverEmit) {
+ pendingEmit = false;
+ if (ep == AlwaysEmit || value != old) {
+ emit q->valueChanged(edit->displayText());
+ emit q->valueChanged(value.toInt());
+ }
+ }
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+QString QSpinBoxPrivate::textFromValue(const QVariant &value) const
+{
+ Q_Q(const QSpinBox);
+ return q->textFromValue(value.toInt());
+}
+/*!
+ \internal
+ \reimp
+*/
+
+QVariant QSpinBoxPrivate::valueFromText(const QString &text) const
+{
+ Q_Q(const QSpinBox);
+
+ return QVariant(q->valueFromText(text));
+}
+
+
+/*!
+ \internal Multi purpose function that parses input, sets state to
+ the appropriate state and returns the value it will be interpreted
+ as.
+*/
+
+QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const
+{
+ if (cachedText == input && !input.isEmpty()) {
+ state = cachedState;
+ QSBDEBUG() << "cachedText was '" << cachedText << "' state was "
+ << state << " and value was " << cachedValue;
+
+ return cachedValue;
+ }
+ const int max = maximum.toInt();
+ const int min = minimum.toInt();
+
+ QString copy = stripped(input, &pos);
+ QSBDEBUG() << "input" << input << "copy" << copy;
+ state = QValidator::Acceptable;
+ int num = min;
+
+ if (max != min && (copy.isEmpty()
+ || (min < 0 && copy == QLatin1String("-"))
+ || (min >= 0 && copy == QLatin1String("+")))) {
+ state = QValidator::Intermediate;
+ QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
+ } else if (copy.startsWith(QLatin1Char('-')) && min >= 0) {
+ state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100
+ } else {
+ bool ok = false;
+ num = locale.toInt(copy, &ok, 10);
+ if (!ok && copy.contains(locale.groupSeparator()) && (max >= 1000 || min <= -1000)) {
+ QString copy2 = copy;
+ copy2.remove(locale.groupSeparator());
+ num = locale.toInt(copy2, &ok, 10);
+ }
+ QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
+ if (!ok) {
+ state = QValidator::Invalid;
+ } else if (num >= min && num <= max) {
+ state = QValidator::Acceptable;
+ } else if (max == min) {
+ state = QValidator::Invalid;
+ } else {
+ if ((num >= 0 && num > max) || (num < 0 && num < min)) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ state = QValidator::Intermediate;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate";
+ }
+ }
+ }
+ if (state != QValidator::Acceptable)
+ num = max > 0 ? min : max;
+ input = prefix + copy + suffix;
+ cachedText = input;
+ cachedState = state;
+ cachedValue = QVariant((int)num);
+
+ QSBDEBUG() << "cachedText is set to '" << cachedText << "' state is set to "
+ << state << " and value is set to " << cachedValue;
+ return cachedValue;
+}
+
+// --- QDoubleSpinBoxPrivate ---
+
+/*!
+ \internal
+ Constructs a QSpinBoxPrivate object
+*/
+
+QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate()
+{
+ actualMin = 0.0;
+ actualMax = 99.99;
+ minimum = QVariant(actualMin);
+ maximum = QVariant(actualMax);
+ value = minimum;
+ singleStep = QVariant(1.0);
+ decimals = 2;
+ type = QVariant::Double;
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+void QDoubleSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
+{
+ Q_Q(QDoubleSpinBox);
+ if (ep != NeverEmit) {
+ pendingEmit = false;
+ if (ep == AlwaysEmit || value != old) {
+ emit q->valueChanged(edit->displayText());
+ emit q->valueChanged(value.toDouble());
+ }
+ }
+}
+
+
+/*!
+ \internal
+ \reimp
+*/
+QVariant QDoubleSpinBoxPrivate::valueFromText(const QString &f) const
+{
+ Q_Q(const QDoubleSpinBox);
+ return QVariant(q->valueFromText(f));
+}
+
+/*!
+ \internal
+ Rounds to a double value that is restricted to decimals.
+ E.g. // decimals = 2
+
+ round(5.555) => 5.56
+ */
+
+double QDoubleSpinBoxPrivate::round(double value) const
+{
+ return QString::number(value, 'f', decimals).toDouble();
+}
+
+
+/*!
+ \internal Multi purpose function that parses input, sets state to
+ the appropriate state and returns the value it will be interpreted
+ as.
+*/
+
+QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const
+{
+ if (cachedText == input && !input.isEmpty()) {
+ state = cachedState;
+ QSBDEBUG() << "cachedText was '" << cachedText << "' state was "
+ << state << " and value was " << cachedValue;
+ return cachedValue;
+ }
+ const double max = maximum.toDouble();
+ const double min = minimum.toDouble();
+
+ QString copy = stripped(input, &pos);
+ QSBDEBUG() << "input" << input << "copy" << copy;
+ int len = copy.size();
+ double num = min;
+ const bool plus = max >= 0;
+ const bool minus = min <= 0;
+
+ switch (len) {
+ case 0:
+ state = max != min ? QValidator::Intermediate : QValidator::Invalid;
+ goto end;
+ case 1:
+ if (copy.at(0) == locale.decimalPoint()
+ || (plus && copy.at(0) == QLatin1Char('+'))
+ || (minus && copy.at(0) == QLatin1Char('-'))) {
+ state = QValidator::Intermediate;
+ goto end;
+ }
+ break;
+ case 2:
+ if (copy.at(1) == locale.decimalPoint()
+ && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) {
+ state = QValidator::Intermediate;
+ goto end;
+ }
+ break;
+ default: break;
+ }
+
+ if (copy.at(0) == locale.groupSeparator()) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ } else if (len > 1) {
+ const int dec = copy.indexOf(locale.decimalPoint());
+ if (dec != -1) {
+ if (dec + 1 < copy.size() && copy.at(dec + 1) == locale.decimalPoint() && pos == dec + 1) {
+ copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter
+ } // should be treated as typing right arrow
+
+ if (copy.size() - dec > decimals + 1) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ for (int i=dec + 1; i<copy.size(); ++i) {
+ if (copy.at(i).isSpace() || copy.at(i) == locale.groupSeparator()) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ }
+ } else {
+ const QChar &last = copy.at(len - 1);
+ const QChar &secondLast = copy.at(len - 2);
+ if ((last == locale.groupSeparator() || last.isSpace())
+ && (secondLast == locale.groupSeparator() || secondLast.isSpace())) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ } else if (last.isSpace() && (!locale.groupSeparator().isSpace() || secondLast.isSpace())) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+ }
+ }
+
+ {
+ bool ok = false;
+ num = locale.toDouble(copy, &ok);
+ QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok;
+
+ if (!ok) {
+ if (locale.groupSeparator().isPrint()) {
+ if (max < 1000 && min > -1000 && copy.contains(locale.groupSeparator())) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+
+ const int len = copy.size();
+ for (int i=0; i<len- 1; ++i) {
+ if (copy.at(i) == locale.groupSeparator() && copy.at(i + 1) == locale.groupSeparator()) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ }
+
+ QString copy2 = copy;
+ copy2.remove(locale.groupSeparator());
+ num = locale.toDouble(copy2, &ok);
+ QSBDEBUG() << locale.groupSeparator() << num << copy2 << ok;
+
+ if (!ok) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+ }
+ }
+
+ if (!ok) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else if (num >= min && num <= max) {
+ state = QValidator::Acceptable;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Acceptable";
+ } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ if ((num >= 0 && num > max) || (num < 0 && num < min)) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ state = QValidator::Intermediate;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate";
+ }
+ }
+ }
+
+end:
+ if (state != QValidator::Acceptable) {
+ num = max > 0 ? min : max;
+ }
+
+ input = prefix + copy + suffix;
+ cachedText = input;
+ cachedState = state;
+ cachedValue = QVariant(num);
+ return QVariant(num);
+}
+
+/*
+ \internal
+ \reimp
+*/
+
+QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const
+{
+ Q_Q(const QDoubleSpinBox);
+ return q->textFromValue(f.toDouble());
+}
+
+/*!
+ \fn void QSpinBox::setLineStep(int step)
+
+ Use setSingleStep() instead.
+*/
+
+/*!
+ \fn void QSpinBox::setMaxValue(int value)
+
+ Use setMaximum() instead.
+*/
+
+/*!
+ \fn void QSpinBox::setMinValue(int value)
+
+ Use setMinimum() instead.
+*/
+
+/*!
+ \fn int QSpinBox::maxValue() const
+
+ Use maximum() instead.
+*/
+
+/*!
+ \fn int QSpinBox::minValue() const
+
+ Use minimum() instead.
+*/
+
+/*! \reimp */
+bool QSpinBox::event(QEvent *event)
+{
+ Q_D(QSpinBox);
+ if (event->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || event->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
+ return QAbstractSpinBox::event(event);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SPINBOX
diff --git a/src/widgets/widgets/qspinbox.h b/src/widgets/widgets/qspinbox.h
new file mode 100644
index 0000000000..1421b1d6d2
--- /dev/null
+++ b/src/widgets/widgets/qspinbox.h
@@ -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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPINBOX_H
+#define QSPINBOX_H
+
+#include <QtWidgets/qabstractspinbox.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SPINBOX
+
+class QSpinBoxPrivate;
+class Q_WIDGETS_EXPORT QSpinBox : public QAbstractSpinBox
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
+ Q_PROPERTY(QString prefix READ prefix WRITE setPrefix)
+ Q_PROPERTY(QString cleanText READ cleanText)
+ Q_PROPERTY(int minimum READ minimum WRITE setMinimum)
+ Q_PROPERTY(int maximum READ maximum WRITE setMaximum)
+ Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep)
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true)
+
+public:
+ explicit QSpinBox(QWidget *parent = 0);
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QSpinBox(QWidget *parent, const char *name);
+ QT3_SUPPORT_CONSTRUCTOR QSpinBox(int min, int max, int step, QWidget *parent,
+ const char *name = 0);
+#endif
+
+ int value() const;
+
+ QString prefix() const;
+ void setPrefix(const QString &prefix);
+
+ QString suffix() const;
+ void setSuffix(const QString &suffix);
+
+ QString cleanText() const;
+
+ int singleStep() const;
+ void setSingleStep(int val);
+
+ int minimum() const;
+ void setMinimum(int min);
+
+ int maximum() const;
+ void setMaximum(int max);
+
+ void setRange(int min, int max);
+
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT void setLineStep(int step) { setSingleStep(step); }
+ inline QT3_SUPPORT void setMaxValue(int val) { setMaximum(val); }
+ inline QT3_SUPPORT void setMinValue(int val) { setMinimum(val); }
+ inline QT3_SUPPORT int maxValue() const { return maximum(); }
+ inline QT3_SUPPORT int minValue() const { return minimum(); }
+#endif
+
+protected:
+ bool event(QEvent *event);
+ virtual QValidator::State validate(QString &input, int &pos) const;
+ virtual int valueFromText(const QString &text) const;
+ virtual QString textFromValue(int val) const;
+ virtual void fixup(QString &str) const;
+
+
+public Q_SLOTS:
+ void setValue(int val);
+
+Q_SIGNALS:
+ void valueChanged(int);
+ void valueChanged(const QString &);
+
+private:
+ Q_DISABLE_COPY(QSpinBox)
+ Q_DECLARE_PRIVATE(QSpinBox)
+};
+
+class QDoubleSpinBoxPrivate;
+class Q_WIDGETS_EXPORT QDoubleSpinBox : public QAbstractSpinBox
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString prefix READ prefix WRITE setPrefix)
+ Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
+ Q_PROPERTY(QString cleanText READ cleanText)
+ Q_PROPERTY(int decimals READ decimals WRITE setDecimals)
+ Q_PROPERTY(double minimum READ minimum WRITE setMinimum)
+ Q_PROPERTY(double maximum READ maximum WRITE setMaximum)
+ Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep)
+ Q_PROPERTY(double value READ value WRITE setValue NOTIFY valueChanged USER true)
+public:
+ explicit QDoubleSpinBox(QWidget *parent = 0);
+
+ double value() const;
+
+ QString prefix() const;
+ void setPrefix(const QString &prefix);
+
+ QString suffix() const;
+ void setSuffix(const QString &suffix);
+
+ QString cleanText() const;
+
+ double singleStep() const;
+ void setSingleStep(double val);
+
+ double minimum() const;
+ void setMinimum(double min);
+
+ double maximum() const;
+ void setMaximum(double max);
+
+ void setRange(double min, double max);
+
+ int decimals() const;
+ void setDecimals(int prec);
+
+ virtual QValidator::State validate(QString &input, int &pos) const;
+ virtual double valueFromText(const QString &text) const;
+ virtual QString textFromValue(double val) const;
+ virtual void fixup(QString &str) const;
+
+public Q_SLOTS:
+ void setValue(double val);
+
+Q_SIGNALS:
+ void valueChanged(double);
+ void valueChanged(const QString &);
+
+private:
+ Q_DISABLE_COPY(QDoubleSpinBox)
+ Q_DECLARE_PRIVATE(QDoubleSpinBox)
+};
+
+#endif // QT_NO_SPINBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSPINBOX_H
diff --git a/src/widgets/widgets/qsplashscreen.cpp b/src/widgets/widgets/qsplashscreen.cpp
new file mode 100644
index 0000000000..e051878db9
--- /dev/null
+++ b/src/widgets/widgets/qsplashscreen.cpp
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsplashscreen.h"
+
+#ifndef QT_NO_SPLASHSCREEN
+
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qtextdocument.h"
+#include "qtextcursor.h"
+#include <QtCore/qdebug.h>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSplashScreenPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QSplashScreen)
+public:
+ QPixmap pixmap;
+ QString currStatus;
+ QColor currColor;
+ int currAlign;
+
+ inline QSplashScreenPrivate();
+};
+
+/*!
+ \class QSplashScreen
+ \brief The QSplashScreen widget provides a splash screen that can
+ be shown during application startup.
+
+ A splash screen is a widget that is usually displayed when an
+ application is being started. Splash screens are often used for
+ applications that have long start up times (e.g. database or
+ networking applications that take time to establish connections) to
+ provide the user with feedback that the application is loading.
+
+ The splash screen appears in the center of the screen. It may be
+ useful to add the Qt::WindowStaysOnTopHint to the splash widget's
+ window flags if you want to keep it above all the other windows on
+ the desktop.
+
+ Some X11 window managers do not support the "stays on top" flag. A
+ solution is to set up a timer that periodically calls raise() on
+ the splash screen to simulate the "stays on top" effect.
+
+ The most common usage is to show a splash screen before the main
+ widget is displayed on the screen. This is illustrated in the
+ following code snippet in which a splash screen is displayed and
+ some initialization tasks are performed before the application's
+ main window is shown:
+
+ \snippet doc/src/snippets/qsplashscreen/main.cpp 0
+ \dots
+ \snippet doc/src/snippets/qsplashscreen/main.cpp 1
+
+ The user can hide the splash screen by clicking on it with the
+ mouse. Since the splash screen is typically displayed before the
+ event loop has started running, it is necessary to periodically
+ call QApplication::processEvents() to receive the mouse clicks.
+
+ It is sometimes useful to update the splash screen with messages,
+ for example, announcing connections established or modules loaded
+ as the application starts up:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qsplashscreen.cpp 0
+
+ QSplashScreen supports this with the showMessage() function. If you
+ wish to do your own drawing you can get a pointer to the pixmap
+ used in the splash screen with pixmap(). Alternatively, you can
+ subclass QSplashScreen and reimplement drawContents().
+*/
+
+/*!
+ Construct a splash screen that will display the \a pixmap.
+
+ There should be no need to set the widget flags, \a f, except
+ perhaps Qt::WindowStaysOnTopHint.
+*/
+QSplashScreen::QSplashScreen(const QPixmap &pixmap, Qt::WindowFlags f)
+ : QWidget(*(new QSplashScreenPrivate()), 0, Qt::SplashScreen | Qt::FramelessWindowHint | f)
+{
+ setPixmap(pixmap); // Does an implicit repaint
+}
+
+/*!
+ \overload
+
+ This function allows you to specify a parent for your splashscreen. The
+ typical use for this constructor is if you have a multiple screens and
+ prefer to have the splash screen on a different screen than your primary
+ one. In that case pass the proper desktop() as the \a parent.
+*/
+QSplashScreen::QSplashScreen(QWidget *parent, const QPixmap &pixmap, Qt::WindowFlags f)
+ : QWidget(*new QSplashScreenPrivate, parent, Qt::SplashScreen | f)
+{
+ d_func()->pixmap = pixmap;
+ setPixmap(d_func()->pixmap); // Does an implicit repaint
+}
+
+/*!
+ Destructor.
+*/
+QSplashScreen::~QSplashScreen()
+{
+}
+
+/*!
+ \reimp
+*/
+void QSplashScreen::mousePressEvent(QMouseEvent *)
+{
+ hide();
+}
+
+/*!
+ This overrides QWidget::repaint(). It differs from the standard
+ repaint function in that it also calls QApplication::flush() to
+ ensure the updates are displayed, even when there is no event loop
+ present.
+*/
+void QSplashScreen::repaint()
+{
+ QWidget::repaint();
+ QApplication::flush();
+}
+
+/*!
+ \fn QSplashScreen::messageChanged(const QString &message)
+
+ This signal is emitted when the message on the splash screen
+ changes. \a message is the new message and is a null-string
+ when the message has been removed.
+
+ \sa showMessage(), clearMessage()
+*/
+
+
+
+/*!
+ Draws the \a message text onto the splash screen with color \a
+ color and aligns the text according to the flags in \a alignment.
+
+ To make sure the splash screen is repainted immediately, you can
+ call \l{QCoreApplication}'s
+ \l{QCoreApplication::}{processEvents()} after the call to
+ showMessage(). You usually want this to make sure that the message
+ is kept up to date with what your application is doing (e.g.,
+ loading files).
+
+ \sa Qt::Alignment, clearMessage()
+*/
+void QSplashScreen::showMessage(const QString &message, int alignment,
+ const QColor &color)
+{
+ Q_D(QSplashScreen);
+ d->currStatus = message;
+ d->currAlign = alignment;
+ d->currColor = color;
+ emit messageChanged(d->currStatus);
+ repaint();
+}
+
+/*!
+ Removes the message being displayed on the splash screen
+
+ \sa showMessage()
+ */
+void QSplashScreen::clearMessage()
+{
+ d_func()->currStatus.clear();
+ emit messageChanged(d_func()->currStatus);
+ repaint();
+}
+
+/*!
+ Makes the splash screen wait until the widget \a mainWin is displayed
+ before calling close() on itself.
+*/
+void QSplashScreen::finish(QWidget *mainWin)
+{
+ if (mainWin) {
+#if defined(Q_WS_X11)
+ extern void qt_x11_wait_for_window_manager(QWidget *mainWin, bool);
+ qt_x11_wait_for_window_manager(mainWin, false);
+#endif
+ }
+ close();
+}
+
+/*!
+ Sets the pixmap that will be used as the splash screen's image to
+ \a pixmap.
+*/
+void QSplashScreen::setPixmap(const QPixmap &pixmap)
+{
+ Q_D(QSplashScreen);
+
+ d->pixmap = pixmap;
+ setAttribute(Qt::WA_TranslucentBackground, pixmap.hasAlpha());
+
+ QRect r(QPoint(), d->pixmap.size());
+ resize(r.size());
+ move(QApplication::desktop()->screenGeometry().center() - r.center());
+ if (isVisible())
+ repaint();
+}
+
+/*!
+ Returns the pixmap that is used in the splash screen. The image
+ does not have any of the text drawn by showMessage() calls.
+*/
+const QPixmap QSplashScreen::pixmap() const
+{
+ return d_func()->pixmap;
+}
+
+/*!
+ \internal
+*/
+inline QSplashScreenPrivate::QSplashScreenPrivate() : currAlign(Qt::AlignLeft)
+{
+}
+
+/*!
+ Draw the contents of the splash screen using painter \a painter.
+ The default implementation draws the message passed by showMessage().
+ Reimplement this function if you want to do your own drawing on
+ the splash screen.
+*/
+void QSplashScreen::drawContents(QPainter *painter)
+{
+ Q_D(QSplashScreen);
+ painter->setPen(d->currColor);
+ QRect r = rect().adjusted(5, 5, -5, -5);
+ if (Qt::mightBeRichText(d->currStatus)) {
+ QTextDocument doc;
+#ifdef QT_NO_TEXTHTMLPARSER
+ doc.setPlainText(d->currStatus);
+#else
+ doc.setHtml(d->currStatus);
+#endif
+ doc.setTextWidth(r.width());
+ QTextCursor cursor(&doc);
+ cursor.select(QTextCursor::Document);
+ QTextBlockFormat fmt;
+ fmt.setAlignment(Qt::Alignment(d->currAlign));
+ cursor.mergeBlockFormat(fmt);
+ painter->save();
+ painter->translate(r.topLeft());
+ doc.drawContents(painter);
+ painter->restore();
+ } else {
+ painter->drawText(r, d->currAlign, d->currStatus);
+ }
+}
+
+/*! \reimp */
+bool QSplashScreen::event(QEvent *e)
+{
+ if (e->type() == QEvent::Paint) {
+ Q_D(QSplashScreen);
+ QPainter painter(this);
+ if (!d->pixmap.isNull())
+ painter.drawPixmap(QPoint(), d->pixmap);
+ drawContents(&painter);
+ }
+ return QWidget::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_SPLASHSCREEN
diff --git a/src/widgets/widgets/qsplashscreen.h b/src/widgets/widgets/qsplashscreen.h
new file mode 100644
index 0000000000..0faaa628c8
--- /dev/null
+++ b/src/widgets/widgets/qsplashscreen.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPLASHSCREEN_H
+#define QSPLASHSCREEN_H
+
+#include <QtGui/qpixmap.h>
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SPLASHSCREEN
+class QSplashScreenPrivate;
+
+class Q_WIDGETS_EXPORT QSplashScreen : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit QSplashScreen(const QPixmap &pixmap = QPixmap(), Qt::WindowFlags f = 0);
+ QSplashScreen(QWidget *parent, const QPixmap &pixmap = QPixmap(), Qt::WindowFlags f = 0);
+ virtual ~QSplashScreen();
+
+ void setPixmap(const QPixmap &pixmap);
+ const QPixmap pixmap() const;
+ void finish(QWidget *w);
+ void repaint();
+
+public Q_SLOTS:
+ void showMessage(const QString &message, int alignment = Qt::AlignLeft,
+ const QColor &color = Qt::black);
+ void clearMessage();
+#ifdef QT3_SUPPORT
+ inline QT_MOC_COMPAT void message(const QString &str, int alignment = Qt::AlignLeft,
+ const QColor &color = Qt::black) { showMessage(str, alignment, color); }
+ inline QT_MOC_COMPAT void clear() { clearMessage(); }
+#endif
+
+Q_SIGNALS:
+ void messageChanged(const QString &message);
+
+protected:
+ bool event(QEvent *e);
+ virtual void drawContents(QPainter *painter);
+ void mousePressEvent(QMouseEvent *);
+
+private:
+ Q_DISABLE_COPY(QSplashScreen)
+ Q_DECLARE_PRIVATE(QSplashScreen)
+};
+
+#endif // QT_NO_SPLASHSCREEN
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSPLASHSCREEN_H
diff --git a/src/widgets/widgets/qsplitter.cpp b/src/widgets/widgets/qsplitter.cpp
new file mode 100644
index 0000000000..5d5897311b
--- /dev/null
+++ b/src/widgets/widgets/qsplitter.cpp
@@ -0,0 +1,1862 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsplitter.h"
+#ifndef QT_NO_SPLITTER
+
+#include "qapplication.h"
+#include "qcursor.h"
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qlayout.h"
+#include "qlist.h"
+#include "qpainter.h"
+#include "qrubberband.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qtextstream.h"
+#include "qvarlengtharray.h"
+#include "qvector.h"
+#include "private/qlayoutengine_p.h"
+#include "private/qsplitter_p.h"
+#include "qtimer.h"
+#include "qdebug.h"
+
+#include <ctype.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QSPLITTER_DEBUG
+
+/*!
+ \class QSplitterHandle
+ \brief The QSplitterHandle class provides handle functionality of the splitter.
+
+ \ingroup organizers
+
+ QSplitterHandle is typically what people think about when they think about
+ a splitter. It is the handle that is used to resize the widgets.
+
+ A typical developer using QSplitter will never have to worry about
+ QSplitterHandle. It is provided for developers who want splitter handles
+ that provide extra features, such as popup menus.
+
+ The typical way one would create splitter handles is to subclass QSplitter then
+ reimplement QSplitter::createHandle() to instantiate the custom splitter
+ handle. For example, a minimum QSplitter subclass might look like this:
+
+ \snippet doc/src/snippets/splitterhandle/splitter.h 0
+
+ The \l{QSplitter::}{createHandle()} implementation simply constructs a
+ custom splitter handle, called \c Splitter in this example:
+
+ \snippet doc/src/snippets/splitterhandle/splitter.cpp 1
+
+ Information about a given handle can be obtained using functions like
+ orientation() and opaqueResize(), and is retrieved from its parent splitter.
+ Details like these can be used to give custom handles different appearances
+ depending on the splitter's orientation.
+
+ The complexity of a custom handle subclass depends on the tasks that it
+ needs to perform. A simple subclass might only provide a paintEvent()
+ implementation:
+
+ \snippet doc/src/snippets/splitterhandle/splitter.cpp 0
+
+ In this example, a predefined gradient is set up differently depending on
+ the orientation of the handle. QSplitterHandle provides a reasonable
+ size hint for the handle, so the subclass does not need to provide a
+ reimplementation of sizeHint() unless the handle has special size
+ requirements.
+
+ \sa QSplitter
+*/
+
+/*!
+ Creates a QSplitter handle with the given \a orientation and
+ QSplitter \a parent.
+*/
+QSplitterHandle::QSplitterHandle(Qt::Orientation orientation, QSplitter *parent)
+ : QWidget(*new QSplitterHandlePrivate, parent, 0)
+{
+ Q_D(QSplitterHandle);
+ d->s = parent;
+ setOrientation(orientation);
+}
+
+/*!
+ Sets the orientation of the splitter handle to \a orientation.
+ This is usually propagated from the QSplitter.
+
+ \sa QSplitter::setOrientation()
+*/
+void QSplitterHandle::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QSplitterHandle);
+ d->orient = orientation;
+#ifndef QT_NO_CURSOR
+ setCursor(orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
+#endif
+}
+
+/*!
+ Returns the handle's orientation. This is usually propagated from the QSplitter.
+
+ \sa QSplitter::orientation()
+*/
+Qt::Orientation QSplitterHandle::orientation() const
+{
+ Q_D(const QSplitterHandle);
+ return d->orient;
+}
+
+
+/*!
+ Returns true if widgets are resized dynamically (opaquely), otherwise
+ returns false. This value is controlled by the QSplitter.
+
+ \sa QSplitter::opaqueResize()
+
+*/
+bool QSplitterHandle::opaqueResize() const
+{
+ Q_D(const QSplitterHandle);
+ return d->s->opaqueResize();
+}
+
+
+/*!
+ Returns the splitter associated with this splitter handle.
+
+ \sa QSplitter::handle()
+*/
+QSplitter *QSplitterHandle::splitter() const
+{
+ return d_func()->s;
+}
+
+/*!
+ Tells the splitter to move this handle to position \a pos, which is
+ the distance from the left or top edge of the widget.
+
+ Note that \a pos is also measured from the left (or top) for
+ right-to-left languages. This function will map \a pos to the
+ appropriate position before calling QSplitter::moveSplitter().
+
+ \sa QSplitter::moveSplitter() closestLegalPosition()
+*/
+void QSplitterHandle::moveSplitter(int pos)
+{
+ Q_D(QSplitterHandle);
+ if (d->s->isRightToLeft() && d->orient == Qt::Horizontal)
+ pos = d->s->contentsRect().width() - pos;
+ d->s->moveSplitter(pos, d->s->indexOf(this));
+}
+
+/*!
+ Returns the closest legal position to \a pos of the splitter
+ handle. The positions are measured from the left or top edge of
+ the splitter, even for right-to-left languages.
+
+ \sa QSplitter::closestLegalPosition(), moveSplitter()
+*/
+
+int QSplitterHandle::closestLegalPosition(int pos)
+{
+ Q_D(QSplitterHandle);
+ QSplitter *s = d->s;
+ if (s->isRightToLeft() && d->orient == Qt::Horizontal) {
+ int w = s->contentsRect().width();
+ return w - s->closestLegalPosition(w - pos, s->indexOf(this));
+ }
+ return s->closestLegalPosition(pos, s->indexOf(this));
+}
+
+/*!
+ \reimp
+*/
+QSize QSplitterHandle::sizeHint() const
+{
+ Q_D(const QSplitterHandle);
+ int hw = d->s->handleWidth();
+ QStyleOption opt(0);
+ opt.init(d->s);
+ opt.state = QStyle::State_None;
+ return parentWidget()->style()->sizeFromContents(QStyle::CT_Splitter, &opt, QSize(hw, hw), d->s)
+ .expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+void QSplitterHandle::resizeEvent(QResizeEvent *event)
+{
+ Q_D(const QSplitterHandle);
+
+ // When splitters are only 1 pixel large we increase the
+ // actual grab area to five pixels
+
+ // Note that QSplitter uses contentsRect for layouting
+ // and ensures that handles are drawn on top of widgets
+ // We simply use the contents margins for draggin and only
+ // paint the mask area
+ bool useTinyMode = (d->s->handleWidth() == 1);
+ setAttribute(Qt::WA_MouseNoMask, useTinyMode);
+ if (useTinyMode) {
+ if (orientation() == Qt::Horizontal)
+ setContentsMargins(2, 0, 2, 0);
+ else
+ setContentsMargins(0, 2, 0, 2);
+ setMask(QRegion(contentsRect()));
+ }
+
+ QWidget::resizeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+bool QSplitterHandle::event(QEvent *event)
+{
+ Q_D(QSplitterHandle);
+ switch(event->type()) {
+ case QEvent::HoverEnter:
+ d->hover = true;
+ update();
+ break;
+ case QEvent::HoverLeave:
+ d->hover = false;
+ update();
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QSplitterHandle::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QSplitterHandle);
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+ int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos()))
+ - d->mouseOffset;
+ if (opaqueResize()) {
+ moveSplitter(pos);
+ } else {
+ d->s->setRubberBand(closestLegalPosition(pos));
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSplitterHandle::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QSplitterHandle);
+ if (e->button() == Qt::LeftButton) {
+ d->mouseOffset = d->pick(e->pos());
+ d->pressed = true;
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSplitterHandle::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QSplitterHandle);
+ if (!opaqueResize() && e->button() == Qt::LeftButton) {
+ int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos()))
+ - d->mouseOffset;
+ d->s->setRubberBand(-1);
+ moveSplitter(pos);
+ }
+ if (e->button() == Qt::LeftButton) {
+ d->pressed = false;
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSplitterHandle::paintEvent(QPaintEvent *)
+{
+ Q_D(QSplitterHandle);
+ QPainter p(this);
+ QStyleOption opt(0);
+ opt.rect = contentsRect();
+ opt.palette = palette();
+ if (orientation() == Qt::Horizontal)
+ opt.state = QStyle::State_Horizontal;
+ else
+ opt.state = QStyle::State_None;
+ if (d->hover)
+ opt.state |= QStyle::State_MouseOver;
+ if (d->pressed)
+ opt.state |= QStyle::State_Sunken;
+ if (isEnabled())
+ opt.state |= QStyle::State_Enabled;
+ parentWidget()->style()->drawControl(QStyle::CE_Splitter, &opt, &p, d->s);
+}
+
+
+int QSplitterLayoutStruct::getWidgetSize(Qt::Orientation orient)
+{
+ if (sizer == -1) {
+ QSize s = widget->sizeHint();
+ const int presizer = pick(s, orient);
+ const int realsize = pick(widget->size(), orient);
+ if (!s.isValid() || (widget->testAttribute(Qt::WA_Resized) && (realsize > presizer))) {
+ sizer = pick(widget->size(), orient);
+ } else {
+ sizer = presizer;
+ }
+ QSizePolicy p = widget->sizePolicy();
+ int sf = (orient == Qt::Horizontal) ? p.horizontalStretch() : p.verticalStretch();
+ if (sf > 1)
+ sizer *= sf;
+ }
+ return sizer;
+}
+
+int QSplitterLayoutStruct::getHandleSize(Qt::Orientation orient)
+{
+ return pick(handle->sizeHint(), orient);
+}
+
+void QSplitterPrivate::init()
+{
+ Q_Q(QSplitter);
+ QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ if (orient == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+}
+
+void QSplitterPrivate::recalc(bool update)
+{
+ Q_Q(QSplitter);
+ int n = list.count();
+ /*
+ Splitter handles before the first visible widget or right
+ before a hidden widget must be hidden.
+ */
+ bool first = true;
+ bool allInvisible = n != 0;
+ for (int i = 0; i < n ; ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+ bool widgetHidden = s->widget->isHidden();
+ if (allInvisible && !widgetHidden && !s->collapsed)
+ allInvisible = false;
+ s->handle->setHidden(first || widgetHidden);
+ if (!widgetHidden)
+ first = false;
+ }
+
+ if (allInvisible)
+ for (int i = 0; i < n ; ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+ if (!s->widget->isHidden()) {
+ s->collapsed = false;
+ break;
+ }
+ }
+
+ int fi = 2 * q->frameWidth();
+ int maxl = fi;
+ int minl = fi;
+ int maxt = QWIDGETSIZE_MAX;
+ int mint = fi;
+ /*
+ calculate min/max sizes for the whole splitter
+ */
+ bool empty = true;
+ for (int j = 0; j < n; j++) {
+ QSplitterLayoutStruct *s = list.at(j);
+
+ if (!s->widget->isHidden()) {
+ empty = false;
+ if (!s->handle->isHidden()) {
+ minl += s->getHandleSize(orient);
+ maxl += s->getHandleSize(orient);
+ }
+
+ QSize minS = qSmartMinSize(s->widget);
+ minl += pick(minS);
+ maxl += pick(s->widget->maximumSize());
+ mint = qMax(mint, trans(minS));
+ int tm = trans(s->widget->maximumSize());
+ if (tm > 0)
+ maxt = qMin(maxt, tm);
+ }
+ }
+
+ if (empty) {
+ if (qobject_cast<QSplitter *>(parent)) {
+ // nested splitters; be nice
+ maxl = maxt = 0;
+ } else {
+ // QSplitter with no children yet
+ maxl = QWIDGETSIZE_MAX;
+ }
+ } else {
+ maxl = qMin<int>(maxl, QWIDGETSIZE_MAX);
+ }
+ if (maxt < mint)
+ maxt = mint;
+
+ if (update) {
+ if (orient == Qt::Horizontal) {
+ q->setMaximumSize(maxl, maxt);
+ if (q->isWindow())
+ q->setMinimumSize(minl,mint);
+ } else {
+ q->setMaximumSize(maxt, maxl);
+ if (q->isWindow())
+ q->setMinimumSize(mint,minl);
+ }
+ doResize();
+ q->updateGeometry();
+ } else {
+ firstShow = true;
+ }
+}
+
+void QSplitterPrivate::doResize()
+{
+ Q_Q(QSplitter);
+ QRect r = q->contentsRect();
+ int n = list.count();
+ QVector<QLayoutStruct> a(n*2);
+ int i;
+
+ bool noStretchFactorsSet = true;
+ for (i = 0; i < n; ++i) {
+ QSizePolicy p = list.at(i)->widget->sizePolicy();
+ int sf = orient == Qt::Horizontal ? p.horizontalStretch() : p.verticalStretch();
+ if (sf != 0) {
+ noStretchFactorsSet = false;
+ break;
+ }
+ }
+
+ int j=0;
+ for (i = 0; i < n; ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+#ifdef QSPLITTER_DEBUG
+ qDebug("widget %d hidden: %d collapsed: %d handle hidden: %d", i, s->widget->isHidden(),
+ s->collapsed, s->handle->isHidden());
+#endif
+
+ a[j].init();
+ if (s->handle->isHidden()) {
+ a[j].maximumSize = 0;
+ } else {
+ a[j].sizeHint = a[j].minimumSize = a[j].maximumSize = s->getHandleSize(orient);
+ a[j].empty = false;
+ }
+ ++j;
+
+ a[j].init();
+ if (s->widget->isHidden() || s->collapsed) {
+ a[j].maximumSize = 0;
+ } else {
+ a[j].minimumSize = pick(qSmartMinSize(s->widget));
+ a[j].maximumSize = pick(s->widget->maximumSize());
+ a[j].empty = false;
+
+ bool stretch = noStretchFactorsSet;
+ if (!stretch) {
+ QSizePolicy p = s->widget->sizePolicy();
+ int sf = orient == Qt::Horizontal ? p.horizontalStretch() : p.verticalStretch();
+ stretch = (sf != 0);
+ }
+ if (stretch) {
+ a[j].stretch = s->getWidgetSize(orient);
+ a[j].sizeHint = a[j].minimumSize;
+ a[j].expansive = true;
+ } else {
+ a[j].sizeHint = qMax(s->getWidgetSize(orient), a[j].minimumSize);
+ }
+ }
+ ++j;
+ }
+
+ qGeomCalc(a, 0, n*2, pick(r.topLeft()), pick(r.size()), 0);
+
+#ifdef QSPLITTER_DEBUG
+ for (i = 0; i < n*2; ++i) {
+ qDebug("%*s%d: stretch %d, sh %d, minS %d, maxS %d, exp %d, emp %d -> %d, %d",
+ i, "", i,
+ a[i].stretch,
+ a[i].sizeHint,
+ a[i].minimumSize,
+ a[i].maximumSize,
+ a[i].expansive,
+ a[i].empty,
+ a[i].pos,
+ a[i].size);
+ }
+#endif
+
+ for (i = 0; i < n; ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+ setGeo(s, a[i*2+1].pos, a[i*2+1].size, false);
+ }
+}
+
+void QSplitterPrivate::storeSizes()
+{
+ for (int i = 0; i < list.size(); ++i) {
+ QSplitterLayoutStruct *sls = list.at(i);
+ sls->sizer = pick(sls->rect.size());
+ }
+}
+
+void QSplitterPrivate::addContribution(int index, int *min, int *max, bool mayCollapse) const
+{
+ QSplitterLayoutStruct *s = list.at(index);
+ if (!s->widget->isHidden()) {
+ if (!s->handle->isHidden()) {
+ *min += s->getHandleSize(orient);
+ *max += s->getHandleSize(orient);
+ }
+ if (mayCollapse || !s->collapsed)
+ *min += pick(qSmartMinSize(s->widget));
+
+ *max += pick(s->widget->maximumSize());
+ }
+}
+
+int QSplitterPrivate::findWidgetJustBeforeOrJustAfter(int index, int delta, int &collapsibleSize) const
+{
+ if (delta < 0)
+ index += delta;
+ do {
+ QWidget *w = list.at(index)->widget;
+ if (!w->isHidden()) {
+ if (collapsible(list.at(index)))
+ collapsibleSize = pick(qSmartMinSize(w));
+ return index;
+ }
+ index += delta;
+ } while (index >= 0 && index < list.count());
+
+ return -1;
+}
+
+/*
+ For the splitter handle with index \a index, \a min and \a max give the range without collapsing any widgets,
+ and \a farMin and farMax give the range with collapsing included.
+*/
+void QSplitterPrivate::getRange(int index, int *farMin, int *min, int *max, int *farMax) const
+{
+ Q_Q(const QSplitter);
+ int n = list.count();
+ if (index <= 0 || index >= n)
+ return;
+
+ int collapsibleSizeBefore = 0;
+ int idJustBefore = findWidgetJustBeforeOrJustAfter(index, -1, collapsibleSizeBefore);
+
+ int collapsibleSizeAfter = 0;
+ int idJustAfter = findWidgetJustBeforeOrJustAfter(index, +1, collapsibleSizeAfter);
+
+ int minBefore = 0;
+ int minAfter = 0;
+ int maxBefore = 0;
+ int maxAfter = 0;
+ int i;
+
+ for (i = 0; i < index; ++i)
+ addContribution(i, &minBefore, &maxBefore, i == idJustBefore);
+ for (i = index; i < n; ++i)
+ addContribution(i, &minAfter, &maxAfter, i == idJustAfter);
+
+ QRect r = q->contentsRect();
+ int farMinVal;
+ int minVal;
+ int maxVal;
+ int farMaxVal;
+
+ int smartMinBefore = qMax(minBefore, pick(r.size()) - maxAfter);
+ int smartMaxBefore = qMin(maxBefore, pick(r.size()) - minAfter);
+
+ minVal = pick(r.topLeft()) + smartMinBefore;
+ maxVal = pick(r.topLeft()) + smartMaxBefore;
+
+ farMinVal = minVal;
+ if (minBefore - collapsibleSizeBefore >= pick(r.size()) - maxAfter)
+ farMinVal -= collapsibleSizeBefore;
+ farMaxVal = maxVal;
+ if (pick(r.size()) - (minAfter - collapsibleSizeAfter) <= maxBefore)
+ farMaxVal += collapsibleSizeAfter;
+
+ if (farMin)
+ *farMin = farMinVal;
+ if (min)
+ *min = minVal;
+ if (max)
+ *max = maxVal;
+ if (farMax)
+ *farMax = farMaxVal;
+}
+
+int QSplitterPrivate::adjustPos(int pos, int index, int *farMin, int *min, int *max, int *farMax) const
+{
+ const int Threshold = 40;
+
+ getRange(index, farMin, min, max, farMax);
+
+ if (pos >= *min) {
+ if (pos <= *max) {
+ return pos;
+ } else {
+ int delta = pos - *max;
+ int width = *farMax - *max;
+
+ if (delta > width / 2 && delta >= qMin(Threshold, width)) {
+ return *farMax;
+ } else {
+ return *max;
+ }
+ }
+ } else {
+ int delta = *min - pos;
+ int width = *min - *farMin;
+
+ if (delta > width / 2 && delta >= qMin(Threshold, width)) {
+ return *farMin;
+ } else {
+ return *min;
+ }
+ }
+}
+
+bool QSplitterPrivate::collapsible(QSplitterLayoutStruct *s) const
+{
+ if (s->collapsible != Default) {
+ return (bool)s->collapsible;
+ } else {
+ return childrenCollapsible;
+ }
+}
+
+void QSplitterPrivate::updateHandles()
+{
+ Q_Q(QSplitter);
+ recalc(q->isVisible());
+}
+
+void QSplitterPrivate::setSizes_helper(const QList<int> &sizes, bool clampNegativeSize)
+{
+ int j = 0;
+
+ for (int i = 0; i < list.size(); ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+
+ s->collapsed = false;
+ s->sizer = sizes.value(j++);
+ if (clampNegativeSize && s->sizer < 0)
+ s->sizer = 0;
+ int smartMinSize = pick(qSmartMinSize(s->widget));
+
+ // Make sure that we reset the collapsed state.
+ if (s->sizer == 0) {
+ if (collapsible(s) && smartMinSize > 0) {
+ s->collapsed = true;
+ } else {
+ s->sizer = smartMinSize;
+ }
+ } else {
+ if (s->sizer < smartMinSize)
+ s->sizer = smartMinSize;
+ }
+ }
+ doResize();
+}
+
+void QSplitterPrivate::setGeo(QSplitterLayoutStruct *sls, int p, int s, bool allowCollapse)
+{
+ Q_Q(QSplitter);
+ QWidget *w = sls->widget;
+ QRect r;
+ QRect contents = q->contentsRect();
+ if (orient == Qt::Horizontal) {
+ r.setRect(p, contents.y(), s, contents.height());
+ } else {
+ r.setRect(contents.x(), p, contents.width(), s);
+ }
+ sls->rect = r;
+
+ int minSize = pick(qSmartMinSize(w));
+
+ if (orient == Qt::Horizontal && q->isRightToLeft())
+ r.moveRight(contents.width() - r.left());
+
+ if (allowCollapse)
+ sls->collapsed = s <= 0 && minSize > 0 && !w->isHidden();
+
+ // Hide the child widget, but without calling hide() so that
+ // the splitter handle is still shown.
+ if (sls->collapsed)
+ r.moveTopLeft(QPoint(-r.width()-1, -r.height()-1));
+
+ w->setGeometry(r);
+
+ if (!sls->handle->isHidden()) {
+ QSplitterHandle *h = sls->handle;
+ QSize hs = h->sizeHint();
+ int left, top, right, bottom;
+ h->getContentsMargins(&left, &top, &right, &bottom);
+ if (orient==Qt::Horizontal) {
+ if (q->isRightToLeft())
+ p = contents.width() - p + hs.width();
+ h->setGeometry(p-hs.width() - left, contents.y(), hs.width() + left + right, contents.height());
+ } else {
+ h->setGeometry(contents.x(), p-hs.height() - top, contents.width(), hs.height() + top + bottom);
+ }
+ }
+}
+
+void QSplitterPrivate::doMove(bool backwards, int hPos, int index, int delta, bool mayCollapse,
+ int *positions, int *widths)
+{
+ if (index < 0 || index >= list.count())
+ return;
+
+#ifdef QSPLITTER_DEBUG
+ qDebug() << "QSplitterPrivate::doMove" << backwards << hPos << index << delta << mayCollapse;
+#endif
+
+ QSplitterLayoutStruct *s = list.at(index);
+ QWidget *w = s->widget;
+
+ int nextId = backwards ? index - delta : index + delta;
+
+ if (w->isHidden()) {
+ doMove(backwards, hPos, nextId, delta, collapsible(nextId), positions, widths);
+ } else {
+ int hs =s->handle->isHidden() ? 0 : s->getHandleSize(orient);
+
+ int ws = backwards ? hPos - pick(s->rect.topLeft())
+ : pick(s->rect.bottomRight()) - hPos -hs + 1;
+ if (ws > 0 || (!s->collapsed && !mayCollapse)) {
+ ws = qMin(ws, pick(w->maximumSize()));
+ ws = qMax(ws, pick(qSmartMinSize(w)));
+ } else {
+ ws = 0;
+ }
+ positions[index] = backwards ? hPos - ws : hPos + hs;
+ widths[index] = ws;
+ doMove(backwards, backwards ? hPos - ws - hs : hPos + hs + ws, nextId, delta,
+ collapsible(nextId), positions, widths);
+ }
+
+}
+
+QSplitterLayoutStruct *QSplitterPrivate::findWidget(QWidget *w) const
+{
+ for (int i = 0; i < list.size(); ++i) {
+ if (list.at(i)->widget == w)
+ return list.at(i);
+ }
+ return 0;
+}
+
+#ifdef QT3_SUPPORT
+static void setStretch(QWidget *w, int sf)
+{
+ QSizePolicy sp = w->sizePolicy();
+ sp.setHorizontalStretch(sf);
+ sp.setVerticalStretch(sf);
+ w->setSizePolicy(sp);
+}
+
+static int getStretch(const QWidget *w)
+{
+ QSizePolicy sp = w->sizePolicy();
+ return qMax(sp.horizontalStretch(), sp.verticalStretch());
+}
+
+void QSplitter::setResizeMode(QWidget *w, ResizeMode mode)
+{
+ /*
+ Internal comment:
+
+ This function tries to simulate the Qt 3.x ResizeMode
+ behavior using QSizePolicy stretch factors. This isn't easy,
+ because the default \l ResizeMode was \l Stretch, not \l
+ KeepSize, whereas the default stetch factor is 0.
+
+ So what we do is this: When the user calls setResizeMode()
+ the first time, we iterate through all the child widgets and
+ set their stretch factors to 1. Later on, if children are
+ added (using addWidget()), their stretch factors are also set
+ to 1.
+
+ There is just one problem left: Often, setResizeMode() is
+ called \e{before} addWidget(), because addWidget() is called
+ from the event loop. In that case, we use a special value,
+ 243, instead of 0 to prevent 0 from being overwritten with 1
+ in addWidget(). This is a wicked hack, but fortunately it
+ only occurs as a result of calling a \c QT3_SUPPORT function.
+ */
+
+ Q_D(QSplitter);
+ bool metWidget = false;
+ if (!d->compatMode) {
+ d->compatMode = true;
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ if (s->widget == w)
+ metWidget = true;
+ if (getStretch(s->widget) == 0)
+ setStretch(s->widget, 1);
+ }
+ }
+ int sf;
+ if (mode == KeepSize)
+ sf = metWidget ? 0 : 243;
+ else
+ sf = 1;
+ setStretch(w, sf);
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QSplitter::QSplitter(QWidget *parent, const char *name)
+ : QFrame(*new QSplitterPrivate, parent)
+{
+ Q_D(QSplitter);
+ setObjectName(QString::fromAscii(name));
+ d->orient = Qt::Horizontal;
+ d->init();
+}
+
+
+/*!
+ Use one of the constructors that don't take the \a name argument
+ and then use setObjectName() instead.
+*/
+QSplitter::QSplitter(Qt::Orientation orientation, QWidget *parent, const char *name)
+ : QFrame(*new QSplitterPrivate, parent)
+{
+ Q_D(QSplitter);
+ setObjectName(QString::fromAscii(name));
+ d->orient = orientation;
+ d->init();
+}
+#endif
+
+/*!
+ \internal
+*/
+void QSplitterPrivate::insertWidget_helper(int index, QWidget *widget, bool show)
+{
+ Q_Q(QSplitter);
+ QBoolBlocker b(blockChildAdd);
+ bool needShow = show && q->isVisible() &&
+ !(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ if (widget->parentWidget() != q)
+ widget->setParent(q);
+ if (needShow)
+ widget->show();
+ insertWidget(index, widget);
+ recalc(q->isVisible());
+}
+
+/*
+ Inserts the widget \a w at position \a index in the splitter's list of widgets.
+
+ If \a w is already in the splitter, it will be moved to the new position.
+*/
+
+QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w)
+{
+ Q_Q(QSplitter);
+ QSplitterLayoutStruct *sls = 0;
+ int i;
+ int last = list.count();
+ for (i = 0; i < list.size(); ++i) {
+ QSplitterLayoutStruct *s = list.at(i);
+ if (s->widget == w) {
+ sls = s;
+ --last;
+ break;
+ }
+ }
+ if (index < 0 || index > last)
+ index = last;
+
+ if (sls) {
+ list.move(i,index);
+ } else {
+ QSplitterHandle *newHandle = 0;
+ sls = new QSplitterLayoutStruct;
+ QString tmp = QLatin1String("qt_splithandle_");
+ tmp += w->objectName();
+ newHandle = q->createHandle();
+ newHandle->setObjectName(tmp);
+ sls->handle = newHandle;
+ sls->widget = w;
+ w->lower();
+ list.insert(index,sls);
+
+ if (newHandle && q->isVisible())
+ newHandle->show(); // will trigger sending of post events
+
+#ifdef QT3_SUPPORT
+ if (compatMode) {
+ int sf = getStretch(sls->widget);
+ if (sf == 243)
+ setStretch(sls->widget, 0);
+ else if (sf == 0)
+ setStretch(sls->widget, 1);
+ }
+#endif
+ }
+ return sls;
+}
+
+/*!
+ \class QSplitter
+ \brief The QSplitter class implements a splitter widget.
+
+ \ingroup organizers
+
+
+ A splitter lets the user control the size of child widgets by dragging the
+ boundary between the children. Any number of widgets may be controlled by a
+ single splitter. The typical use of a QSplitter is to create several
+ widgets and add them using insertWidget() or addWidget().
+
+ The following example will show a QListView, QTreeView, and
+ QTextEdit side by side, with two splitter handles:
+
+ \snippet doc/src/snippets/splitter/splitter.cpp 0
+
+ If a widget is already inside a QSplitter when insertWidget() or
+ addWidget() is called, it will move to the new position. This can be used
+ to reorder widgets in the splitter later. You can use indexOf(),
+ widget(), and count() to get access to the widgets inside the splitter.
+
+ A default QSplitter lays out its children horizontally (side by side); you
+ can use setOrientation(Qt::Vertical) to lay its
+ children out vertically.
+
+ By default, all widgets can be as large or as small as the user
+ wishes, between the \l minimumSizeHint() (or \l minimumSize())
+ and \l maximumSize() of the widgets.
+
+ QSplitter resizes its children dynamically by default. If you
+ would rather have QSplitter resize the children only at the end of
+ a resize operation, call setOpaqueResize(false).
+
+ The initial distribution of size between the widgets is determined by
+ multiplying the initial size with the stretch factor.
+ You can also use setSizes() to set the sizes
+ of all the widgets. The function sizes() returns the sizes set by the user.
+ Alternatively, you can save and restore the sizes of the widgets from a
+ QByteArray using saveState() and restoreState() respectively.
+
+ When you hide() a child its space will be distributed among the
+ other children. It will be reinstated when you show() it again.
+
+ \sa QSplitterHandle, QHBoxLayout, QVBoxLayout, QTabWidget
+*/
+
+
+/*!
+ Constructs a horizontal splitter with the \a parent
+ argument passed on to the QFrame constructor.
+
+ \sa setOrientation()
+*/
+QSplitter::QSplitter(QWidget *parent)
+ : QFrame(*new QSplitterPrivate, parent)
+{
+ Q_D(QSplitter);
+ d->orient = Qt::Horizontal;
+ d->init();
+}
+
+
+/*!
+ Constructs a splitter with the given \a orientation and \a parent.
+
+ \sa setOrientation()
+*/
+QSplitter::QSplitter(Qt::Orientation orientation, QWidget *parent)
+ : QFrame(*new QSplitterPrivate, parent)
+{
+ Q_D(QSplitter);
+ d->orient = orientation;
+ d->init();
+}
+
+
+/*!
+ Destroys the splitter. All children are deleted.
+*/
+
+QSplitter::~QSplitter()
+{
+ Q_D(QSplitter);
+ delete d->rubberBand;
+ while (!d->list.isEmpty())
+ delete d->list.takeFirst();
+}
+
+/*!
+ Updates the splitter's state. You should not need to call this
+ function.
+*/
+void QSplitter::refresh()
+{
+ Q_D(QSplitter);
+ d->recalc(true);
+}
+
+/*!
+ \property QSplitter::orientation
+ \brief the orientation of the splitter
+
+ By default the orientation is horizontal (i.e., the widgets are
+ laid out side by side). The possible orientations are
+ Qt::Horizontal and Qt::Vertical.
+
+ \sa QSplitterHandle::orientation()
+*/
+
+void QSplitter::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QSplitter);
+ if (d->orient == orientation)
+ return;
+
+ if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy(sp);
+ setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ }
+
+ d->orient = orientation;
+
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ s->handle->setOrientation(orientation);
+ }
+ d->recalc(isVisible());
+}
+
+Qt::Orientation QSplitter::orientation() const
+{
+ Q_D(const QSplitter);
+ return d->orient;
+}
+
+/*!
+ \property QSplitter::childrenCollapsible
+ \brief whether child widgets can be resized down to size 0 by the user
+
+ By default, children are collapsible. It is possible to enable
+ and disable the collapsing of individual children using
+ setCollapsible().
+
+ \sa setCollapsible()
+*/
+
+void QSplitter::setChildrenCollapsible(bool collapse)
+{
+ Q_D(QSplitter);
+ d->childrenCollapsible = collapse;
+}
+
+bool QSplitter::childrenCollapsible() const
+{
+ Q_D(const QSplitter);
+ return d->childrenCollapsible;
+}
+
+/*!
+ Sets whether the child widget at index \a index is collapsible to \a collapse.
+
+ By default, children are collapsible, meaning that the user can
+ resize them down to size 0, even if they have a non-zero
+ minimumSize() or minimumSizeHint(). This behavior can be changed
+ on a per-widget basis by calling this function, or globally for
+ all the widgets in the splitter by setting the \l
+ childrenCollapsible property.
+
+ \sa childrenCollapsible
+*/
+
+void QSplitter::setCollapsible(int index, bool collapse)
+{
+ Q_D(QSplitter);
+
+ if (index < 0 || index >= d->list.size()) {
+ qWarning("QSplitter::setCollapsible: Index %d out of range", index);
+ return;
+ }
+ d->list.at(index)->collapsible = collapse ? 1 : 0;
+}
+
+/*!
+ Returns true if the widget at \a index is collapsible, otherwise returns false
+*/
+bool QSplitter::isCollapsible(int index) const
+{
+ Q_D(const QSplitter);
+ if (index < 0 || index >= d->list.size()) {
+ qWarning("QSplitter::isCollapsible: Index %d out of range", index);
+ return false;
+ }
+ return d->list.at(index)->collapsible;
+}
+
+/*!
+ \reimp
+*/
+void QSplitter::resizeEvent(QResizeEvent *)
+{
+ Q_D(QSplitter);
+ d->doResize();
+}
+
+/*!
+ Adds the given \a widget to the splitter's layout after all the other
+ items.
+
+ If \a widget is already in the splitter, it will be moved to the new position.
+
+ \sa insertWidget() widget() indexOf()
+*/
+void QSplitter::addWidget(QWidget *widget)
+{
+ Q_D(QSplitter);
+ insertWidget(d->list.count(), widget);
+}
+
+/*!
+ Inserts the \a widget specified into the splitter's layout at the
+ given \a index.
+
+ If \a widget is already in the splitter, it will be moved to the new position.
+
+ if \a index is an invalid index, then the widget will be inserted at the end.
+
+ \sa addWidget() indexOf() widget()
+*/
+void QSplitter::insertWidget(int index, QWidget *widget)
+{
+ Q_D(QSplitter);
+ d->insertWidget_helper(index, widget, true);
+}
+
+/*!
+ \fn int QSplitter::indexOf(QWidget *widget) const
+
+ Returns the index in the splitter's layout of the specified \a widget. This
+ also works for handles.
+
+ Handles are numbered from 0. There are as many handles as there
+ are child widgets, but the handle at position 0 is always hidden.
+
+
+ \sa count(), widget()
+*/
+int QSplitter::indexOf(QWidget *w) const
+{
+ Q_D(const QSplitter);
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ if (s->widget == w || s->handle == w)
+ return i;
+ }
+ return -1;
+}
+
+/*!
+ Returns a new splitter handle as a child widget of this splitter.
+ This function can be reimplemented in subclasses to provide support
+ for custom handles.
+
+ \sa handle(), indexOf()
+*/
+QSplitterHandle *QSplitter::createHandle()
+{
+ Q_D(QSplitter);
+ return new QSplitterHandle(d->orient, this);
+}
+
+/*!
+ Returns the handle to the left (or above) for the item in the
+ splitter's layout at the given \a index. The handle at index 0 is
+ always hidden.
+
+ For right-to-left languages such as Arabic and Hebrew, the layout
+ of horizontal splitters is reversed. The handle will be to the
+ right of the widget at \a index.
+
+ \sa count(), widget(), indexOf(), createHandle(), setHandleWidth()
+*/
+QSplitterHandle *QSplitter::handle(int index) const
+{
+ Q_D(const QSplitter);
+ if (index < 0 || index >= d->list.size())
+ return 0;
+ return d->list.at(index)->handle;
+}
+
+/*!
+ Returns the widget at the given \a index in the splitter's layout.
+
+ \sa count(), handle(), indexOf(), insertWidget()
+*/
+QWidget *QSplitter::widget(int index) const
+{
+ Q_D(const QSplitter);
+ if (index < 0 || index >= d->list.size())
+ return 0;
+ return d->list.at(index)->widget;
+}
+
+/*!
+ Returns the number of widgets contained in the splitter's layout.
+
+ \sa widget(), handle()
+*/
+int QSplitter::count() const
+{
+ Q_D(const QSplitter);
+ return d->list.count();
+}
+
+/*!
+ \reimp
+
+ Tells the splitter that the child widget described by \a c has been
+ inserted or removed.
+
+ This method is also used to handle the situation where a widget is created
+ with the splitter as a parent but not explicitly added with insertWidget()
+ or addWidget(). This is for compatibility and not the recommended way of
+ putting widgets into a splitter in new code. Please use insertWidget() or
+ addWidget() in new code.
+
+ \sa addWidget() insertWidget()
+*/
+
+void QSplitter::childEvent(QChildEvent *c)
+{
+ Q_D(QSplitter);
+ if (!c->child()->isWidgetType())
+ return;
+ QWidget *w = static_cast<QWidget*>(c->child());
+ if (c->added() && !d->blockChildAdd && !w->isWindow() && !d->findWidget(w)) {
+ d->insertWidget_helper(d->list.count(), w, false);
+ } else if (c->polished() && !d->blockChildAdd) {
+ if (isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide)))
+ w->show();
+ } else if (c->type() == QEvent::ChildRemoved) {
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ if (s->widget == w) {
+ d->list.removeAt(i);
+ delete s;
+ d->recalc(isVisible());
+ return;
+ }
+ }
+ }
+}
+
+
+/*!
+ Displays a rubber band at position \a pos. If \a pos is negative, the
+ rubber band is removed.
+*/
+
+void QSplitter::setRubberBand(int pos)
+{
+ Q_D(QSplitter);
+ if (pos < 0) {
+ if (d->rubberBand)
+ d->rubberBand->deleteLater();
+ return;
+ }
+ QRect r = contentsRect();
+ const int rBord = 3; // customizable?
+ int hw = handleWidth();
+ if (!d->rubberBand) {
+ QBoolBlocker b(d->blockChildAdd);
+ d->rubberBand = new QRubberBand(QRubberBand::Line, this);
+ // For accessibility to identify this special widget.
+ d->rubberBand->setObjectName(QLatin1String("qt_rubberband"));
+ }
+
+ const QRect newGeom = d->orient == Qt::Horizontal ? QRect(QPoint(pos + hw / 2 - rBord, r.y()), QSize(2 * rBord, r.height()))
+ : QRect(QPoint(r.x(), pos + hw / 2 - rBord), QSize(r.width(), 2 * rBord));
+ d->rubberBand->setGeometry(newGeom);
+ d->rubberBand->show();
+}
+
+/*!
+ \reimp
+*/
+
+bool QSplitter::event(QEvent *e)
+{
+ Q_D(QSplitter);
+ switch (e->type()) {
+ case QEvent::Hide:
+ // Reset firstShow to false here since things can be done to the splitter in between
+ if (!d->firstShow)
+ d->firstShow = true;
+ break;
+ case QEvent::Show:
+ if (!d->firstShow)
+ break;
+ d->firstShow = false;
+ // fall through
+ case QEvent::HideToParent:
+ case QEvent::ShowToParent:
+ case QEvent::LayoutRequest:
+#ifdef QT3_SUPPORT
+ case QEvent::LayoutHint:
+#endif
+ d->recalc(isVisible());
+ break;
+ default:
+ ;
+ }
+ return QWidget::event(e);
+}
+
+/*!
+ \fn QSplitter::splitterMoved(int pos, int index)
+
+ This signal is emitted when the splitter handle at a particular \a
+ index has been moved to position \a pos.
+
+ For right-to-left languages such as Arabic and Hebrew, the layout
+ of horizontal splitters is reversed. \a pos is then the
+ distance from the right edge of the widget.
+
+ \sa moveSplitter()
+*/
+
+/*!
+ Moves the left or top edge of the splitter handle at \a index as
+ close as possible to position \a pos, which is the distance from the
+ left or top edge of the widget.
+
+ For right-to-left languages such as Arabic and Hebrew, the layout
+ of horizontal splitters is reversed. \a pos is then the distance
+ from the right edge of the widget.
+
+ \sa splitterMoved(), closestLegalPosition(), getRange()
+*/
+void QSplitter::moveSplitter(int pos, int index)
+{
+ Q_D(QSplitter);
+ QSplitterLayoutStruct *s = d->list.at(index);
+ int farMin;
+ int min;
+ int max;
+ int farMax;
+
+#ifdef QSPLITTER_DEBUG
+ int debugp = pos;
+#endif
+
+ pos = d->adjustPos(pos, index, &farMin, &min, &max, &farMax);
+ int oldP = d->pick(s->rect.topLeft());
+#ifdef QSPLITTER_DEBUG
+ qDebug() << "QSplitter::moveSplitter" << debugp << index << "adjusted" << pos << "oldP" << oldP;
+#endif
+
+ QVarLengthArray<int, 32> poss(d->list.count());
+ QVarLengthArray<int, 32> ws(d->list.count());
+ bool upLeft;
+
+ d->doMove(false, pos, index, +1, (d->collapsible(s) && (pos > max)), poss.data(), ws.data());
+ d->doMove(true, pos, index - 1, +1, (d->collapsible(index - 1) && (pos < min)), poss.data(), ws.data());
+ upLeft = (pos < oldP);
+
+ int wid, delta, count = d->list.count();
+ if (upLeft) {
+ wid = 0;
+ delta = 1;
+ } else {
+ wid = count - 1;
+ delta = -1;
+ }
+ for (; wid >= 0 && wid < count; wid += delta) {
+ QSplitterLayoutStruct *sls = d->list.at( wid );
+ if (!sls->widget->isHidden())
+ d->setGeo(sls, poss[wid], ws[wid], true);
+ }
+ d->storeSizes();
+
+ emit splitterMoved(pos, index);
+}
+
+
+/*!
+ Returns the valid range of the splitter with index \a index in
+ *\a{min} and *\a{max} if \a min and \a max are not 0.
+*/
+
+void QSplitter::getRange(int index, int *min, int *max) const
+{
+ Q_D(const QSplitter);
+ d->getRange(index, min, 0, 0, max);
+}
+
+
+/*!
+ Returns the closest legal position to \a pos of the widget with index
+ \a index.
+
+ For right-to-left languages such as Arabic and Hebrew, the layout
+ of horizontal splitters is reversed. Positions are then measured
+ from the right edge of the widget.
+
+ \sa getRange()
+*/
+
+int QSplitter::closestLegalPosition(int pos, int index)
+{
+ Q_D(QSplitter);
+ int x, i, n, u;
+ return d->adjustPos(pos, index, &u, &n, &i, &x);
+}
+
+/*!
+ \property QSplitter::opaqueResize
+ \brief whether resizing is opaque
+
+ Opaque resizing is on by default.
+*/
+
+bool QSplitter::opaqueResize() const
+{
+ Q_D(const QSplitter);
+ return d->opaque;
+}
+
+
+void QSplitter::setOpaqueResize(bool on)
+{
+ Q_D(QSplitter);
+ d->opaque = on;
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn void QSplitter::moveToFirst(QWidget *widget)
+
+ Use insertWidget(0, \a widget) instead.
+*/
+
+
+/*!
+ \fn void QSplitter::moveToLast(QWidget *widget)
+
+ Use addWidget(\a widget) instead.
+*/
+
+/*!
+ \fn void QSplitter::setResizeMode(QWidget *widget, ResizeMode mode)
+
+ Use setStretchFactor() instead.
+
+ \oldcode
+ splitter->setResizeMode(firstChild, QSplitter::KeepSize);
+ splitter->setResizeMode(secondChild, QSplitter::Stretch);
+ \newcode
+ splitter->setStretchFactor(splitter->indexOf(firstChild), 0);
+ splitter->setStretchFactor(splitter->indexOf(secondChild), 1);
+ \endcode
+*/
+
+/*!
+ \fn void QSplitter::setCollapsible(QWidget *widget, bool collapsible)
+
+ Use setCollapsible(indexOf(\a widget, \a collapsible)) instead.
+*/
+
+/*!
+ \fn void QSplitter::setMargin(int margin)
+ Sets the width of the margin around the contents of the widget to \a margin.
+
+ Use QWidget::setContentsMargins() instead.
+ \sa margin(), QWidget::setContentsMargins()
+*/
+
+/*!
+ \fn int QSplitter::margin() const
+ Returns the width of the margin around the contents of the widget.
+
+ Use QWidget::getContentsMargins() instead.
+ \sa setMargin(), QWidget::getContentsMargins()
+*/
+
+#endif
+
+/*!
+ \reimp
+*/
+QSize QSplitter::sizeHint() const
+{
+ Q_D(const QSplitter);
+ ensurePolished();
+ int l = 0;
+ int t = 0;
+ for (int i = 0; i < d->list.size(); ++i) {
+ QWidget *w = d->list.at(i)->widget;
+ if (w->isHidden())
+ continue;
+ QSize s = w->sizeHint();
+ if (s.isValid()) {
+ l += d->pick(s);
+ t = qMax(t, d->trans(s));
+ }
+ }
+ return orientation() == Qt::Horizontal ? QSize(l, t) : QSize(t, l);
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QSplitter::minimumSizeHint() const
+{
+ Q_D(const QSplitter);
+ ensurePolished();
+ int l = 0;
+ int t = 0;
+
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ if (!s || !s->widget)
+ continue;
+ if (s->widget->isHidden())
+ continue;
+ QSize widgetSize = qSmartMinSize(s->widget);
+ if (widgetSize.isValid()) {
+ l += d->pick(widgetSize);
+ t = qMax(t, d->trans(widgetSize));
+ }
+ if (!s->handle || s->handle->isHidden())
+ continue;
+ QSize splitterSize = s->handle->sizeHint();
+ if (splitterSize.isValid()) {
+ l += d->pick(splitterSize);
+ t = qMax(t, d->trans(splitterSize));
+ }
+ }
+ return orientation() == Qt::Horizontal ? QSize(l, t) : QSize(t, l);
+}
+
+
+/*!
+ Returns a list of the size parameters of all the widgets in this splitter.
+
+ If the splitter's orientation is horizontal, the list contains the
+ widgets width in pixels, from left to right; if the orientation is
+ vertical, the list contains the widgets height in pixels,
+ from top to bottom.
+
+ Giving the values to another splitter's setSizes() function will
+ produce a splitter with the same layout as this one.
+
+ Note that invisible widgets have a size of 0.
+
+ \sa setSizes()
+*/
+
+QList<int> QSplitter::sizes() const
+{
+ Q_D(const QSplitter);
+ ensurePolished();
+
+ QList<int> list;
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ list.append(d->pick(s->rect.size()));
+ }
+ return list;
+}
+
+/*!
+ Sets the child widgets respective sizes to the values given in the \a list.
+
+ If the splitter is horizontal, the values set the widths of each
+ widget in pixels, from left to right. If the splitter is vertical, the
+ heights of each widget is set, from top to bottom.
+
+ Extra values in the \a list are ignored. If \a list contains too few
+ values, the result is undefined but the program will still be well-behaved.
+
+ The overall size of the splitter widget is not affected.
+ Instead, any additional/missing space is distributed amongst the
+ widgets according to the relative weight of the sizes.
+
+ If you specify a size of 0, the widget will be invisible. The size policies
+ of the widgets are preserved. That is, a value smaller then the minimal size
+ hint of the respective widget will be replaced by the value of the hint.
+
+ \sa sizes()
+*/
+
+void QSplitter::setSizes(const QList<int> &list)
+{
+ Q_D(QSplitter);
+ d->setSizes_helper(list, true);
+}
+
+/*!
+ \property QSplitter::handleWidth
+ \brief the width of the splitter handles
+
+ By default, this property contains a value that depends on the user's platform
+ and style preferences.
+
+ If you set handleWidth to 1, the actual grab area will grow to overlap a
+ few pixels of it's respective widgets.
+*/
+
+int QSplitter::handleWidth() const
+{
+ Q_D(const QSplitter);
+ if (d->handleWidth > 0) {
+ return d->handleWidth;
+ } else {
+ return style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this);
+ }
+}
+
+void QSplitter::setHandleWidth(int width)
+{
+ Q_D(QSplitter);
+ d->handleWidth = width;
+ d->updateHandles();
+}
+
+/*!
+ \reimp
+*/
+void QSplitter::changeEvent(QEvent *ev)
+{
+ Q_D(QSplitter);
+ if(ev->type() == QEvent::StyleChange)
+ d->updateHandles();
+ QFrame::changeEvent(ev);
+}
+
+static const qint32 SplitterMagic = 0xff;
+
+/*!
+ Saves the state of the splitter's layout.
+
+ Typically this is used in conjunction with QSettings to remember the size
+ for a future session. A version number is stored as part of the data.
+ Here is an example:
+
+ \snippet doc/src/snippets/splitter/splitter.cpp 1
+
+ \sa restoreState()
+*/
+QByteArray QSplitter::saveState() const
+{
+ Q_D(const QSplitter);
+ int version = 0;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(SplitterMagic);
+ stream << qint32(version);
+ QList<int> list;
+ for (int i = 0; i < d->list.size(); ++i) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ list.append(s->sizer);
+ }
+ stream << list;
+ stream << childrenCollapsible();
+ stream << qint32(handleWidth());
+ stream << opaqueResize();
+ stream << qint32(orientation());
+ return data;
+}
+
+/*!
+ Restores the splitter's layout to the \a state specified.
+ Returns true if the state is restored; otherwise returns false.
+
+ Typically this is used in conjunction with QSettings to restore the size
+ from a past session. Here is an example:
+
+ Restore the splitters's state:
+
+ \snippet doc/src/snippets/splitter/splitter.cpp 2
+
+ A failure to restore the splitter's layout may result from either
+ invalid or out-of-date data in the supplied byte array.
+
+ \sa saveState()
+*/
+bool QSplitter::restoreState(const QByteArray &state)
+{
+ Q_D(QSplitter);
+ int version = 0;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ QList<int> list;
+ bool b;
+ qint32 i;
+ qint32 marker;
+ qint32 v;
+
+ stream >> marker;
+ stream >> v;
+ if (marker != SplitterMagic || v != version)
+ return false;
+
+ stream >> list;
+ d->setSizes_helper(list, false);
+
+ stream >> b;
+ setChildrenCollapsible(b);
+
+ stream >> i;
+ setHandleWidth(i);
+
+ stream >> b;
+ setOpaqueResize(b);
+
+ stream >> i;
+ setOrientation(Qt::Orientation(i));
+ d->doResize();
+
+ return true;
+}
+
+/*!
+ Updates the size policy of the widget at position \a index to
+ have a stretch factor of \a stretch.
+
+ \a stretch is not the effective stretch factor; the effective
+ stretch factor is calculated by taking the initial size of the
+ widget and multiplying it with \a stretch.
+
+ This function is provided for convenience. It is equivalent to
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qsplitter.cpp 0
+
+ \sa setSizes(), widget()
+*/
+void QSplitter::setStretchFactor(int index, int stretch)
+{
+ Q_D(QSplitter);
+ if (index <= -1 || index >= d->list.count())
+ return;
+
+ QWidget *widget = d->list.at(index)->widget;
+ QSizePolicy sp = widget->sizePolicy();
+ sp.setHorizontalStretch(stretch);
+ sp.setVerticalStretch(stretch);
+ widget->setSizePolicy(sp);
+}
+
+
+//#ifdef QT3_SUPPORT
+#ifndef QT_NO_TEXTSTREAM
+/*!
+ \relates QSplitter
+ \obsolete
+
+ Use \a ts << \a{splitter}.saveState() instead.
+*/
+
+QTextStream& operator<<(QTextStream& ts, const QSplitter& splitter)
+{
+ ts << splitter.saveState() << endl;
+ return ts;
+}
+
+/*!
+ \relates QSplitter
+ \obsolete
+
+ Use \a ts >> \a{splitter}.restoreState() instead.
+*/
+
+QTextStream& operator>>(QTextStream& ts, QSplitter& splitter)
+{
+ QString line = ts.readLine();
+ line = line.simplified();
+ line.replace(QLatin1Char(' '), QString());
+ line = line.toUpper();
+
+ splitter.restoreState(line.toAscii());
+ return ts;
+}
+#endif // QT_NO_TEXTSTREAM
+//#endif // QT3_SUPPORT
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SPLITTER
diff --git a/src/widgets/widgets/qsplitter.h b/src/widgets/widgets/qsplitter.h
new file mode 100644
index 0000000000..09d7d3589d
--- /dev/null
+++ b/src/widgets/widgets/qsplitter.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPLITTER_H
+#define QSPLITTER_H
+
+#include <QtWidgets/qframe.h>
+#include <QtWidgets/qsizepolicy.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_SPLITTER
+
+class QSplitterPrivate;
+class QTextStream;
+template <typename T> class QList;
+
+class QSplitterHandle;
+
+class Q_WIDGETS_EXPORT QSplitter : public QFrame
+{
+ Q_OBJECT
+
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize)
+ Q_PROPERTY(int handleWidth READ handleWidth WRITE setHandleWidth)
+ Q_PROPERTY(bool childrenCollapsible READ childrenCollapsible WRITE setChildrenCollapsible)
+
+public:
+ explicit QSplitter(QWidget* parent = 0);
+ explicit QSplitter(Qt::Orientation, QWidget* parent = 0);
+ ~QSplitter();
+
+ void addWidget(QWidget *widget);
+ void insertWidget(int index, QWidget *widget);
+
+ void setOrientation(Qt::Orientation);
+ Qt::Orientation orientation() const;
+
+ void setChildrenCollapsible(bool);
+ bool childrenCollapsible() const;
+
+ void setCollapsible(int index, bool);
+ bool isCollapsible(int index) const;
+ void setOpaqueResize(bool opaque = true);
+ bool opaqueResize() const;
+ void refresh();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QList<int> sizes() const;
+ void setSizes(const QList<int> &list);
+
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+ int handleWidth() const;
+ void setHandleWidth(int);
+
+ int indexOf(QWidget *w) const;
+ QWidget *widget(int index) const;
+ int count() const;
+
+ void getRange(int index, int *, int *) const;
+ QSplitterHandle *handle(int index) const;
+
+ void setStretchFactor(int index, int stretch);
+
+Q_SIGNALS:
+ void splitterMoved(int pos, int index);
+
+protected:
+ virtual QSplitterHandle *createHandle();
+
+ void childEvent(QChildEvent *);
+
+ bool event(QEvent *);
+ void resizeEvent(QResizeEvent *);
+
+ void changeEvent(QEvent *);
+ void moveSplitter(int pos, int index);
+ void setRubberBand(int position);
+ int closestLegalPosition(int, int);
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QSplitter(QWidget* parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QSplitter(Qt::Orientation, QWidget* parent, const char* name);
+ enum ResizeMode { Stretch, KeepSize, FollowSizeHint, Auto };
+ QT3_SUPPORT void setResizeMode(QWidget *w, ResizeMode mode);
+ inline QT3_SUPPORT void moveToFirst(QWidget *w) { insertWidget(0,w); }
+ inline QT3_SUPPORT void moveToLast(QWidget *w) { addWidget(w); }
+ inline QT3_SUPPORT void setCollapsible(QWidget *w, bool collapse)
+ { setCollapsible(indexOf(w), collapse); }
+ QT3_SUPPORT void setMargin(int margin) { setContentsMargins(margin, margin, margin, margin); }
+ QT3_SUPPORT int margin() const
+ { int margin; int dummy; getContentsMargins(&margin, &dummy, &dummy, &dummy); return margin; }
+#endif
+
+private:
+ Q_DISABLE_COPY(QSplitter)
+ Q_DECLARE_PRIVATE(QSplitter)
+private:
+ friend class QSplitterHandle;
+};
+
+//#ifdef QT3_SUPPORT
+#ifndef QT_NO_TEXTSTREAM
+Q_WIDGETS_EXPORT QTextStream& operator<<(QTextStream&, const QSplitter&);
+Q_WIDGETS_EXPORT QTextStream& operator>>(QTextStream&, QSplitter&);
+#endif
+//#endif
+
+class QSplitterHandlePrivate;
+class Q_WIDGETS_EXPORT QSplitterHandle : public QWidget
+{
+ Q_OBJECT
+public:
+ QSplitterHandle(Qt::Orientation o, QSplitter *parent);
+ void setOrientation(Qt::Orientation o);
+ Qt::Orientation orientation() const;
+ bool opaqueResize() const;
+ QSplitter *splitter() const;
+
+ QSize sizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void resizeEvent(QResizeEvent *);
+ bool event(QEvent *);
+
+ void moveSplitter(int p);
+ int closestLegalPosition(int p);
+
+private:
+ Q_DISABLE_COPY(QSplitterHandle)
+ Q_DECLARE_PRIVATE(QSplitterHandle)
+};
+
+#endif // QT_NO_SPLITTER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSPLITTER_H
diff --git a/src/widgets/widgets/qsplitter_p.h b/src/widgets/widgets/qsplitter_p.h
new file mode 100644
index 0000000000..05e7a35165
--- /dev/null
+++ b/src/widgets/widgets/qsplitter_p.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPLITTER_P_H
+#define QSPLITTER_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/qframe_p.h"
+#include "qrubberband.h"
+
+QT_BEGIN_NAMESPACE
+
+static const uint Default = 2;
+
+class QSplitterLayoutStruct
+{
+public:
+ QRect rect;
+ int sizer;
+ uint collapsed : 1;
+ uint collapsible : 2;
+ QWidget *widget;
+ QSplitterHandle *handle;
+
+ QSplitterLayoutStruct() : sizer(-1), collapsed(false), collapsible(Default), widget(0), handle(0) {}
+ ~QSplitterLayoutStruct() { delete handle; }
+ int getWidgetSize(Qt::Orientation orient);
+ int getHandleSize(Qt::Orientation orient);
+ int pick(const QSize &size, Qt::Orientation orient)
+ { return (orient == Qt::Horizontal) ? size.width() : size.height(); }
+};
+
+class QSplitterPrivate : public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QSplitter)
+public:
+ QSplitterPrivate() : rubberBand(0), opaque(true), firstShow(true),
+ childrenCollapsible(true), compatMode(false), handleWidth(0), blockChildAdd(false) {}
+
+ QPointer<QRubberBand> rubberBand;
+ mutable QList<QSplitterLayoutStruct *> list;
+ Qt::Orientation orient;
+ bool opaque : 8;
+ bool firstShow : 8;
+ bool childrenCollapsible : 8;
+ bool compatMode : 8;
+ int handleWidth;
+ bool blockChildAdd;
+
+ inline int pick(const QPoint &pos) const
+ { return orient == Qt::Horizontal ? pos.x() : pos.y(); }
+ inline int pick(const QSize &s) const
+ { return orient == Qt::Horizontal ? s.width() : s.height(); }
+
+ inline int trans(const QPoint &pos) const
+ { return orient == Qt::Vertical ? pos.x() : pos.y(); }
+ inline int trans(const QSize &s) const
+ { return orient == Qt::Vertical ? s.width() : s.height(); }
+
+ void init();
+ void recalc(bool update = false);
+ void doResize();
+ void storeSizes();
+ void getRange(int index, int *, int *, int *, int *) const;
+ void addContribution(int, int *, int *, bool) const;
+ int adjustPos(int, int, int *, int *, int *, int *) const;
+ bool collapsible(QSplitterLayoutStruct *) const;
+ bool collapsible(int index) const
+ { return (index < 0 || index >= list.size()) ? true : collapsible(list.at(index)); }
+ QSplitterLayoutStruct *findWidget(QWidget *) const;
+ void insertWidget_helper(int index, QWidget *widget, bool show);
+ QSplitterLayoutStruct *insertWidget(int index, QWidget *);
+ void doMove(bool backwards, int pos, int index, int delta,
+ bool mayCollapse, int *positions, int *widths);
+ void setGeo(QSplitterLayoutStruct *s, int pos, int size, bool allowCollapse);
+ int findWidgetJustBeforeOrJustAfter(int index, int delta, int &collapsibleSize) const;
+ void updateHandles();
+ void setSizes_helper(const QList<int> &sizes, bool clampNegativeSize = false);
+
+};
+
+class QSplitterHandlePrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QSplitterHandle)
+public:
+ QSplitterHandlePrivate() : s(0), orient(Qt::Horizontal), mouseOffset(0), opaq(false), hover(false), pressed(false) {}
+
+ inline int pick(const QPoint &pos) const
+ { return orient == Qt::Horizontal ? pos.x() : pos.y(); }
+
+ QSplitter *s;
+ Qt::Orientation orient;
+ int mouseOffset;
+ bool opaq : 1;
+ bool hover : 1;
+ bool pressed : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/widgets/qstackedwidget.cpp b/src/widgets/widgets/qstackedwidget.cpp
new file mode 100644
index 0000000000..c4bf79a1c4
--- /dev/null
+++ b/src/widgets/widgets/qstackedwidget.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstackedwidget.h"
+
+#ifndef QT_NO_STACKEDWIDGET
+
+#include <qstackedlayout.h>
+#include <qevent.h>
+#include <private/qframe_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/**
+ QStackedLayout does not support height for width (simply because it does not reimplement
+ heightForWidth() and hasHeightForWidth()). That is not possible to fix without breaking
+ binary compatibility. (QLayout is subject to multiple inheritance).
+ However, we can fix QStackedWidget by simply using a modified version of QStackedLayout
+ that reimplements the hfw-related functions:
+ */
+class QStackedLayoutHFW : public QStackedLayout
+{
+public:
+ QStackedLayoutHFW(QWidget *parent = 0) : QStackedLayout(parent) {}
+ bool hasHeightForWidth() const;
+ int heightForWidth(int width) const;
+};
+
+bool QStackedLayoutHFW::hasHeightForWidth() const
+{
+ const int n = count();
+
+ for (int i = 0; i < n; ++i) {
+ if (QLayoutItem *item = itemAt(i)) {
+ if (item->hasHeightForWidth())
+ return true;
+ }
+ }
+ return false;
+}
+
+int QStackedLayoutHFW::heightForWidth(int width) const
+{
+ const int n = count();
+
+ int hfw = 0;
+ for (int i = 0; i < n; ++i) {
+ if (QLayoutItem *item = itemAt(i)) {
+ hfw = qMax(hfw, item->heightForWidth(width));
+ }
+ }
+ return hfw;
+}
+
+
+class QStackedWidgetPrivate : public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QStackedWidget)
+public:
+ QStackedWidgetPrivate():layout(0){}
+ QStackedLayoutHFW *layout;
+ bool blockChildAdd;
+};
+
+/*!
+ \class QStackedWidget
+ \brief The QStackedWidget class provides a stack of widgets where
+ only one widget is visible at a time.
+
+ \ingroup organizers
+ \ingroup geomanagement
+
+
+ QStackedWidget can be used to create a user interface similar to
+ the one provided by QTabWidget. It is a convenience layout widget
+ built on top of the QStackedLayout class.
+
+ Like QStackedLayout, QStackedWidget can be constructed and
+ populated with a number of child widgets ("pages"):
+
+ \snippet doc/src/snippets/qstackedwidget/main.cpp 0
+ \snippet doc/src/snippets/qstackedwidget/main.cpp 2
+ \snippet doc/src/snippets/qstackedwidget/main.cpp 3
+
+ QStackedWidget 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 QStackedWidget's pages. For
+ example:
+
+ \snippet doc/src/snippets/qstackedwidget/main.cpp 1
+
+ When populating a stacked widget, 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 a widget from the stacked widget. The number of
+ widgets contained in the stacked widget, 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 stacked widget changes or a
+ widget is removed from the stacked widget, the currentChanged()
+ and widgetRemoved() signals are emitted respectively.
+
+ \sa QStackedLayout, QTabWidget, {Config Dialog Example}
+*/
+
+/*!
+ \fn void QStackedWidget::currentChanged(int index)
+
+ This signal is emitted whenever the current widget changes.
+
+ The parameter holds the \a index of the new current widget, or -1
+ if there isn't a new one (for example, if there are no widgets in
+ the QStackedWidget).
+
+ \sa currentWidget(), setCurrentWidget()
+*/
+
+/*!
+ \fn void QStackedWidget::widgetRemoved(int index)
+
+ This signal is emitted whenever a widget is removed. The widget's
+ \a index is passed as parameter.
+
+ \sa removeWidget()
+*/
+
+/*!
+ Constructs a QStackedWidget with the given \a parent.
+
+ \sa addWidget(), insertWidget()
+*/
+QStackedWidget::QStackedWidget(QWidget *parent)
+ : QFrame(*new QStackedWidgetPrivate, parent)
+{
+ Q_D(QStackedWidget);
+ d->layout = new QStackedLayoutHFW(this);
+ connect(d->layout, SIGNAL(widgetRemoved(int)), this, SIGNAL(widgetRemoved(int)));
+ connect(d->layout, SIGNAL(currentChanged(int)), this, SIGNAL(currentChanged(int)));
+}
+
+/*!
+ Destroys this stacked widget, and frees any allocated resources.
+*/
+QStackedWidget::~QStackedWidget()
+{
+}
+
+/*!
+ Appends the given \a widget to the QStackedWidget and returns the
+ index position. Ownership of \a widget is passed on to the
+ QStackedWidget.
+
+ If the QStackedWidget is empty before this function is called,
+ \a widget becomes the current widget.
+
+ \sa insertWidget(), removeWidget(), setCurrentWidget()
+*/
+int QStackedWidget::addWidget(QWidget *widget)
+{
+ return d_func()->layout->addWidget(widget);
+}
+
+/*!
+ Inserts the given \a widget at the given \a index in the
+ QStackedWidget. Ownership of \a widget is passed on to the
+ QStackedWidget. If \a index is out of range, the \a widget is
+ appended (in which case it is the actual index of the \a widget
+ that is returned).
+
+ If the QStackedWidget was 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 QStackedWidget::insertWidget(int index, QWidget *widget)
+{
+ return d_func()->layout->insertWidget(index, widget);
+}
+
+/*!
+ Removes \a widget from the QStackedWidget. i.e., \a widget is \e
+ not deleted but simply removed from the stacked layout, causing it
+ to be hidden.
+
+ \bold{Note:} Ownership of \a widget reverts to the application.
+
+ \sa addWidget(), insertWidget(), currentWidget()
+*/
+void QStackedWidget::removeWidget(QWidget *widget)
+{
+ d_func()->layout->removeWidget(widget);
+}
+
+/*!
+ \property QStackedWidget::currentIndex
+ \brief the index position of the widget that is visible
+
+ The current index is -1 if there is no current widget.
+
+ By default, this property contains a value of -1 because the stack
+ is initially empty.
+
+ \sa currentWidget(), indexOf()
+*/
+
+void QStackedWidget::setCurrentIndex(int index)
+{
+ d_func()->layout->setCurrentIndex(index);
+}
+
+int QStackedWidget::currentIndex() const
+{
+ return d_func()->layout->currentIndex();
+}
+
+/*!
+ Returns the current widget, or 0 if there are no child widgets.
+
+ \sa currentIndex(), setCurrentWidget()
+*/
+QWidget *QStackedWidget::currentWidget() const
+{
+ return d_func()->layout->currentWidget();
+}
+
+
+/*!
+ \fn void QStackedWidget::setCurrentWidget(QWidget *widget)
+
+ Sets the current widget to be the specified \a widget. The new
+ current widget must already be contained in this stacked widget.
+
+ \sa currentWidget(), setCurrentIndex()
+ */
+void QStackedWidget::setCurrentWidget(QWidget *widget)
+{
+ Q_D(QStackedWidget);
+ if (d->layout->indexOf(widget) == -1) {
+ qWarning("QStackedWidget::setCurrentWidget: widget %p not contained in stack", widget);
+ return;
+ }
+ d->layout->setCurrentWidget(widget);
+}
+
+/*!
+ Returns the index of the given \a widget, or -1 if the given \a
+ widget is not a child of the QStackedWidget.
+
+ \sa currentIndex(), widget()
+*/
+int QStackedWidget::indexOf(QWidget *widget) const
+{
+ return d_func()->layout->indexOf(widget);
+}
+
+/*!
+ Returns the widget at the given \a index, or 0 if there is no such
+ widget.
+
+ \sa currentWidget(), indexOf()
+*/
+QWidget *QStackedWidget::widget(int index) const
+{
+ return d_func()->layout->widget(index);
+}
+
+/*!
+ \property QStackedWidget::count
+ \brief the number of widgets contained by this stacked widget
+
+ By default, this property contains a value of 0.
+
+ \sa currentIndex(), widget()
+*/
+int QStackedWidget::count() const
+{
+ return d_func()->layout->count();
+}
+
+/*! \reimp */
+bool QStackedWidget::event(QEvent *e)
+{
+ return QFrame::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_STACKEDWIDGET
diff --git a/src/widgets/widgets/qstackedwidget.h b/src/widgets/widgets/qstackedwidget.h
new file mode 100644
index 0000000000..e0275fe27f
--- /dev/null
+++ b/src/widgets/widgets/qstackedwidget.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTACKEDWIDGET_H
+#define QSTACKEDWIDGET_H
+
+#include <QtWidgets/qframe.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_STACKEDWIDGET
+
+class QStackedWidgetPrivate;
+
+class Q_WIDGETS_EXPORT QStackedWidget : public QFrame
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged)
+ Q_PROPERTY(int count READ count)
+public:
+ explicit QStackedWidget(QWidget *parent=0);
+ ~QStackedWidget();
+
+ int addWidget(QWidget *w);
+ int insertWidget(int index, QWidget *w);
+ void removeWidget(QWidget *w);
+
+ QWidget *currentWidget() const;
+ int currentIndex() const;
+
+ int indexOf(QWidget *) const;
+ QWidget *widget(int) const;
+ int count() const;
+
+public Q_SLOTS:
+ void setCurrentIndex(int index);
+ void setCurrentWidget(QWidget *w);
+
+Q_SIGNALS:
+ void currentChanged(int);
+ void widgetRemoved(int index);
+
+protected:
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QStackedWidget)
+ Q_DECLARE_PRIVATE(QStackedWidget)
+};
+
+#endif // QT_NO_STACKEDWIDGET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSTACKEDWIDGET_H
diff --git a/src/widgets/widgets/qstatusbar.cpp b/src/widgets/widgets/qstatusbar.cpp
new file mode 100644
index 0000000000..dbf299a712
--- /dev/null
+++ b/src/widgets/widgets/qstatusbar.cpp
@@ -0,0 +1,847 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstatusbar.h"
+#ifndef QT_NO_STATUSBAR
+
+#include "qlist.h"
+#include "qdebug.h"
+#include "qevent.h"
+#include "qlayout.h"
+#include "qpainter.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qsizegrip.h"
+#include "qmainwindow.h"
+
+#include <private/qlayoutengine_p.h>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStatusBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QStatusBar)
+public:
+ QStatusBarPrivate() {}
+
+ struct SBItem {
+ SBItem(QWidget* widget, int stretch, bool permanent)
+ : s(stretch), w(widget), p(permanent) {}
+ int s;
+ QWidget * w;
+ bool p;
+ };
+
+ QList<SBItem *> items;
+ QString tempItem;
+
+ QBoxLayout * box;
+ QTimer * timer;
+
+#ifndef QT_NO_SIZEGRIP
+ QSizeGrip * resizer;
+ bool showSizeGrip;
+#endif
+
+ int savedStrut;
+
+#ifdef Q_WS_MAC
+ QPoint dragStart;
+#endif
+
+ int indexToLastNonPermanentWidget() const
+ {
+ int i = items.size() - 1;
+ for (; i >= 0; --i) {
+ SBItem *item = items.at(i);
+ if (!(item && item->p))
+ break;
+ }
+ return i;
+ }
+
+#ifndef QT_NO_SIZEGRIP
+ void tryToShowSizeGrip()
+ {
+ if (!showSizeGrip)
+ return;
+ showSizeGrip = false;
+ if (!resizer || resizer->isVisible())
+ return;
+ resizer->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ QMetaObject::invokeMethod(resizer, "_q_showIfNotHidden", Qt::DirectConnection);
+ resizer->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ }
+#endif
+
+ QRect messageRect() const;
+};
+
+
+QRect QStatusBarPrivate::messageRect() const
+{
+ Q_Q(const QStatusBar);
+ bool rtl = q->layoutDirection() == Qt::RightToLeft;
+
+ int left = 6;
+ int right = q->width() - 12;
+
+#ifndef QT_NO_SIZEGRIP
+ if (resizer && resizer->isVisible()) {
+ if (rtl)
+ left = resizer->x() + resizer->width();
+ else
+ right = resizer->x();
+ }
+#endif
+
+ for (int i=0; i<items.size(); ++i) {
+ QStatusBarPrivate::SBItem* item = items.at(i);
+ if (!item)
+ break;
+ if (item->p && item->w->isVisible()) {
+ if (item->p) {
+ if (rtl)
+ left = qMax(left, item->w->x() + item->w->width() + 2);
+ else
+ right = qMin(right, item->w->x() - 2);
+ }
+ break;
+ }
+ }
+ return QRect(left, 0, right-left, q->height());
+}
+
+
+/*!
+ \class QStatusBar
+ \brief The QStatusBar class provides a horizontal bar suitable for
+ presenting status information.
+
+ \ingroup mainwindow-classes
+ \ingroup helpsystem
+
+
+ Each status indicator falls into one of three categories:
+
+ \list
+ \o \e Temporary - briefly occupies most of the status bar. Used
+ to explain tool tip texts or menu entries, for example.
+ \o \e Normal - occupies part of the status bar and may be hidden
+ by temporary messages. Used to display the page and line
+ number in a word processor, for example.
+ \o \e Permanent - is never hidden. Used for important mode
+ indications, for example, some applications put a Caps Lock
+ indicator in the status bar.
+ \endlist
+
+ QStatusBar lets you display all three types of indicators.
+
+ Typically, a request for the status bar functionality occurs in
+ relation to a QMainWindow object. QMainWindow provides a main
+ application window, with a menu bar, tool bars, dock widgets \e
+ and a status bar around a large central widget. The status bar can
+ be retrieved using the QMainWindow::statusBar() function, and
+ replaced using the QMainWindow::setStatusBar() function.
+
+ Use the showMessage() slot to display a \e temporary message:
+
+ \snippet examples/mainwindows/dockwidgets/mainwindow.cpp 8
+
+ To remove a temporary message, use the clearMessage() slot, or set
+ a time limit when calling showMessage(). For example:
+
+ \snippet examples/mainwindows/dockwidgets/mainwindow.cpp 3
+
+ Use the currentMessage() function to retrieve the temporary
+ message currently shown. The QStatusBar class also provide the
+ messageChanged() signal which is emitted whenever the temporary
+ status message changes.
+
+ \target permanent message
+ \e Normal and \e Permanent messages are displayed by creating a
+ small widget (QLabel, QProgressBar or even QToolButton) and then
+ adding it to the status bar using the addWidget() or the
+ addPermanentWidget() function. Use the removeWidget() function to
+ remove such messages from the status bar.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qstatusbar.cpp 0
+
+ By default QStatusBar provides a QSizeGrip in the lower-right
+ corner. You can disable it using the setSizeGripEnabled()
+ function. Use the isSizeGripEnabled() function to determine the
+ current status of the size grip.
+
+ \image plastique-statusbar.png A status bar shown in the Plastique widget style
+
+ \sa QMainWindow, QStatusTipEvent, {fowler}{GUI Design Handbook:
+ Status Bar}, {Application Example}
+*/
+
+#ifdef QT3_SUPPORT
+/*!
+ Constructs a status bar with a size grip and the given \a parent
+ and object \a name.
+
+ Use the QStatusBar() constructor and the QObject::setObjectName()
+ function instead.
+
+ \oldcode
+ QStatusBar *myStatusBar = new QStatusBar(parent, name);
+ \newcode
+ QStatusBar *myStatusBar = new QStatusBar(parent);
+ myStatusBar->setObjectName(name);
+ \endcode
+*/
+QStatusBar::QStatusBar(QWidget * parent, const char *name)
+ : QWidget(*new QStatusBarPrivate, parent, 0)
+{
+ Q_D(QStatusBar);
+ setObjectName(QString::fromAscii(name));
+ d->box = 0;
+ d->timer = 0;
+
+#ifndef QT_NO_SIZEGRIP
+ d->resizer = 0;
+ d->showSizeGrip = false;
+ setSizeGripEnabled(true); // causes reformat()
+#else
+ reformat();
+#endif
+}
+
+
+/*!
+ \fn void QStatusBar::addWidget(QWidget * widget, int stretch, bool permanent)
+
+ Use addWidget() or addPermanentWidget() instead, depending on the
+ value of the \a permanent parameter.
+
+ \oldcode
+ QStatusBar *myStatusBar;
+ myStatusBar->addWidget(widget, stretch, permanent); // permanent == true
+ \newcode
+ QStatusBar *myStatusBar;
+ myStatusBar->addPermanentWidget(widget, stretch);
+ \endcode
+ */
+
+#endif
+
+/*!
+ Constructs a status bar with a size grip and the given \a parent.
+
+ \sa setSizeGripEnabled()
+*/
+QStatusBar::QStatusBar(QWidget * parent)
+ : QWidget(*new QStatusBarPrivate, parent, 0)
+{
+ Q_D(QStatusBar);
+ d->box = 0;
+ d->timer = 0;
+
+#ifndef QT_NO_SIZEGRIP
+ d->resizer = 0;
+ setSizeGripEnabled(true); // causes reformat()
+#else
+ reformat();
+#endif
+}
+
+/*!
+ Destroys this status bar and frees any allocated resources and
+ child widgets.
+*/
+QStatusBar::~QStatusBar()
+{
+ Q_D(QStatusBar);
+ while (!d->items.isEmpty())
+ delete d->items.takeFirst();
+}
+
+
+/*!
+ Adds the given \a widget to this status bar, reparenting the
+ widget if it isn't already a child of this QStatusBar object. The
+ \a stretch parameter is used to compute a suitable size for the
+ given \a widget as the status bar grows and shrinks. The default
+ stretch factor is 0, i.e giving the widget a minimum of space.
+
+ The widget is located to the far left of the first permanent
+ widget (see addPermanentWidget()) and may be obscured by temporary
+ messages.
+
+ \sa insertWidget(), removeWidget(), addPermanentWidget()
+*/
+
+void QStatusBar::addWidget(QWidget * widget, int stretch)
+{
+ if (!widget)
+ return;
+ insertWidget(d_func()->indexToLastNonPermanentWidget() + 1, widget, stretch);
+}
+
+/*!
+ \since 4.2
+
+ Inserts the given \a widget at the given \a index to this status bar,
+ reparenting the widget if it isn't already a child of this
+ QStatusBar object. If \a index is out of range, the widget is appended
+ (in which case it is the actual index of the widget that is returned).
+
+ The \a stretch parameter is used to compute a suitable size for
+ the given \a widget as the status bar grows and shrinks. The
+ default stretch factor is 0, i.e giving the widget a minimum of
+ space.
+
+ The widget is located to the far left of the first permanent
+ widget (see addPermanentWidget()) and may be obscured by temporary
+ messages.
+
+ \sa addWidget(), removeWidget(), addPermanentWidget()
+*/
+int QStatusBar::insertWidget(int index, QWidget *widget, int stretch)
+{
+ if (!widget)
+ return -1;
+
+ Q_D(QStatusBar);
+ QStatusBarPrivate::SBItem* item = new QStatusBarPrivate::SBItem(widget, stretch, false);
+
+ int idx = d->indexToLastNonPermanentWidget();
+ if (index < 0 || index > d->items.size() || (idx >= 0 && index > idx + 1)) {
+ qWarning("QStatusBar::insertWidget: Index out of range (%d), appending widget", index);
+ index = idx + 1;
+ }
+ d->items.insert(index, item);
+
+ if (!d->tempItem.isEmpty())
+ widget->hide();
+
+ reformat();
+ if (!widget->isHidden() || !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
+ widget->show();
+
+ return index;
+}
+
+/*!
+ Adds the given \a widget permanently to this status bar,
+ reparenting the widget if it isn't already a child of this
+ QStatusBar object. The \a stretch parameter is used to compute a
+ suitable size for the given \a widget as the status bar grows and
+ shrinks. The default stretch factor is 0, i.e giving the widget a
+ minimum of space.
+
+ Permanently means that the widget may not be obscured by temporary
+ messages. It is is located at the far right of the status bar.
+
+ \sa insertPermanentWidget(), removeWidget(), addWidget()
+*/
+
+void QStatusBar::addPermanentWidget(QWidget * widget, int stretch)
+{
+ if (!widget)
+ return;
+ insertPermanentWidget(d_func()->items.size(), widget, stretch);
+}
+
+
+/*!
+ \since 4.2
+
+ Inserts the given \a widget at the given \a index permanently to this status bar,
+ reparenting the widget if it isn't already a child of this
+ QStatusBar object. If \a index is out of range, the widget is appended
+ (in which case it is the actual index of the widget that is returned).
+
+ The \a stretch parameter is used to compute a
+ suitable size for the given \a widget as the status bar grows and
+ shrinks. The default stretch factor is 0, i.e giving the widget a
+ minimum of space.
+
+ Permanently means that the widget may not be obscured by temporary
+ messages. It is is located at the far right of the status bar.
+
+ \sa addPermanentWidget(), removeWidget(), addWidget()
+*/
+int QStatusBar::insertPermanentWidget(int index, QWidget *widget, int stretch)
+{
+ if (!widget)
+ return -1;
+
+ Q_D(QStatusBar);
+ QStatusBarPrivate::SBItem* item = new QStatusBarPrivate::SBItem(widget, stretch, true);
+
+ int idx = d->indexToLastNonPermanentWidget();
+ if (index < 0 || index > d->items.size() || (idx >= 0 && index <= idx)) {
+ qWarning("QStatusBar::insertPermanentWidget: Index out of range (%d), appending widget", index);
+ index = d->items.size();
+ }
+ d->items.insert(index, item);
+
+ reformat();
+ if (!widget->isHidden() || !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
+ widget->show();
+
+ return index;
+}
+
+/*!
+ Removes the specified \a widget from the status bar.
+
+ \note This function does not delete the widget but \e hides it.
+ To add the widget again, you must call both the addWidget() and
+ show() functions.
+
+ \sa addWidget(), addPermanentWidget(), clearMessage()
+*/
+
+void QStatusBar::removeWidget(QWidget *widget)
+{
+ if (!widget)
+ return;
+
+ Q_D(QStatusBar);
+ bool found = false;
+ QStatusBarPrivate::SBItem* item;
+ for (int i=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item)
+ break;
+ if (item->w == widget) {
+ d->items.removeAt(i);
+ item->w->hide();
+ delete item;
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ reformat();
+#if defined(QT_DEBUG)
+ else
+ qDebug("QStatusBar::removeWidget(): Widget not found.");
+#endif
+}
+
+/*!
+ \property QStatusBar::sizeGripEnabled
+
+ \brief whether the QSizeGrip in the bottom-right corner of the
+ status bar is enabled
+
+ The size grip is enabled by default.
+*/
+
+bool QStatusBar::isSizeGripEnabled() const
+{
+#ifdef QT_NO_SIZEGRIP
+ return false;
+#else
+ Q_D(const QStatusBar);
+ return !!d->resizer;
+#endif
+}
+
+void QStatusBar::setSizeGripEnabled(bool enabled)
+{
+#ifdef QT_NO_SIZEGRIP
+ Q_UNUSED(enabled);
+#else
+ Q_D(QStatusBar);
+ if (!enabled != !d->resizer) {
+ if (enabled) {
+ d->resizer = new QSizeGrip(this);
+ d->resizer->hide();
+ d->resizer->installEventFilter(this);
+ d->showSizeGrip = true;
+ } else {
+ delete d->resizer;
+ d->resizer = 0;
+ d->showSizeGrip = false;
+ }
+ reformat();
+ if (d->resizer && isVisible())
+ d->tryToShowSizeGrip();
+ }
+#endif
+}
+
+
+/*!
+ Changes the status bar's appearance to account for item changes.
+
+ Special subclasses may need this function, but geometry management
+ will usually take care of any necessary rearrangements.
+*/
+void QStatusBar::reformat()
+{
+ Q_D(QStatusBar);
+ if (d->box)
+ delete d->box;
+
+ QBoxLayout *vbox;
+#ifndef QT_NO_SIZEGRIP
+ if (d->resizer) {
+ d->box = new QHBoxLayout(this);
+ d->box->setMargin(0);
+ vbox = new QVBoxLayout;
+ d->box->addLayout(vbox);
+ } else
+#endif
+ {
+ vbox = d->box = new QVBoxLayout(this);
+ d->box->setMargin(0);
+ }
+ vbox->addSpacing(3);
+ QBoxLayout* l = new QHBoxLayout;
+ vbox->addLayout(l);
+ l->addSpacing(2);
+ l->setSpacing(6);
+
+ int maxH = fontMetrics().height();
+
+ int i;
+ QStatusBarPrivate::SBItem* item;
+ for (i=0,item=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item || item->p)
+ break;
+ l->addWidget(item->w, item->s);
+ int itemH = qMin(qSmartMinSize(item->w).height(), item->w->maximumHeight());
+ maxH = qMax(maxH, itemH);
+ }
+
+ l->addStretch(0);
+
+ for (item=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item)
+ break;
+ l->addWidget(item->w, item->s);
+ int itemH = qMin(qSmartMinSize(item->w).height(), item->w->maximumHeight());
+ maxH = qMax(maxH, itemH);
+ }
+#ifndef QT_NO_SIZEGRIP
+ if (d->resizer) {
+ maxH = qMax(maxH, d->resizer->sizeHint().height());
+ d->box->addSpacing(1);
+ d->box->addWidget(d->resizer, 0, Qt::AlignBottom);
+ }
+#endif
+ l->addStrut(maxH);
+ d->savedStrut = maxH;
+ vbox->addSpacing(2);
+ d->box->activate();
+ update();
+}
+
+/*!
+
+ Hides the normal status indications and displays the given \a
+ message for the specified number of milli-seconds (\a{timeout}). If
+ \a{timeout} is 0 (default), the \a {message} remains displayed until
+ the clearMessage() slot is called or until the showMessage() slot is
+ called again to change the message.
+
+ Note that showMessage() is called to show temporary explanations of
+ tool tip texts, so passing a \a{timeout} of 0 is not sufficient to
+ display a \l{permanent message}{permanent message}.
+
+ \sa messageChanged(), currentMessage(), clearMessage()
+*/
+void QStatusBar::showMessage(const QString &message, int timeout)
+{
+ Q_D(QStatusBar);
+ if (d->tempItem == message)
+ return;
+
+ d->tempItem = message;
+
+ if (timeout > 0) {
+ if (!d->timer) {
+ d->timer = new QTimer(this);
+ connect(d->timer, SIGNAL(timeout()), this, SLOT(clearMessage()));
+ }
+ d->timer->start(timeout);
+ } else if (d->timer) {
+ delete d->timer;
+ d->timer = 0;
+ }
+
+ hideOrShow();
+}
+
+/*!
+ Removes any temporary message being shown.
+
+ \sa currentMessage(), showMessage(), removeWidget()
+*/
+
+void QStatusBar::clearMessage()
+{
+ Q_D(QStatusBar);
+ if (d->tempItem.isEmpty())
+ return;
+ if (d->timer) {
+ qDeleteInEventHandler(d->timer);
+ d->timer = 0;
+ }
+ d->tempItem.clear();
+ hideOrShow();
+}
+
+/*!
+ Returns the temporary message currently shown,
+ or an empty string if there is no such message.
+
+ \sa showMessage()
+*/
+QString QStatusBar::currentMessage() const
+{
+ Q_D(const QStatusBar);
+ return d->tempItem;
+}
+
+/*!
+ \fn void QStatusBar::message(const QString &message, int timeout)
+
+ Use the showMessage() function instead.
+*/
+
+/*!
+ \fn void QStatusBar::clear()
+
+ Use the clearMessage() function instead.
+*/
+
+/*!
+ \fn QStatusBar::messageChanged(const QString &message)
+
+ This signal is emitted whenever the temporary status message
+ changes. The new temporary message is passed in the \a message
+ parameter which is a null-string when the message has been
+ removed.
+
+ \sa showMessage(), clearMessage()
+*/
+
+/*!
+ Ensures that the right widgets are visible.
+
+ Used by the showMessage() and clearMessage() functions.
+*/
+void QStatusBar::hideOrShow()
+{
+ Q_D(QStatusBar);
+ bool haveMessage = !d->tempItem.isEmpty();
+
+ QStatusBarPrivate::SBItem* item = 0;
+ for (int i=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item || item->p)
+ break;
+ if (haveMessage && item->w->isVisible()) {
+ item->w->hide();
+ item->w->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ } else if (!haveMessage && !item->w->testAttribute(Qt::WA_WState_ExplicitShowHide)) {
+ item->w->show();
+ }
+ }
+
+ emit messageChanged(d->tempItem);
+ repaint(d->messageRect());
+}
+
+/*!
+ \reimp
+ */
+void QStatusBar::showEvent(QShowEvent *)
+{
+#ifndef QT_NO_SIZEGRIP
+ Q_D(QStatusBar);
+ if (d->resizer && d->showSizeGrip)
+ d->tryToShowSizeGrip();
+#endif
+}
+
+/*!
+ \reimp
+ \fn void QStatusBar::paintEvent(QPaintEvent *event)
+
+ Shows the temporary message, if appropriate, in response to the
+ paint \a event.
+*/
+void QStatusBar::paintEvent(QPaintEvent *event)
+{
+ Q_D(QStatusBar);
+ bool haveMessage = !d->tempItem.isEmpty();
+
+ QPainter p(this);
+ QStyleOption opt;
+ opt.initFrom(this);
+ style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this);
+
+ for (int i=0; i<d->items.size(); ++i) {
+ QStatusBarPrivate::SBItem* item = d->items.at(i);
+ if (item && item->w->isVisible() && (!haveMessage || item->p)) {
+ QRect ir = item->w->geometry().adjusted(-2, -1, 2, 1);
+ if (event->rect().intersects(ir)) {
+ QStyleOption opt(0);
+ opt.rect = ir;
+ opt.palette = palette();
+ opt.state = QStyle::State_None;
+ style()->drawPrimitive(QStyle::PE_FrameStatusBarItem, &opt, &p, item->w);
+ }
+ }
+ }
+ if (haveMessage) {
+ p.setPen(palette().foreground().color());
+ p.drawText(d->messageRect(), Qt::AlignLeading | Qt::AlignVCenter | Qt::TextSingleLine, d->tempItem);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QStatusBar::resizeEvent(QResizeEvent * e)
+{
+ QWidget::resizeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+
+bool QStatusBar::event(QEvent *e)
+{
+ Q_D(QStatusBar);
+
+ if (e->type() == QEvent::LayoutRequest
+#ifdef QT3_SUPPORT
+ || e->type() == QEvent::LayoutHint
+#endif
+ ) {
+ // Calculate new strut height and call reformat() if it has changed
+ int maxH = fontMetrics().height();
+
+ QStatusBarPrivate::SBItem* item = 0;
+ for (int i=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item)
+ break;
+ int itemH = qMin(qSmartMinSize(item->w).height(), item->w->maximumHeight());
+ maxH = qMax(maxH, itemH);
+ }
+
+#ifndef QT_NO_SIZEGRIP
+ if (d->resizer)
+ maxH = qMax(maxH, d->resizer->sizeHint().height());
+#endif
+
+ if (maxH != d->savedStrut)
+ reformat();
+ else
+ update();
+ }
+ if (e->type() == QEvent::ChildRemoved) {
+ QStatusBarPrivate::SBItem* item = 0;
+ for (int i=0; i<d->items.size(); ++i) {
+ item = d->items.at(i);
+ if (!item)
+ break;
+ if (item->w == ((QChildEvent*)e)->child()) {
+ d->items.removeAt(i);
+ delete item;
+ }
+ }
+ }
+
+// On Mac OS X Leopard it is possible to drag the window by clicking
+// on the tool bar on most applications.
+#ifndef Q_WS_MAC
+ return QWidget::event(e);
+#else
+ if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4)
+ return QWidget::event(e);
+
+ // Enable drag-click only if the status bar is the status bar for a
+ // QMainWindow with a unifed toolbar.
+ if (parent() == 0 || qobject_cast<QMainWindow *>(parent()) == 0 ||
+ qobject_cast<QMainWindow *>(parent())->unifiedTitleAndToolBarOnMac() == false )
+ return QWidget::event(e);
+
+ // Check for mouse events.
+ QMouseEvent *mouseEvent;
+ if (e->type() == QEvent::MouseButtonPress ||
+ e->type() == QEvent::MouseMove ||
+ e->type() == QEvent::MouseButtonRelease) {
+ mouseEvent = static_cast <QMouseEvent*>(e);
+ } else {
+ return QWidget::event(e);
+ }
+
+ // The following is a standard mouse drag handler.
+ if (e->type() == QEvent::MouseButtonPress && (mouseEvent->button() == Qt::LeftButton)) {
+ d->dragStart = mouseEvent->pos();
+ } else if (e->type() == QEvent::MouseMove){
+ if (d->dragStart == QPoint())
+ return QWidget::event(e);
+ QPoint pos = mouseEvent->pos();
+ QPoint delta = (pos - d->dragStart);
+ window()->move(window()->pos() + delta);
+ } else if (e->type() == QEvent::MouseButtonRelease && (mouseEvent->button() == Qt::LeftButton)){
+ d->dragStart = QPoint();
+ } else {
+ return QWidget::event(e);
+ }
+
+ return true;
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/widgets/qstatusbar.h b/src/widgets/widgets/qstatusbar.h
new file mode 100644
index 0000000000..32dfed8f7b
--- /dev/null
+++ b/src/widgets/widgets/qstatusbar.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATUSBAR_H
+#define QSTATUSBAR_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_STATUSBAR
+
+class QStatusBarPrivate;
+
+class Q_WIDGETS_EXPORT QStatusBar: public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool sizeGripEnabled READ isSizeGripEnabled WRITE setSizeGripEnabled)
+
+public:
+ explicit QStatusBar(QWidget* parent=0);
+ virtual ~QStatusBar();
+
+ void addWidget(QWidget *widget, int stretch = 0);
+ int insertWidget(int index, QWidget *widget, int stretch = 0);
+ void addPermanentWidget(QWidget *widget, int stretch = 0);
+ int insertPermanentWidget(int index, QWidget *widget, int stretch = 0);
+ void removeWidget(QWidget *widget);
+
+ void setSizeGripEnabled(bool);
+ bool isSizeGripEnabled() const;
+
+ QString currentMessage() const;
+
+public Q_SLOTS:
+ void showMessage(const QString &text, int timeout = 0);
+ void clearMessage();
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QStatusBar(QWidget* parent, const char* name);
+ QT3_SUPPORT void addWidget(QWidget *w, int stretch, bool permanent)
+ { if (permanent) addPermanentWidget(w, stretch); else addWidget(w, stretch); }
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void message(const QString &text, int timeout = 0) { showMessage(text, timeout); }
+ inline QT_MOC_COMPAT void clear() { clearMessage(); }
+#endif
+
+Q_SIGNALS:
+ void messageChanged(const QString &text);
+
+protected:
+ void showEvent(QShowEvent *);
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+
+ // ### Qt 5: consider making reformat() and hideOrShow() private
+ void reformat();
+ void hideOrShow();
+ bool event(QEvent *);
+
+private:
+ Q_DISABLE_COPY(QStatusBar)
+ Q_DECLARE_PRIVATE(QStatusBar)
+};
+
+#endif // QT_NO_STATUSBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSTATUSBAR_H
diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp
new file mode 100644
index 0000000000..8faf156608
--- /dev/null
+++ b/src/widgets/widgets/qtabbar.cpp
@@ -0,0 +1,2376 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qlayoutengine_p.h"
+#include "qabstractitemdelegate.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qcursor.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qstylepainter.h"
+#include "qtabwidget.h"
+#include "qtooltip.h"
+#include "qwhatsthis.h"
+#include "private/qtextengine_p.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+#include "qdebug.h"
+#include "private/qtabbar_p.h"
+
+#ifndef QT_NO_TABBAR
+
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#ifndef QT_NO_STYLE_S60
+#include "qs60style.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+
+inline static bool verticalTabs(QTabBar::Shape shape)
+{
+ return shape == QTabBar::RoundedWest
+ || shape == QTabBar::RoundedEast
+ || shape == QTabBar::TriangularWest
+ || shape == QTabBar::TriangularEast;
+}
+
+void QTabBarPrivate::updateMacBorderMetrics()
+{
+#if (defined Q_WS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
+ Q_Q(QTabBar);
+ ::HIContentBorderMetrics metrics;
+
+ // TODO: get metrics to preserve the bottom value
+ // TODO: test tab bar position
+
+ OSWindowRef window = qt_mac_window_for(q);
+
+ // push base line separator down to the client are so we can paint over it (Carbon)
+ metrics.top = (documentMode && q->isVisible()) ? 1 : 0;
+ metrics.bottom = 0;
+ metrics.left = 0;
+ metrics.right = 0;
+ qt_mac_updateContentBorderMetricts(window, metrics);
+#if QT_MAC_USE_COCOA
+ // In Cocoa we need to keep track of the drawRect method.
+ // If documentMode is enabled we need to change it, unless
+ // a toolbar is present.
+ // Notice that all the information is kept in the window,
+ // that's why we get the private widget for it instead of
+ // the private widget for this widget.
+ QWidgetPrivate *privateWidget = qt_widget_private(q->window());
+ if(privateWidget)
+ privateWidget->changeMethods = documentMode;
+ // Since in Cocoa there is no simple way to remove the baseline, so we just ask the
+ // top level to do the magic for us.
+ privateWidget->syncUnifiedMode();
+#endif // QT_MAC_USE_COCOA
+ }
+#endif
+}
+
+/*!
+ Initialize \a option with the values from the tab at \a tabIndex. This method
+ is useful for subclasses when they need a QStyleOptionTab, QStyleOptionTabV2,
+ or QStyleOptionTabV3 but don't want to fill in all the information themselves.
+ This function will check the version of the QStyleOptionTab and fill in the
+ additional values for a QStyleOptionTabV2 and QStyleOptionTabV3.
+
+ \sa QStyleOption::initFrom() QTabWidget::initStyleOption()
+*/
+void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const
+{
+ Q_D(const QTabBar);
+ int totalTabs = d->tabList.size();
+
+ if (!option || (tabIndex < 0 || tabIndex >= totalTabs))
+ return;
+
+ const QTabBarPrivate::Tab &tab = d->tabList.at(tabIndex);
+ option->initFrom(this);
+ option->state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
+ option->rect = tabRect(tabIndex);
+ bool isCurrent = tabIndex == d->currentIndex;
+ option->row = 0;
+ if (tabIndex == d->pressedIndex)
+ option->state |= QStyle::State_Sunken;
+ if (isCurrent)
+ option->state |= QStyle::State_Selected;
+ if (isCurrent && hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ if (!tab.enabled)
+ option->state &= ~QStyle::State_Enabled;
+ if (isActiveWindow())
+ option->state |= QStyle::State_Active;
+ if (!d->dragInProgress && option->rect == d->hoverRect)
+ option->state |= QStyle::State_MouseOver;
+ option->shape = d->shape;
+ option->text = tab.text;
+
+ if (tab.textColor.isValid())
+ option->palette.setColor(foregroundRole(), tab.textColor);
+
+ option->icon = tab.icon;
+ if (QStyleOptionTabV2 *optionV2 = qstyleoption_cast<QStyleOptionTabV2 *>(option))
+ optionV2->iconSize = iconSize(); // Will get the default value then.
+
+ if (QStyleOptionTabV3 *optionV3 = qstyleoption_cast<QStyleOptionTabV3 *>(option)) {
+ optionV3->leftButtonSize = tab.leftWidget ? tab.leftWidget->size() : QSize();
+ optionV3->rightButtonSize = tab.rightWidget ? tab.rightWidget->size() : QSize();
+ optionV3->documentMode = d->documentMode;
+ }
+
+ if (tabIndex > 0 && tabIndex - 1 == d->currentIndex)
+ option->selectedPosition = QStyleOptionTab::PreviousIsSelected;
+ else if (tabIndex + 1 < totalTabs && tabIndex + 1 == d->currentIndex)
+ option->selectedPosition = QStyleOptionTab::NextIsSelected;
+ else
+ option->selectedPosition = QStyleOptionTab::NotAdjacent;
+
+ bool paintBeginning = (tabIndex == 0) || (d->dragInProgress && tabIndex == d->pressedIndex + 1);
+ bool paintEnd = (tabIndex == totalTabs - 1) || (d->dragInProgress && tabIndex == d->pressedIndex - 1);
+ if (paintBeginning) {
+ if (paintEnd)
+ option->position = QStyleOptionTab::OnlyOneTab;
+ else
+ option->position = QStyleOptionTab::Beginning;
+ } else if (paintEnd) {
+ option->position = QStyleOptionTab::End;
+ } else {
+ option->position = QStyleOptionTab::Middle;
+ }
+
+#ifndef QT_NO_TABWIDGET
+ if (const QTabWidget *tw = qobject_cast<const QTabWidget *>(parentWidget())) {
+ if (tw->cornerWidget(Qt::TopLeftCorner) || tw->cornerWidget(Qt::BottomLeftCorner))
+ option->cornerWidgets |= QStyleOptionTab::LeftCornerWidget;
+ if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner))
+ option->cornerWidgets |= QStyleOptionTab::RightCornerWidget;
+ }
+#endif
+
+ QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option, this);
+ option->text = fontMetrics().elidedText(option->text, d->elideMode, textRect.width(),
+ Qt::TextShowMnemonic);
+}
+
+/*!
+ \class QTabBar
+ \brief The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
+
+ \ingroup basicwidgets
+
+
+ QTabBar is straightforward to use; it draws the tabs using one of
+ the predefined \link QTabBar::Shape shapes\endlink, and emits a
+ signal when a tab is selected. It can be subclassed to tailor the
+ look and feel. Qt also provides a ready-made \l{QTabWidget}.
+
+ Each tab has a tabText(), an optional tabIcon(), an optional
+ tabToolTip(), optional tabWhatsThis() and optional tabData().
+ The tabs's attributes can be changed with setTabText(), setTabIcon(),
+ setTabToolTip(), setTabWhatsThis and setTabData(). Each tabs can be
+ enabled or disabled individually with setTabEnabled().
+
+ Each tab can display text in a distinct color. The current text color
+ for a tab can be found with the tabTextColor() function. Set the text
+ color for a particular tab with setTabTextColor().
+
+ Tabs are added using addTab(), or inserted at particular positions
+ using insertTab(). The total number of tabs is given by
+ count(). Tabs can be removed from the tab bar with
+ removeTab(). Combining removeTab() and insertTab() allows you to
+ move tabs to different positions.
+
+ The \l shape property defines the tabs' appearance. The choice of
+ shape is a matter of taste, although tab dialogs (for preferences
+ and similar) invariably use \l RoundedNorth.
+ Tab controls in windows other than dialogs almost
+ always use either \l RoundedSouth or \l TriangularSouth. Many
+ spreadsheets and other tab controls in which all the pages are
+ essentially similar use \l TriangularSouth, whereas \l
+ RoundedSouth is used mostly when the pages are different (e.g. a
+ multi-page tool palette). The default in QTabBar is \l
+ RoundedNorth.
+
+ The most important part of QTabBar's API is the currentChanged()
+ signal. This is emitted whenever the current tab changes (even at
+ startup, when the current tab changes from 'none'). There is also
+ a slot, setCurrentIndex(), which can be used to select a tab
+ programmatically. The function currentIndex() returns the index of
+ the current tab, \l count holds the number of tabs.
+
+ QTabBar creates automatic mnemonic keys in the manner of QAbstractButton;
+ e.g. if a tab's label is "\&Graphics", Alt+G becomes a shortcut
+ key for switching to that tab.
+
+ The following virtual functions may need to be reimplemented in
+ order to tailor the look and feel or store extra data with each
+ tab:
+
+ \list
+ \i tabSizeHint() calcuates the size of a tab.
+ \i tabInserted() notifies that a new tab was added.
+ \i tabRemoved() notifies that a tab was removed.
+ \i tabLayoutChange() notifies that the tabs have been re-laid out.
+ \i paintEvent() paints all tabs.
+ \endlist
+
+ For subclasses, you might also need the tabRect() functions which
+ returns the visual geometry of a single tab.
+
+ \table 100%
+ \row \o \inlineimage plastique-tabbar.png Screenshot of a Plastique style tab bar
+ \o A tab bar shown in the Plastique widget style.
+ \row \o \inlineimage plastique-tabbar-truncated.png Screenshot of a truncated Plastique tab bar
+ \o A truncated tab bar shown in the Plastique widget style.
+ \endtable
+
+ \sa QTabWidget
+*/
+
+/*!
+ \enum QTabBar::Shape
+
+ This enum type lists the built-in shapes supported by QTabBar. Treat these
+ as hints as some styles may not render some of the shapes. However,
+ position should be honored.
+
+ \value RoundedNorth The normal rounded look above the pages
+
+ \value RoundedSouth The normal rounded look below the pages
+
+ \value RoundedWest The normal rounded look on the left side of the pages
+
+ \value RoundedEast The normal rounded look on the right side the pages
+
+ \value TriangularNorth Triangular tabs above the pages.
+
+ \value TriangularSouth Triangular tabs similar to those used in
+ the Excel spreadsheet, for example
+
+ \value TriangularWest Triangular tabs on the left of the pages.
+
+ \value TriangularEast Triangular tabs on the right of the pages.
+ \omitvalue RoundedAbove
+ \omitvalue RoundedBelow
+ \omitvalue TriangularAbove
+ \omitvalue TriangularBelow
+*/
+
+/*!
+ \fn void QTabBar::currentChanged(int index)
+
+ This signal is emitted when the tab bar's current tab changes. The
+ new current has the given \a index, or -1 if there isn't a new one
+ (for example, if there are no tab in the QTabBar)
+*/
+
+/*!
+ \fn void QTabBar::tabCloseRequested(int index)
+ \since 4.5
+
+ This signal is emitted when the close button on a tab is clicked.
+ The \a index is the index that should be removed.
+
+ \sa setTabsClosable()
+*/
+
+/*!
+ \fn void QTabBar::tabMoved(int from, int to)
+ \since 4.5
+
+ This signal is emitted when the tab has moved the tab
+ at index position \a from to index position \a to.
+
+ note: QTabWidget will automatically move the page when
+ this signal is emitted from its tab bar.
+
+ \sa moveTab()
+*/
+
+int QTabBarPrivate::extraWidth() const
+{
+ Q_Q(const QTabBar);
+ return 2 * qMax(q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, q),
+ QApplication::globalStrut().width());
+}
+
+void QTabBarPrivate::init()
+{
+ Q_Q(QTabBar);
+ leftB = new QToolButton(q);
+ leftB->setAutoRepeat(true);
+ QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
+ leftB->hide();
+ rightB = new QToolButton(q);
+ rightB->setAutoRepeat(true);
+ QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
+ rightB->hide();
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled()) {
+ leftB->setFocusPolicy(Qt::NoFocus);
+ rightB->setFocusPolicy(Qt::NoFocus);
+ q->setFocusPolicy(Qt::NoFocus);
+ } else
+#endif
+ q->setFocusPolicy(Qt::TabFocus);
+ q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ elideMode = Qt::TextElideMode(q->style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, q));
+ useScrollButtons = !q->style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, q);
+}
+
+QTabBarPrivate::Tab *QTabBarPrivate::at(int index)
+{
+ return validIndex(index)?&tabList[index]:0;
+}
+
+const QTabBarPrivate::Tab *QTabBarPrivate::at(int index) const
+{
+ return validIndex(index)?&tabList[index]:0;
+}
+
+int QTabBarPrivate::indexAtPos(const QPoint &p) const
+{
+ Q_Q(const QTabBar);
+ if (q->tabRect(currentIndex).contains(p))
+ return currentIndex;
+ for (int i = 0; i < tabList.count(); ++i)
+ if (tabList.at(i).enabled && q->tabRect(i).contains(p))
+ return i;
+ return -1;
+}
+
+void QTabBarPrivate::layoutTabs()
+{
+ Q_Q(QTabBar);
+ scrollOffset = 0;
+ layoutDirty = false;
+ QSize size = q->size();
+ int last, available;
+ int maxExtent;
+ int i;
+ bool vertTabs = verticalTabs(shape);
+ int tabChainIndex = 0;
+
+ Qt::Alignment tabAlignment = Qt::Alignment(q->style()->styleHint(QStyle::SH_TabBar_Alignment, 0, q));
+ QVector<QLayoutStruct> tabChain(tabList.count() + 2);
+
+ // We put an empty item at the front and back and set its expansive attribute
+ // depending on tabAlignment.
+ tabChain[tabChainIndex].init();
+ tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignLeft)
+ && (tabAlignment != Qt::AlignJustify);
+ tabChain[tabChainIndex].empty = true;
+ ++tabChainIndex;
+
+ // We now go through our list of tabs and set the minimum size and the size hint
+ // This will allow us to elide text if necessary. Since we don't set
+ // a maximum size, tabs will EXPAND to fill up the empty space.
+ // Since tab widget is rather *ahem* strict about keeping the geometry of the
+ // tab bar to its absolute minimum, this won't bleed through, but will show up
+ // if you use tab bar on its own (a.k.a. not a bug, but a feature).
+ // Update: if expanding is false, we DO set a maximum size to prevent the tabs
+ // being wider than necessary.
+ if (!vertTabs) {
+ int minx = 0;
+ int x = 0;
+ int maxHeight = 0;
+ for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) {
+ QSize sz = q->tabSizeHint(i);
+ tabList[i].maxRect = QRect(x, 0, sz.width(), sz.height());
+ x += sz.width();
+ maxHeight = qMax(maxHeight, sz.height());
+ sz = minimumTabSizeHint(i);
+ tabList[i].minRect = QRect(minx, 0, sz.width(), sz.height());
+ minx += sz.width();
+ tabChain[tabChainIndex].init();
+ tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.width();
+ tabChain[tabChainIndex].minimumSize = sz.width();
+ tabChain[tabChainIndex].empty = false;
+ tabChain[tabChainIndex].expansive = true;
+
+ if (!expanding)
+ tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint;
+ }
+
+ last = minx;
+ available = size.width();
+ maxExtent = maxHeight;
+ } else {
+ int miny = 0;
+ int y = 0;
+ int maxWidth = 0;
+ for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) {
+ QSize sz = q->tabSizeHint(i);
+ tabList[i].maxRect = QRect(0, y, sz.width(), sz.height());
+ y += sz.height();
+ maxWidth = qMax(maxWidth, sz.width());
+ sz = minimumTabSizeHint(i);
+ tabList[i].minRect = QRect(0, miny, sz.width(), sz.height());
+ miny += sz.height();
+ tabChain[tabChainIndex].init();
+ tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.height();
+ tabChain[tabChainIndex].minimumSize = sz.height();
+ tabChain[tabChainIndex].empty = false;
+ tabChain[tabChainIndex].expansive = true;
+
+ if (!expanding)
+ tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint;
+ }
+
+ last = miny;
+ available = size.height();
+ maxExtent = maxWidth;
+ }
+
+ Q_ASSERT(tabChainIndex == tabChain.count() - 1); // add an assert just to make sure.
+ // Mirror our front item.
+ tabChain[tabChainIndex].init();
+ tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignRight)
+ && (tabAlignment != Qt::AlignJustify);
+ tabChain[tabChainIndex].empty = true;
+
+ // Do the calculation
+ qGeomCalc(tabChain, 0, tabChain.count(), 0, qMax(available, last), 0);
+
+ // Use the results
+ for (i = 0; i < tabList.count(); ++i) {
+ const QLayoutStruct &lstruct = tabChain.at(i + 1);
+ if (!vertTabs)
+ tabList[i].rect.setRect(lstruct.pos, 0, lstruct.size, maxExtent);
+ else
+ tabList[i].rect.setRect(0, lstruct.pos, maxExtent, lstruct.size);
+ }
+
+ if (useScrollButtons && tabList.count() && last > available) {
+ int extra = extraWidth();
+#ifndef QT_NO_STYLE_S60
+ QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style());
+#endif
+ if (!vertTabs) {
+ Qt::LayoutDirection ld = q->layoutDirection();
+ QRect arrows = QStyle::visualRect(ld, q->rect(),
+ QRect(available - extra, 0, extra, size.height()));
+ int buttonOverlap = q->style()->pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, q);
+
+ if (ld == Qt::LeftToRight) {
+// In S60style, tab scroll buttons are layoutted separately, on the sides of the tabbar.
+#ifndef QT_NO_STYLE_S60
+ if (s60Style) {
+ rightB->setGeometry(arrows.left() + extra / 2, arrows.top(), extra / 2, arrows.height());
+ leftB->setGeometry(0, arrows.top(), extra / 2, arrows.height());
+ } else {
+#endif
+ leftB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
+ rightB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(),
+ extra/2, arrows.height());
+#ifndef QT_NO_STYLE_S60
+ }
+#endif
+ leftB->setArrowType(Qt::LeftArrow);
+ rightB->setArrowType(Qt::RightArrow);
+ } else {
+#ifndef QT_NO_STYLE_S60
+ if (s60Style) {
+ rightB->setGeometry(arrows.left() + extra / 2, arrows.top(), extra / 2, arrows.height());
+ leftB->setGeometry(0, arrows.top(), extra / 2, arrows.height());
+ } else {
+#endif
+ rightB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height());
+ leftB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(),
+ extra/2, arrows.height());
+#ifndef QT_NO_STYLE_S60
+ }
+#endif
+ rightB->setArrowType(Qt::LeftArrow);
+ leftB->setArrowType(Qt::RightArrow);
+ }
+ } else {
+#ifndef QT_NO_STYLE_S60
+ if (s60Style) {
+ QRect arrows = QRect(0, 0, size.width(), available );
+ leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra / 2);
+ leftB->setArrowType(Qt::UpArrow);
+ rightB->setGeometry(arrows.left(), arrows.bottom() - extra / 2 + 1,
+ arrows.width(), extra / 2);
+ rightB->setArrowType(Qt::DownArrow);
+ } else {
+#endif
+ QRect arrows = QRect(0, available - extra, size.width(), extra );
+ leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra/2);
+ leftB->setArrowType(Qt::UpArrow);
+ rightB->setGeometry(arrows.left(), arrows.bottom() - extra/2 + 1,
+ arrows.width(), extra/2);
+ rightB->setArrowType(Qt::DownArrow);
+#ifndef QT_NO_STYLE_S60
+ }
+#endif
+ }
+ leftB->setEnabled(scrollOffset > 0);
+ rightB->setEnabled(last - scrollOffset >= available - extra);
+ leftB->show();
+ rightB->show();
+ } else {
+ rightB->hide();
+ leftB->hide();
+ }
+
+ layoutWidgets();
+ q->tabLayoutChange();
+}
+
+void QTabBarPrivate::makeVisible(int index)
+{
+ Q_Q(QTabBar);
+ if (!validIndex(index) || leftB->isHidden())
+ return;
+
+ const QRect tabRect = tabList.at(index).rect;
+ const int oldScrollOffset = scrollOffset;
+ const bool horiz = !verticalTabs(shape);
+ const int available = (horiz ? q->width() : q->height()) - extraWidth();
+ const int start = horiz ? tabRect.left() : tabRect.top();
+ const int end = horiz ? tabRect.right() : tabRect.bottom();
+ if (start < scrollOffset) // too far left
+ scrollOffset = start - (index ? 8 : 0);
+ else if (end > scrollOffset + available) // too far right
+ scrollOffset = end - available + 1;
+
+ leftB->setEnabled(scrollOffset > 0);
+ const int last = horiz ? tabList.last().rect.right() : tabList.last().rect.bottom();
+ rightB->setEnabled(last - scrollOffset >= available);
+ if (oldScrollOffset != scrollOffset) {
+ q->update();
+ layoutWidgets();
+ }
+}
+
+void QTabBarPrivate::layoutTab(int index)
+{
+ Q_Q(QTabBar);
+ Q_ASSERT(index >= 0);
+
+ Tab &tab = tabList[index];
+ bool vertical = verticalTabs(shape);
+ if (!(tab.leftWidget || tab.rightWidget))
+ return;
+
+ QStyleOptionTabV3 opt;
+ q->initStyleOption(&opt, index);
+ if (tab.leftWidget) {
+ QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabLeftButton, &opt, q);
+ QPoint p = rect.topLeft();
+ if ((index == pressedIndex) || paintWithOffsets) {
+ if (vertical)
+ p.setY(p.y() + tabList[index].dragOffset);
+ else
+ p.setX(p.x() + tabList[index].dragOffset);
+ }
+ tab.leftWidget->move(p);
+ }
+ if (tab.rightWidget) {
+ QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabRightButton, &opt, q);
+ QPoint p = rect.topLeft();
+ if ((index == pressedIndex) || paintWithOffsets) {
+ if (vertical)
+ p.setY(p.y() + tab.dragOffset);
+ else
+ p.setX(p.x() + tab.dragOffset);
+ }
+ tab.rightWidget->move(p);
+ }
+}
+
+void QTabBarPrivate::layoutWidgets(int start)
+{
+ Q_Q(QTabBar);
+ for (int i = start; i < q->count(); ++i) {
+ layoutTab(i);
+ }
+}
+
+void QTabBarPrivate::_q_closeTab()
+{
+ Q_Q(QTabBar);
+ QObject *object = q->sender();
+ int tabToClose = -1;
+ QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)q->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, q);
+ for (int i = 0; i < tabList.count(); ++i) {
+ if (closeSide == QTabBar::LeftSide) {
+ if (tabList.at(i).leftWidget == object) {
+ tabToClose = i;
+ break;
+ }
+ } else {
+ if (tabList.at(i).rightWidget == object) {
+ tabToClose = i;
+ break;
+ }
+ }
+ }
+ if (tabToClose != -1)
+ emit q->tabCloseRequested(tabToClose);
+}
+
+void QTabBarPrivate::_q_scrollTabs()
+{
+ Q_Q(QTabBar);
+ const QObject *sender = q->sender();
+ int i = -1;
+ if (!verticalTabs(shape)) {
+ if (sender == leftB) {
+ for (i = tabList.count() - 1; i >= 0; --i) {
+ if (tabList.at(i).rect.left() - scrollOffset < 0) {
+ makeVisible(i);
+ return;
+ }
+ }
+ } else if (sender == rightB) {
+ int availableWidth = q->width() - extraWidth();
+ for (i = 0; i < tabList.count(); ++i) {
+ if (tabList.at(i).rect.right() - scrollOffset > availableWidth) {
+ makeVisible(i);
+ return;
+ }
+ }
+ }
+ } else { // vertical
+ if (sender == leftB) {
+ for (i = tabList.count() - 1; i >= 0; --i) {
+ if (tabList.at(i).rect.top() - scrollOffset < 0) {
+ makeVisible(i);
+ return;
+ }
+ }
+ } else if (sender == rightB) {
+ int available = q->height() - extraWidth();
+ for (i = 0; i < tabList.count(); ++i) {
+ if (tabList.at(i).rect.bottom() - scrollOffset > available) {
+ makeVisible(i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void QTabBarPrivate::refresh()
+{
+ Q_Q(QTabBar);
+
+ // be safe in case a subclass is also handling move with the tabs
+ if (pressedIndex != -1
+ && movable
+ && QApplication::mouseButtons() == Qt::NoButton) {
+ moveTabFinished(pressedIndex);
+ if (!validIndex(pressedIndex))
+ pressedIndex = -1;
+ }
+
+ if (!q->isVisible()) {
+ layoutDirty = true;
+ } else {
+ layoutTabs();
+ makeVisible(currentIndex);
+ q->update();
+ q->updateGeometry();
+ }
+}
+
+/*!
+ Creates a new tab bar with the given \a parent.
+*/
+QTabBar::QTabBar(QWidget* parent)
+ :QWidget(*new QTabBarPrivate, parent, 0)
+{
+ Q_D(QTabBar);
+ d->init();
+}
+
+
+/*!
+ Destroys the tab bar.
+*/
+QTabBar::~QTabBar()
+{
+}
+
+/*!
+ \property QTabBar::shape
+ \brief the shape of the tabs in the tab bar
+
+ Possible values for this property are described by the Shape enum.
+*/
+
+
+QTabBar::Shape QTabBar::shape() const
+{
+ Q_D(const QTabBar);
+ return d->shape;
+}
+
+void QTabBar::setShape(Shape shape)
+{
+ Q_D(QTabBar);
+ if (d->shape == shape)
+ return;
+ d->shape = shape;
+ d->refresh();
+}
+
+/*!
+ \property QTabBar::drawBase
+ \brief defines whether or not tab bar should draw its base.
+
+ If true then QTabBar draws a base in relation to the styles overlab.
+ Otherwise only the tabs are drawn.
+
+ \sa QStyle::pixelMetric() QStyle::PM_TabBarBaseOverlap QStyleOptionTabBarBaseV2
+*/
+
+void QTabBar::setDrawBase(bool drawBase)
+{
+ Q_D(QTabBar);
+ if (d->drawBase == drawBase)
+ return;
+ d->drawBase = drawBase;
+ update();
+}
+
+bool QTabBar::drawBase() const
+{
+ Q_D(const QTabBar);
+ return d->drawBase;
+}
+
+/*!
+ Adds a new tab with text \a text. Returns the new
+ tab's index.
+*/
+int QTabBar::addTab(const QString &text)
+{
+ return insertTab(-1, text);
+}
+
+/*!
+ \overload
+
+ Adds a new tab with icon \a icon and text \a
+ text. Returns the new tab's index.
+*/
+int QTabBar::addTab(const QIcon& icon, const QString &text)
+{
+ return insertTab(-1, icon, text);
+}
+
+/*!
+ Inserts a new tab with text \a text at position \a index. If \a
+ index is out of range, the new tab is appened. Returns the new
+ tab's index.
+*/
+int QTabBar::insertTab(int index, const QString &text)
+{
+ return insertTab(index, QIcon(), text);
+}
+
+/*!\overload
+
+ Inserts a new tab with icon \a icon and text \a text at position
+ \a index. If \a index is out of range, the new tab is
+ appended. Returns the new tab's index.
+
+ If the QTabBar was empty before this function is called, the inserted tab
+ becomes the current tab.
+
+ Inserting a new tab at an index less than or equal to the current index
+ will increment the current index, but keep the current tab.
+*/
+int QTabBar::insertTab(int index, const QIcon& icon, const QString &text)
+{
+ Q_D(QTabBar);
+ if (!d->validIndex(index)) {
+ index = d->tabList.count();
+ d->tabList.append(QTabBarPrivate::Tab(icon, text));
+ } else {
+ d->tabList.insert(index, QTabBarPrivate::Tab(icon, text));
+ }
+#ifndef QT_NO_SHORTCUT
+ d->tabList[index].shortcutId = grabShortcut(QKeySequence::mnemonic(text));
+#endif
+ d->refresh();
+ if (d->tabList.count() == 1)
+ setCurrentIndex(index);
+ else if (index <= d->currentIndex)
+ ++d->currentIndex;
+
+ if (d->closeButtonOnTabs) {
+ QStyleOptionTabV3 opt;
+ initStyleOption(&opt, index);
+ ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
+ QAbstractButton *closeButton = new CloseButton(this);
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
+ setTabButton(index, closeSide, closeButton);
+ }
+
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ if (d->tabList[i].lastTab >= index)
+ ++d->tabList[i].lastTab;
+ }
+
+ tabInserted(index);
+ return index;
+}
+
+
+/*!
+ Removes the tab at position \a index.
+
+ \sa SelectionBehavior
+ */
+void QTabBar::removeTab(int index)
+{
+ Q_D(QTabBar);
+ if (d->validIndex(index)) {
+#ifndef QT_NO_SHORTCUT
+ releaseShortcut(d->tabList.at(index).shortcutId);
+#endif
+ if (d->tabList[index].leftWidget) {
+ d->tabList[index].leftWidget->hide();
+ d->tabList[index].leftWidget->deleteLater();
+ d->tabList[index].leftWidget = 0;
+ }
+ if (d->tabList[index].rightWidget) {
+ d->tabList[index].rightWidget->hide();
+ d->tabList[index].rightWidget->deleteLater();
+ d->tabList[index].rightWidget = 0;
+ }
+
+ int newIndex = d->tabList[index].lastTab;
+ d->tabList.removeAt(index);
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ if (d->tabList[i].lastTab == index)
+ d->tabList[i].lastTab = -1;
+ if (d->tabList[i].lastTab > index)
+ --d->tabList[i].lastTab;
+ }
+ if (index == d->currentIndex) {
+ // The current tab is going away, in order to make sure
+ // we emit that "current has changed", we need to reset this
+ // around.
+ d->currentIndex = -1;
+ if (d->tabList.size() > 0) {
+ switch(d->selectionBehaviorOnRemove) {
+ case SelectPreviousTab:
+ if (newIndex > index)
+ newIndex--;
+ if (d->validIndex(newIndex))
+ break;
+ // else fallthrough
+ case SelectRightTab:
+ newIndex = index;
+ if (newIndex >= d->tabList.size())
+ newIndex = d->tabList.size() - 1;
+ break;
+ case SelectLeftTab:
+ newIndex = index - 1;
+ if (newIndex < 0)
+ newIndex = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (d->validIndex(newIndex)) {
+ // don't loose newIndex's old through setCurrentIndex
+ int bump = d->tabList[newIndex].lastTab;
+ setCurrentIndex(newIndex);
+ d->tabList[newIndex].lastTab = bump;
+ }
+ } else {
+ emit currentChanged(-1);
+ }
+ } else if (index < d->currentIndex) {
+ setCurrentIndex(d->currentIndex - 1);
+ }
+ d->refresh();
+ tabRemoved(index);
+ }
+}
+
+
+/*!
+ Returns true if the tab at position \a index is enabled; otherwise
+ returns false.
+*/
+bool QTabBar::isTabEnabled(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->enabled;
+ return false;
+}
+
+/*!
+ If \a enabled is true then the tab at position \a index is
+ enabled; otherwise the item at position \a index is disabled.
+*/
+void QTabBar::setTabEnabled(int index, bool enabled)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index)) {
+ tab->enabled = enabled;
+#ifndef QT_NO_SHORTCUT
+ setShortcutEnabled(tab->shortcutId, enabled);
+#endif
+ update();
+ if (!enabled && index == d->currentIndex)
+ setCurrentIndex(d->validIndex(index+1)?index+1:0);
+ else if (enabled && !d->validIndex(d->currentIndex))
+ setCurrentIndex(index);
+ }
+}
+
+
+/*!
+ Returns the text of the tab at position \a index, or an empty
+ string if \a index is out of range.
+*/
+QString QTabBar::tabText(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->text;
+ return QString();
+}
+
+/*!
+ Sets the text of the tab at position \a index to \a text.
+*/
+void QTabBar::setTabText(int index, const QString &text)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index)) {
+ tab->text = text;
+#ifndef QT_NO_SHORTCUT
+ releaseShortcut(tab->shortcutId);
+ tab->shortcutId = grabShortcut(QKeySequence::mnemonic(text));
+ setShortcutEnabled(tab->shortcutId, tab->enabled);
+#endif
+ d->refresh();
+ }
+}
+
+/*!
+ Returns the text color of the tab with the given \a index, or a invalid
+ color if \a index is out of range.
+
+ \sa setTabTextColor()
+*/
+QColor QTabBar::tabTextColor(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->textColor;
+ return QColor();
+}
+
+/*!
+ Sets the color of the text in the tab with the given \a index to the specified \a color.
+
+ If an invalid color is specified, the tab will use the QTabBar foreground role instead.
+
+ \sa tabTextColor()
+*/
+void QTabBar::setTabTextColor(int index, const QColor &color)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index)) {
+ tab->textColor = color;
+ update(tabRect(index));
+ }
+}
+
+/*!
+ Returns the icon of the tab at position \a index, or a null icon
+ if \a index is out of range.
+*/
+QIcon QTabBar::tabIcon(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->icon;
+ return QIcon();
+}
+
+/*!
+ Sets the icon of the tab at position \a index to \a icon.
+*/
+void QTabBar::setTabIcon(int index, const QIcon & icon)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index)) {
+ bool simpleIconChange = (!icon.isNull() && !tab->icon.isNull());
+ tab->icon = icon;
+ if (simpleIconChange)
+ update(tabRect(index));
+ else
+ d->refresh();
+ }
+}
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Sets the tool tip of the tab at position \a index to \a tip.
+*/
+void QTabBar::setTabToolTip(int index, const QString & tip)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index))
+ tab->toolTip = tip;
+}
+
+/*!
+ Returns the tool tip of the tab at position \a index, or an empty
+ string if \a index is out of range.
+*/
+QString QTabBar::tabToolTip(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->toolTip;
+ return QString();
+}
+#endif // QT_NO_TOOLTIP
+
+#ifndef QT_NO_WHATSTHIS
+/*!
+ \since 4.1
+
+ Sets the What's This help text of the tab at position \a index
+ to \a text.
+*/
+void QTabBar::setTabWhatsThis(int index, const QString &text)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index))
+ tab->whatsThis = text;
+}
+
+/*!
+ \since 4.1
+
+ Returns the What's This help text of the tab at position \a index,
+ or an empty string if \a index is out of range.
+*/
+QString QTabBar::tabWhatsThis(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->whatsThis;
+ return QString();
+}
+
+#endif // QT_NO_WHATSTHIS
+
+/*!
+ Sets the data of the tab at position \a index to \a data.
+*/
+void QTabBar::setTabData(int index, const QVariant & data)
+{
+ Q_D(QTabBar);
+ if (QTabBarPrivate::Tab *tab = d->at(index))
+ tab->data = data;
+}
+
+/*!
+ Returns the data of the tab at position \a index, or a null
+ variant if \a index is out of range.
+*/
+QVariant QTabBar::tabData(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index))
+ return tab->data;
+ return QVariant();
+}
+
+/*!
+ Returns the visual rectangle of the tab at position \a
+ index, or a null rectangle if \a index is out of range.
+*/
+QRect QTabBar::tabRect(int index) const
+{
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index)) {
+ if (d->layoutDirty)
+ const_cast<QTabBarPrivate*>(d)->layoutTabs();
+ QRect r = tab->rect;
+ if (verticalTabs(d->shape))
+ r.translate(0, -d->scrollOffset);
+ else
+ r.translate(-d->scrollOffset, 0);
+ if (!verticalTabs(d->shape))
+ r = QStyle::visualRect(layoutDirection(), rect(), r);
+ return r;
+ }
+ return QRect();
+}
+
+/*!
+ \since 4.3
+ Returns the index of the tab that covers \a position or -1 if no
+ tab covers \a position;
+*/
+
+int QTabBar::tabAt(const QPoint &position) const
+{
+ Q_D(const QTabBar);
+ if (d->validIndex(d->currentIndex)
+ && tabRect(d->currentIndex).contains(position)) {
+ return d->currentIndex;
+ }
+ const int max = d->tabList.size();
+ for (int i = 0; i < max; ++i) {
+ if (tabRect(i).contains(position)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*!
+ \property QTabBar::currentIndex
+ \brief the index of the tab bar's visible tab
+
+ The current index is -1 if there is no current tab.
+*/
+
+int QTabBar::currentIndex() const
+{
+ Q_D(const QTabBar);
+ if (d->validIndex(d->currentIndex))
+ return d->currentIndex;
+ return -1;
+}
+
+
+void QTabBar::setCurrentIndex(int index)
+{
+ Q_D(QTabBar);
+ if (d->dragInProgress && d->pressedIndex != -1)
+ return;
+
+ int oldIndex = d->currentIndex;
+ if (d->validIndex(index) && d->currentIndex != index) {
+ d->currentIndex = index;
+ update();
+ d->makeVisible(index);
+ d->tabList[index].lastTab = oldIndex;
+ if (oldIndex >= 0 && oldIndex < count())
+ d->layoutTab(oldIndex);
+ d->layoutTab(index);
+#ifndef QT_NO_ACCESSIBILITY
+ if (QAccessible::isActive()) {
+ QAccessible::updateAccessibility(this, index + 1, QAccessible::Focus);
+ QAccessible::updateAccessibility(this, index + 1, QAccessible::Selection);
+ }
+#endif
+#ifdef QT3_SUPPORT
+ emit selected(index);
+#endif
+ emit currentChanged(index);
+ }
+}
+
+/*!
+ \property QTabBar::iconSize
+ \brief The size for icons in the tab bar
+ \since 4.1
+
+ The default value is style-dependent. \c iconSize is a maximum
+ size; icons that are smaller are not scaled up.
+
+ \sa QTabWidget::iconSize
+*/
+QSize QTabBar::iconSize() const
+{
+ Q_D(const QTabBar);
+ if (d->iconSize.isValid())
+ return d->iconSize;
+ int iconExtent = style()->pixelMetric(QStyle::PM_TabBarIconSize, 0, this);
+ return QSize(iconExtent, iconExtent);
+
+}
+
+void QTabBar::setIconSize(const QSize &size)
+{
+ Q_D(QTabBar);
+ d->iconSize = size;
+ d->layoutDirty = true;
+ update();
+ updateGeometry();
+}
+
+/*!
+ \property QTabBar::count
+ \brief the number of tabs in the tab bar
+*/
+
+int QTabBar::count() const
+{
+ Q_D(const QTabBar);
+ return d->tabList.count();
+}
+
+
+/*!\reimp
+ */
+QSize QTabBar::sizeHint() const
+{
+ Q_D(const QTabBar);
+ if (d->layoutDirty)
+ const_cast<QTabBarPrivate*>(d)->layoutTabs();
+ QRect r;
+ for (int i = 0; i < d->tabList.count(); ++i)
+ r = r.united(d->tabList.at(i).maxRect);
+ QSize sz = QApplication::globalStrut();
+ return r.size().expandedTo(sz);
+}
+
+/*!\reimp
+ */
+QSize QTabBar::minimumSizeHint() const
+{
+ Q_D(const QTabBar);
+ if (d->layoutDirty)
+ const_cast<QTabBarPrivate*>(d)->layoutTabs();
+ if (!d->useScrollButtons) {
+ QRect r;
+ for (int i = 0; i < d->tabList.count(); ++i)
+ r = r.united(d->tabList.at(i).minRect);
+ return r.size().expandedTo(QApplication::globalStrut());
+ }
+ if (verticalTabs(d->shape))
+ return QSize(sizeHint().width(), d->rightB->sizeHint().height() * 2 + 75);
+ else
+ return QSize(d->rightB->sizeHint().width() * 2 + 75, sizeHint().height());
+}
+
+// Compute the most-elided possible text, for minimumSizeHint
+static QString computeElidedText(Qt::TextElideMode mode, const QString &text)
+{
+ if (text.length() <= 3)
+ return text;
+
+ static const QLatin1String Ellipses("...");
+ QString ret;
+ switch (mode) {
+ case Qt::ElideRight:
+ ret = text.left(2) + Ellipses;
+ break;
+ case Qt::ElideMiddle:
+ ret = text.left(1) + Ellipses + text.right(1);
+ break;
+ case Qt::ElideLeft:
+ ret = Ellipses + text.right(2);
+ break;
+ case Qt::ElideNone:
+ ret = text;
+ break;
+ }
+ return ret;
+}
+
+QSize QTabBarPrivate::minimumTabSizeHint(int index)
+{
+ Q_Q(QTabBar);
+ // ### Qt 5: make this a protected virtual function in QTabBar
+ Tab &tab = tabList[index];
+ QString oldText = tab.text;
+ tab.text = computeElidedText(elideMode, oldText);
+ QSize size = q->tabSizeHint(index);
+ tab.text = oldText;
+ return size;
+}
+
+/*!
+ Returns the size hint for the tab at position \a index.
+*/
+QSize QTabBar::tabSizeHint(int index) const
+{
+ //Note: this must match with the computations in QCommonStylePrivate::tabLayout
+ Q_D(const QTabBar);
+ if (const QTabBarPrivate::Tab *tab = d->at(index)) {
+ QStyleOptionTabV3 opt;
+ initStyleOption(&opt, index);
+ opt.text = d->tabList.at(index).text;
+ QSize iconSize = tab->icon.isNull() ? QSize(0, 0) : opt.iconSize;
+ int hframe = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this);
+ int vframe = style()->pixelMetric(QStyle::PM_TabBarTabVSpace, &opt, this);
+ const QFontMetrics fm = fontMetrics();
+
+ int maxWidgetHeight = qMax(opt.leftButtonSize.height(), opt.rightButtonSize.height());
+ int maxWidgetWidth = qMax(opt.leftButtonSize.width(), opt.rightButtonSize.width());
+
+ int widgetWidth = 0;
+ int widgetHeight = 0;
+ int padding = 0;
+ if (!opt.leftButtonSize.isEmpty()) {
+ padding += 4;
+ widgetWidth += opt.leftButtonSize.width();
+ widgetHeight += opt.leftButtonSize.height();
+ }
+ if (!opt.rightButtonSize.isEmpty()) {
+ padding += 4;
+ widgetWidth += opt.rightButtonSize.width();
+ widgetHeight += opt.rightButtonSize.height();
+ }
+ if (!opt.icon.isNull())
+ padding += 4;
+
+ QSize csz;
+ if (verticalTabs(d->shape)) {
+ csz = QSize( qMax(maxWidgetWidth, qMax(fm.height(), iconSize.height())) + vframe,
+ fm.size(Qt::TextShowMnemonic, tab->text).width() + iconSize.width() + hframe + widgetHeight + padding);
+ } else {
+ csz = QSize(fm.size(Qt::TextShowMnemonic, tab->text).width() + iconSize.width() + hframe
+ + widgetWidth + padding,
+ qMax(maxWidgetHeight, qMax(fm.height(), iconSize.height())) + vframe);
+ }
+
+ QSize retSize = style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, csz, this);
+ return retSize;
+ }
+ return QSize();
+}
+
+/*!
+ This virtual handler is called after a new tab was added or
+ inserted at position \a index.
+
+ \sa tabRemoved()
+ */
+void QTabBar::tabInserted(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ This virtual handler is called after a tab was removed from
+ position \a index.
+
+ \sa tabInserted()
+ */
+void QTabBar::tabRemoved(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ This virtual handler is called whenever the tab layout changes.
+
+ \sa tabRect()
+ */
+void QTabBar::tabLayoutChange()
+{
+}
+
+
+/*!\reimp
+ */
+void QTabBar::showEvent(QShowEvent *)
+{
+ Q_D(QTabBar);
+ if (d->layoutDirty)
+ d->refresh();
+ if (!d->validIndex(d->currentIndex))
+ setCurrentIndex(0);
+ d->updateMacBorderMetrics();
+}
+
+/*!\reimp
+ */
+void QTabBar::hideEvent(QHideEvent *)
+{
+ Q_D(QTabBar);
+ d->updateMacBorderMetrics();
+}
+
+/*!\reimp
+ */
+bool QTabBar::event(QEvent *event)
+{
+ Q_D(QTabBar);
+ if (event->type() == QEvent::HoverMove
+ || event->type() == QEvent::HoverEnter) {
+ QHoverEvent *he = static_cast<QHoverEvent *>(event);
+ if (!d->hoverRect.contains(he->pos())) {
+ QRect oldHoverRect = d->hoverRect;
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ QRect area = tabRect(i);
+ if (area.contains(he->pos())) {
+ d->hoverRect = area;
+ break;
+ }
+ }
+ if (he->oldPos() != QPoint(-1, -1))
+ update(oldHoverRect);
+ update(d->hoverRect);
+ }
+ return true;
+ } else if (event->type() == QEvent::HoverLeave ) {
+ QRect oldHoverRect = d->hoverRect;
+ d->hoverRect = QRect();
+ update(oldHoverRect);
+ return true;
+#ifndef QT_NO_TOOLTIP
+ } else if (event->type() == QEvent::ToolTip) {
+ if (const QTabBarPrivate::Tab *tab = d->at(tabAt(static_cast<QHelpEvent*>(event)->pos()))) {
+ if (!tab->toolTip.isEmpty()) {
+ QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(), tab->toolTip, this);
+ return true;
+ }
+ }
+#endif // QT_NO_TOOLTIP
+#ifndef QT_NO_WHATSTHIS
+ } else if (event->type() == QEvent::QueryWhatsThis) {
+ const QTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast<QHelpEvent*>(event)->pos()));
+ if (!tab || tab->whatsThis.isEmpty())
+ event->ignore();
+ return true;
+ } else if (event->type() == QEvent::WhatsThis) {
+ if (const QTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast<QHelpEvent*>(event)->pos()))) {
+ if (!tab->whatsThis.isEmpty()) {
+ QWhatsThis::showText(static_cast<QHelpEvent*>(event)->globalPos(),
+ tab->whatsThis, this);
+ return true;
+ }
+ }
+#endif // QT_NO_WHATSTHIS
+#ifndef QT_NO_SHORTCUT
+ } else if (event->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ const QTabBarPrivate::Tab *tab = &d->tabList.at(i);
+ if (tab->shortcutId == se->shortcutId()) {
+ setCurrentIndex(i);
+ return true;
+ }
+ }
+#endif
+ }
+ return QWidget::event(event);
+}
+
+/*!\reimp
+ */
+void QTabBar::resizeEvent(QResizeEvent *)
+{
+ Q_D(QTabBar);
+ if (d->layoutDirty)
+ updateGeometry();
+ d->layoutTabs();
+
+ d->makeVisible(d->currentIndex);
+}
+
+/*!\reimp
+ */
+void QTabBar::paintEvent(QPaintEvent *)
+{
+ Q_D(QTabBar);
+
+ QStyleOptionTabBarBaseV2 optTabBase;
+ QTabBarPrivate::initStyleBaseOption(&optTabBase, this, size());
+
+ QStylePainter p(this);
+ int selected = -1;
+ int cut = -1;
+ bool rtl = optTabBase.direction == Qt::RightToLeft;
+ bool vertical = verticalTabs(d->shape);
+ QStyleOptionTab cutTab;
+ selected = d->currentIndex;
+ if (d->dragInProgress)
+ selected = d->pressedIndex;
+
+ for (int i = 0; i < d->tabList.count(); ++i)
+ optTabBase.tabBarRect |= tabRect(i);
+
+ optTabBase.selectedTabRect = tabRect(selected);
+
+ if (d->drawBase)
+ p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
+
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ QStyleOptionTabV3 tab;
+ initStyleOption(&tab, i);
+ if (d->paintWithOffsets && d->tabList[i].dragOffset != 0) {
+ if (vertical) {
+ tab.rect.moveTop(tab.rect.y() + d->tabList[i].dragOffset);
+ } else {
+ tab.rect.moveLeft(tab.rect.x() + d->tabList[i].dragOffset);
+ }
+ }
+ if (!(tab.state & QStyle::State_Enabled)) {
+ tab.palette.setCurrentColorGroup(QPalette::Disabled);
+ }
+ // If this tab is partially obscured, make a note of it so that we can pass the information
+ // along when we draw the tear.
+ if (((!vertical && (!rtl && tab.rect.left() < 0)) || (rtl && tab.rect.right() > width()))
+ || (vertical && tab.rect.top() < 0)) {
+ cut = i;
+ cutTab = tab;
+ }
+ // Don't bother drawing a tab if the entire tab is outside of the visible tab bar.
+ if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width()))
+ || (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height())))
+ continue;
+
+ optTabBase.tabBarRect |= tab.rect;
+ if (i == selected)
+ continue;
+
+ p.drawControl(QStyle::CE_TabBarTab, tab);
+ }
+
+ // Draw the selected tab last to get it "on top"
+ if (selected >= 0) {
+ QStyleOptionTabV3 tab;
+ initStyleOption(&tab, selected);
+ if (d->paintWithOffsets && d->tabList[selected].dragOffset != 0) {
+ if (vertical)
+ tab.rect.moveTop(tab.rect.y() + d->tabList[selected].dragOffset);
+ else
+ tab.rect.moveLeft(tab.rect.x() + d->tabList[selected].dragOffset);
+ }
+ if (!d->dragInProgress)
+ p.drawControl(QStyle::CE_TabBarTab, tab);
+ else {
+ int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this);
+ d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
+ }
+ }
+
+ // Only draw the tear indicator if necessary. Most of the time we don't need too.
+ if (d->leftB->isVisible() && cut >= 0) {
+ cutTab.rect = rect();
+ cutTab.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicator, &cutTab, this);
+ p.drawPrimitive(QStyle::PE_IndicatorTabTear, cutTab);
+ }
+}
+
+/*
+ Given that index at position from moved to position to where return where index goes.
+ */
+int QTabBarPrivate::calculateNewPosition(int from, int to, int index) const
+{
+ if (index == from)
+ return to;
+
+ int start = qMin(from, to);
+ int end = qMax(from, to);
+ if (index >= start && index <= end)
+ index += (from < to) ? -1 : 1;
+ return index;
+}
+
+/*!
+ Moves the item at index position \a from to index position \a to.
+ \since 4.5
+
+ \sa tabMoved(), tabLayoutChange()
+ */
+void QTabBar::moveTab(int from, int to)
+{
+ Q_D(QTabBar);
+ if (from == to
+ || !d->validIndex(from)
+ || !d->validIndex(to))
+ return;
+
+ bool vertical = verticalTabs(d->shape);
+ int oldPressedPosition = 0;
+ if (d->pressedIndex != -1) {
+ // Record the position of the pressed tab before reordering the tabs.
+ oldPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.y()
+ : d->tabList[d->pressedIndex].rect.x();
+ }
+
+ // Update the locations of the tabs first
+ int start = qMin(from, to);
+ int end = qMax(from, to);
+ int width = vertical ? d->tabList[from].rect.height() : d->tabList[from].rect.width();
+ if (from < to)
+ width *= -1;
+ bool rtl = isRightToLeft();
+ for (int i = start; i <= end; ++i) {
+ if (i == from)
+ continue;
+ if (vertical)
+ d->tabList[i].rect.moveTop(d->tabList[i].rect.y() + width);
+ else
+ d->tabList[i].rect.moveLeft(d->tabList[i].rect.x() + width);
+ int direction = -1;
+ if (rtl && !vertical)
+ direction *= -1;
+ if (d->tabList[i].dragOffset != 0)
+ d->tabList[i].dragOffset += (direction * width);
+ }
+
+ if (vertical) {
+ if (from < to)
+ d->tabList[from].rect.moveTop(d->tabList[to].rect.bottom() + 1);
+ else
+ d->tabList[from].rect.moveTop(d->tabList[to].rect.top() - width);
+ } else {
+ if (from < to)
+ d->tabList[from].rect.moveLeft(d->tabList[to].rect.right() + 1);
+ else
+ d->tabList[from].rect.moveLeft(d->tabList[to].rect.left() - width);
+ }
+
+ // Move the actual data structures
+ d->tabList.move(from, to);
+
+ // update lastTab locations
+ for (int i = 0; i < d->tabList.count(); ++i)
+ d->tabList[i].lastTab = d->calculateNewPosition(from, to, d->tabList[i].lastTab);
+
+ // update external variables
+ d->currentIndex = d->calculateNewPosition(from, to, d->currentIndex);
+
+ // If we are in the middle of a drag update the dragStartPosition
+ if (d->pressedIndex != -1) {
+ d->pressedIndex = d->calculateNewPosition(from, to, d->pressedIndex);
+ int newPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.top() : d->tabList[d->pressedIndex].rect.left();
+ int diff = oldPressedPosition - newPressedPosition;
+ if (isRightToLeft() && !vertical)
+ diff *= -1;
+ if (vertical)
+ d->dragStartPosition.setY(d->dragStartPosition.y() - diff);
+ else
+ d->dragStartPosition.setX(d->dragStartPosition.x() - diff);
+ }
+
+ d->layoutWidgets(start);
+ update();
+ emit tabMoved(from, to);
+ emit tabLayoutChange();
+}
+
+void QTabBarPrivate::slide(int from, int to)
+{
+ Q_Q(QTabBar);
+ if (from == to
+ || !validIndex(from)
+ || !validIndex(to))
+ return;
+ bool vertical = verticalTabs(shape);
+ int preLocation = vertical ? q->tabRect(from).y() : q->tabRect(from).x();
+ q->setUpdatesEnabled(false);
+ q->moveTab(from, to);
+ q->setUpdatesEnabled(true);
+ int postLocation = vertical ? q->tabRect(to).y() : q->tabRect(to).x();
+ int length = postLocation - preLocation;
+ tabList[to].dragOffset -= length;
+ tabList[to].startAnimation(this, ANIMATION_DURATION);
+}
+
+void QTabBarPrivate::moveTab(int index, int offset)
+{
+ if (!validIndex(index))
+ return;
+ tabList[index].dragOffset = offset;
+ layoutTab(index); // Make buttons follow tab
+ q_func()->update();
+}
+
+/*!\reimp
+*/
+void QTabBar::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QTabBar);
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+ // Be safe!
+ if (d->pressedIndex != -1 && d->movable)
+ d->moveTabFinished(d->pressedIndex);
+
+ d->pressedIndex = d->indexAtPos(event->pos());
+#ifdef Q_WS_MAC
+ d->previousPressedIndex = d->pressedIndex;
+#endif
+ if (d->validIndex(d->pressedIndex)) {
+ QStyleOptionTabBarBaseV2 optTabBase;
+ optTabBase.init(this);
+ optTabBase.documentMode = d->documentMode;
+ if (event->type() == style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this))
+ setCurrentIndex(d->pressedIndex);
+ else
+ repaint(tabRect(d->pressedIndex));
+ if (d->movable) {
+ d->dragStartPosition = event->pos();
+ }
+ }
+}
+
+/*!\reimp
+ */
+void QTabBar::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QTabBar);
+ if (d->movable) {
+ // Be safe!
+ if (d->pressedIndex != -1
+ && event->buttons() == Qt::NoButton)
+ d->moveTabFinished(d->pressedIndex);
+
+ // Start drag
+ if (!d->dragInProgress && d->pressedIndex != -1) {
+ if ((event->pos() - d->dragStartPosition).manhattanLength() > QApplication::startDragDistance()) {
+ d->dragInProgress = true;
+ d->setupMovableTab();
+ }
+ }
+
+ int offset = (event->pos() - d->dragStartPosition).manhattanLength();
+ if (event->buttons() == Qt::LeftButton
+ && offset > QApplication::startDragDistance()
+ && d->validIndex(d->pressedIndex)) {
+ bool vertical = verticalTabs(d->shape);
+ int dragDistance;
+ if (vertical) {
+ dragDistance = (event->pos().y() - d->dragStartPosition.y());
+ } else {
+ dragDistance = (event->pos().x() - d->dragStartPosition.x());
+ }
+ d->tabList[d->pressedIndex].dragOffset = dragDistance;
+
+ QRect startingRect = tabRect(d->pressedIndex);
+ if (vertical)
+ startingRect.moveTop(startingRect.y() + dragDistance);
+ else
+ startingRect.moveLeft(startingRect.x() + dragDistance);
+
+ int overIndex;
+ if (dragDistance < 0)
+ overIndex = tabAt(startingRect.topLeft());
+ else
+ overIndex = tabAt(startingRect.topRight());
+
+ if (overIndex != d->pressedIndex && overIndex != -1) {
+ int offset = 1;
+ if (isRightToLeft() && !vertical)
+ offset *= -1;
+ if (dragDistance < 0) {
+ dragDistance *= -1;
+ offset *= -1;
+ }
+ for (int i = d->pressedIndex;
+ offset > 0 ? i < overIndex : i > overIndex;
+ i += offset) {
+ QRect overIndexRect = tabRect(overIndex);
+ int needsToBeOver = (vertical ? overIndexRect.height() : overIndexRect.width()) / 2;
+ if (dragDistance > needsToBeOver)
+ d->slide(i + offset, d->pressedIndex);
+ }
+ }
+ // Buttons needs to follow the dragged tab
+ d->layoutTab(d->pressedIndex);
+
+ update();
+ }
+#ifdef Q_WS_MAC
+ } else if (!d->documentMode && event->buttons() == Qt::LeftButton && d->previousPressedIndex != -1) {
+ int newPressedIndex = d->indexAtPos(event->pos());
+ if (d->pressedIndex == -1 && d->previousPressedIndex == newPressedIndex) {
+ d->pressedIndex = d->previousPressedIndex;
+ update(tabRect(d->pressedIndex));
+ } else if(d->pressedIndex != newPressedIndex) {
+ d->pressedIndex = -1;
+ update(tabRect(d->previousPressedIndex));
+ }
+#endif
+ }
+
+ if (event->buttons() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+ QStyleOptionTabBarBaseV2 optTabBase;
+ optTabBase.init(this);
+ optTabBase.documentMode = d->documentMode;
+}
+
+void QTabBarPrivate::setupMovableTab()
+{
+ Q_Q(QTabBar);
+ if (!movingTab)
+ movingTab = new QWidget(q);
+
+ int taboverlap = q->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ,q);
+ QRect grabRect = q->tabRect(pressedIndex);
+ grabRect.adjust(-taboverlap, 0, taboverlap, 0);
+
+ QPixmap grabImage(grabRect.size());
+ grabImage.fill(Qt::transparent);
+ QStylePainter p(&grabImage, q);
+ p.initFrom(q);
+
+ QStyleOptionTabV3 tab;
+ q->initStyleOption(&tab, pressedIndex);
+ tab.rect.moveTopLeft(QPoint(taboverlap, 0));
+ p.drawControl(QStyle::CE_TabBarTab, tab);
+ p.end();
+
+ QPalette pal;
+ pal.setBrush(QPalette::All, QPalette::Window, grabImage);
+ movingTab->setPalette(pal);
+ movingTab->setGeometry(grabRect);
+ movingTab->setAutoFillBackground(true);
+ movingTab->raise();
+
+ // Re-arrange widget order to avoid overlaps
+ if (tabList[pressedIndex].leftWidget)
+ tabList[pressedIndex].leftWidget->raise();
+ if (tabList[pressedIndex].rightWidget)
+ tabList[pressedIndex].rightWidget->raise();
+ if (leftB)
+ leftB->raise();
+ if (rightB)
+ rightB->raise();
+ movingTab->setVisible(true);
+}
+
+void QTabBarPrivate::moveTabFinished(int index)
+{
+ Q_Q(QTabBar);
+ bool cleanup = (pressedIndex == index) || (pressedIndex == -1) || !validIndex(index);
+ bool allAnimationsFinished = true;
+#ifndef QT_NO_ANIMATION
+ for(int i = 0; allAnimationsFinished && i < tabList.count(); ++i) {
+ const Tab &t = tabList.at(i);
+ if (t.animation && t.animation->state() == QAbstractAnimation::Running)
+ allAnimationsFinished = false;
+ }
+#endif //QT_NO_ANIMATION
+ if (allAnimationsFinished && cleanup) {
+ if(movingTab)
+ movingTab->setVisible(false); // We might not get a mouse release
+ for (int i = 0; i < tabList.count(); ++i) {
+ tabList[i].dragOffset = 0;
+ }
+ if (pressedIndex != -1 && movable) {
+ pressedIndex = -1;
+ dragInProgress = false;
+ dragStartPosition = QPoint();
+ }
+ layoutWidgets();
+ } else {
+ if (!validIndex(index))
+ return;
+ tabList[index].dragOffset = 0;
+ }
+ q->update();
+}
+
+/*!\reimp
+*/
+void QTabBar::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QTabBar);
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+#ifdef Q_WS_MAC
+ d->previousPressedIndex = -1;
+#endif
+ if (d->movable && d->dragInProgress && d->validIndex(d->pressedIndex)) {
+ int length = d->tabList[d->pressedIndex].dragOffset;
+ int width = verticalTabs(d->shape)
+ ? tabRect(d->pressedIndex).height()
+ : tabRect(d->pressedIndex).width();
+ int duration = qMin(ANIMATION_DURATION,
+ (qAbs(length) * ANIMATION_DURATION) / width);
+ d->tabList[d->pressedIndex].startAnimation(d, duration);
+ d->dragInProgress = false;
+ d->movingTab->setVisible(false);
+ d->dragStartPosition = QPoint();
+ }
+
+ int i = d->indexAtPos(event->pos()) == d->pressedIndex ? d->pressedIndex : -1;
+ d->pressedIndex = -1;
+ QStyleOptionTabBarBaseV2 optTabBase;
+ optTabBase.initFrom(this);
+ optTabBase.documentMode = d->documentMode;
+ if (style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this) == QEvent::MouseButtonRelease)
+ setCurrentIndex(i);
+}
+
+/*!\reimp
+ */
+void QTabBar::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QTabBar);
+ if (event->key() != Qt::Key_Left && event->key() != Qt::Key_Right) {
+ event->ignore();
+ return;
+ }
+ int offset = event->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1;
+ d->setCurrentNextEnabledIndex(offset);
+}
+
+/*!\reimp
+ */
+#ifndef QT_NO_WHEELEVENT
+void QTabBar::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QTabBar);
+ int offset = event->delta() > 0 ? -1 : 1;
+ d->setCurrentNextEnabledIndex(offset);
+ QWidget::wheelEvent(event);
+}
+#endif //QT_NO_WHEELEVENT
+
+void QTabBarPrivate::setCurrentNextEnabledIndex(int offset)
+{
+ Q_Q(QTabBar);
+ for (int index = currentIndex + offset; validIndex(index); index += offset) {
+ if (tabList.at(index).enabled) {
+ q->setCurrentIndex(index);
+ break;
+ }
+ }
+}
+
+/*!\reimp
+ */
+void QTabBar::changeEvent(QEvent *event)
+{
+ Q_D(QTabBar);
+ if (event->type() == QEvent::StyleChange) {
+ if (!d->elideModeSetByUser)
+ d->elideMode = Qt::TextElideMode(style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, this));
+ if (!d->useScrollButtonsSetByUser)
+ d->useScrollButtons = !style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, this);
+ d->refresh();
+ } else if (event->type() == QEvent::FontChange) {
+ d->refresh();
+ }
+ QWidget::changeEvent(event);
+}
+
+/*!
+ \property QTabBar::elideMode
+ \brief how to elide text in the tab bar
+ \since 4.2
+
+ This property controls how items are elided when there is not
+ enough space to show them for a given tab bar size.
+
+ By default the value is style dependent.
+
+ \sa QTabWidget::elideMode usesScrollButtons QStyle::SH_TabBar_ElideMode
+*/
+
+Qt::TextElideMode QTabBar::elideMode() const
+{
+ Q_D(const QTabBar);
+ return d->elideMode;
+}
+
+void QTabBar::setElideMode(Qt::TextElideMode mode)
+{
+ Q_D(QTabBar);
+ d->elideMode = mode;
+ d->elideModeSetByUser = true;
+ d->refresh();
+}
+
+/*!
+ \property QTabBar::usesScrollButtons
+ \brief Whether or not a tab bar should use buttons to scroll tabs when it
+ has many tabs.
+ \since 4.2
+
+ When there are too many tabs in a tab bar for its size, the tab bar can either choose
+ to expand its size or to add buttons that allow you to scroll through the tabs.
+
+ By default the value is style dependant.
+
+ \sa elideMode QTabWidget::usesScrollButtons QStyle::SH_TabBar_PreferNoArrows
+*/
+bool QTabBar::usesScrollButtons() const
+{
+ return d_func()->useScrollButtons;
+}
+
+void QTabBar::setUsesScrollButtons(bool useButtons)
+{
+ Q_D(QTabBar);
+ d->useScrollButtonsSetByUser = true;
+ if (d->useScrollButtons == useButtons)
+ return;
+ d->useScrollButtons = useButtons;
+ d->refresh();
+}
+
+/*!
+ \fn void QTabBar::setCurrentTab(int index)
+
+ Use setCurrentIndex() instead.
+*/
+
+/*!
+ \fn void QTabBar::selected(int index);
+
+ Use currentChanged() instead.
+*/
+
+
+/*!
+ \property QTabBar::tabsClosable
+ \brief Whether or not a tab bar should place close buttons on each tab
+ \since 4.5
+
+ When tabsClosable is set to true a close button will appear on the tab on
+ either the left or right hand side depending upon the style. When the button
+ is clicked the tab the signal tabCloseRequested will be emitted.
+
+ By default the value is false.
+
+ \sa setTabButton(), tabRemoved()
+*/
+
+bool QTabBar::tabsClosable() const
+{
+ Q_D(const QTabBar);
+ return d->closeButtonOnTabs;
+}
+
+void QTabBar::setTabsClosable(bool closable)
+{
+ Q_D(QTabBar);
+ if (d->closeButtonOnTabs == closable)
+ return;
+ d->closeButtonOnTabs = closable;
+ ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
+ if (!closable) {
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ if (closeSide == LeftSide && d->tabList[i].leftWidget) {
+ d->tabList[i].leftWidget->deleteLater();
+ d->tabList[i].leftWidget = 0;
+ }
+ if (closeSide == RightSide && d->tabList[i].rightWidget) {
+ d->tabList[i].rightWidget->deleteLater();
+ d->tabList[i].rightWidget = 0;
+ }
+ }
+ } else {
+ bool newButtons = false;
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ if (tabButton(i, closeSide))
+ continue;
+ newButtons = true;
+ QAbstractButton *closeButton = new CloseButton(this);
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
+ setTabButton(i, closeSide, closeButton);
+ }
+ if (newButtons)
+ d->layoutTabs();
+ }
+ update();
+}
+
+/*!
+ \enum QTabBar::ButtonPosition
+ \since 4.5
+
+ This enum type lists the location of the widget on a tab.
+
+ \value LeftSide Left side of the tab.
+
+ \value RightSide Right side of the tab.
+
+*/
+
+/*!
+ \enum QTabBar::SelectionBehavior
+ \since 4.5
+
+ This enum type lists the behavior of QTabBar when a tab is removed
+ and the tab being removed is also the current tab.
+
+ \value SelectLeftTab Select the tab to the left of the one being removed.
+
+ \value SelectRightTab Select the tab to the right of the one being removed.
+
+ \value SelectPreviousTab Select the previously selected tab.
+
+*/
+
+/*!
+ \property QTabBar::selectionBehaviorOnRemove
+ \brief What tab should be set as current when removeTab is called if
+ the removed tab is also the current tab.
+ \since 4.5
+
+ By default the value is SelectRightTab.
+
+ \sa removeTab()
+*/
+
+
+QTabBar::SelectionBehavior QTabBar::selectionBehaviorOnRemove() const
+{
+ Q_D(const QTabBar);
+ return d->selectionBehaviorOnRemove;
+}
+
+void QTabBar::setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior behavior)
+{
+ Q_D(QTabBar);
+ d->selectionBehaviorOnRemove = behavior;
+}
+
+/*!
+ \property QTabBar::expanding
+ \brief When expanding is true QTabBar will expand the tabs to use the empty space.
+ \since 4.5
+
+ By default the value is true.
+
+ \sa QTabWidget::documentMode
+*/
+
+bool QTabBar::expanding() const
+{
+ Q_D(const QTabBar);
+ return d->expanding;
+}
+
+void QTabBar::setExpanding(bool enabled)
+{
+ Q_D(QTabBar);
+ if (d->expanding == enabled)
+ return;
+ d->expanding = enabled;
+ d->layoutTabs();
+}
+
+/*!
+ \property QTabBar::movable
+ \brief This property holds whether the user can move the tabs
+ within the tabbar area.
+
+ \since 4.5
+
+ By default, this property is false;
+*/
+
+bool QTabBar::isMovable() const
+{
+ Q_D(const QTabBar);
+ return d->movable;
+}
+
+void QTabBar::setMovable(bool movable)
+{
+ Q_D(QTabBar);
+ d->movable = movable;
+}
+
+
+/*!
+ \property QTabBar::documentMode
+ \brief Whether or not the tab bar is rendered in a mode suitable for the main window.
+ \since 4.5
+
+ This property is used as a hint for styles to draw the tabs in a different
+ way then they would normally look in a tab widget. On Mac OS X this will
+ look similar to the tabs in Safari or Leopard's Terminal.app.
+
+ \sa QTabWidget::documentMode
+*/
+bool QTabBar::documentMode() const
+{
+ return d_func()->documentMode;
+}
+
+void QTabBar::setDocumentMode(bool enabled)
+{
+ Q_D(QTabBar);
+
+ d->documentMode = enabled;
+ d->updateMacBorderMetrics();
+}
+
+/*!
+ Sets \a widget on the tab \a index. The widget is placed
+ on the left or right hand side depending upon the \a position.
+ \since 4.5
+
+ Any previously set widget in \a position is hidden.
+
+ The tab bar will take ownership of the widget and so all widgets set here
+ will be deleted by the tab bar when it is destroyed unless you separately
+ reparent the widget after setting some other widget (or 0).
+
+ \sa tabsClosable()
+ */
+void QTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget)
+{
+ Q_D(QTabBar);
+ if (index < 0 || index >= d->tabList.count())
+ return;
+ if (widget) {
+ widget->setParent(this);
+ // make sure our left and right widgets stay on top
+ widget->lower();
+ widget->show();
+ }
+ if (position == LeftSide) {
+ if (d->tabList[index].leftWidget)
+ d->tabList[index].leftWidget->hide();
+ d->tabList[index].leftWidget = widget;
+ } else {
+ if (d->tabList[index].rightWidget)
+ d->tabList[index].rightWidget->hide();
+ d->tabList[index].rightWidget = widget;
+ }
+ d->layoutTabs();
+ d->refresh();
+ update();
+}
+
+/*!
+ Returns the widget set a tab \a index and \a position or 0 if
+ one is not set.
+ */
+QWidget *QTabBar::tabButton(int index, ButtonPosition position) const
+{
+ Q_D(const QTabBar);
+ if (index < 0 || index >= d->tabList.count())
+ return 0;
+ if (position == LeftSide)
+ return d->tabList.at(index).leftWidget;
+ else
+ return d->tabList.at(index).rightWidget;
+}
+
+CloseButton::CloseButton(QWidget *parent)
+ : QAbstractButton(parent)
+{
+ setFocusPolicy(Qt::NoFocus);
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::ArrowCursor);
+#endif
+#ifndef QT_NO_TOOLTIP
+ setToolTip(tr("Close Tab"));
+#endif
+ resize(sizeHint());
+}
+
+QSize CloseButton::sizeHint() const
+{
+ ensurePolished();
+ int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
+ int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
+ return QSize(width, height);
+}
+
+void CloseButton::enterEvent(QEvent *event)
+{
+ if (isEnabled())
+ update();
+ QAbstractButton::enterEvent(event);
+}
+
+void CloseButton::leaveEvent(QEvent *event)
+{
+ if (isEnabled())
+ update();
+ QAbstractButton::leaveEvent(event);
+}
+
+void CloseButton::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ opt.init(this);
+ opt.state |= QStyle::State_AutoRaise;
+ if (isEnabled() && underMouse() && !isChecked() && !isDown())
+ opt.state |= QStyle::State_Raised;
+ if (isChecked())
+ opt.state |= QStyle::State_On;
+ if (isDown())
+ opt.state |= QStyle::State_Sunken;
+
+ if (const QTabBar *tb = qobject_cast<const QTabBar *>(parent())) {
+ int index = tb->currentIndex();
+ QTabBar::ButtonPosition position = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb);
+ if (tb->tabButton(index, position) == this)
+ opt.state |= QStyle::State_Selected;
+ }
+
+ style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtabbar.cpp"
+
+#endif // QT_NO_TABBAR
diff --git a/src/widgets/widgets/qtabbar.h b/src/widgets/widgets/qtabbar.h
new file mode 100644
index 0000000000..3e2ff3e9d0
--- /dev/null
+++ b/src/widgets/widgets/qtabbar.h
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTABBAR_H
+#define QTABBAR_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TABBAR
+
+class QIcon;
+class QTabBarPrivate;
+class QStyleOptionTab;
+
+class Q_WIDGETS_EXPORT QTabBar: public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(Shape)
+ Q_PROPERTY(Shape shape READ shape WRITE setShape)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool drawBase READ drawBase WRITE setDrawBase)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+ Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode)
+ Q_PROPERTY(bool usesScrollButtons READ usesScrollButtons WRITE setUsesScrollButtons)
+ Q_PROPERTY(bool tabsClosable READ tabsClosable WRITE setTabsClosable)
+ Q_PROPERTY(SelectionBehavior selectionBehaviorOnRemove READ selectionBehaviorOnRemove WRITE setSelectionBehaviorOnRemove)
+ Q_PROPERTY(bool expanding READ expanding WRITE setExpanding)
+ Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
+ Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
+
+public:
+ explicit QTabBar(QWidget* parent=0);
+ ~QTabBar();
+
+ enum Shape { RoundedNorth, RoundedSouth, RoundedWest, RoundedEast,
+ TriangularNorth, TriangularSouth, TriangularWest, TriangularEast
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ , RoundedAbove = RoundedNorth, RoundedBelow = RoundedSouth,
+ TriangularAbove = TriangularNorth, TriangularBelow = TriangularSouth
+#endif
+ };
+
+ enum ButtonPosition {
+ LeftSide,
+ RightSide
+ };
+
+ enum SelectionBehavior {
+ SelectLeftTab,
+ SelectRightTab,
+ SelectPreviousTab
+ };
+
+ Shape shape() const;
+ void setShape(Shape shape);
+
+ int addTab(const QString &text);
+ int addTab(const QIcon &icon, const QString &text);
+
+ int insertTab(int index, const QString &text);
+ int insertTab(int index, const QIcon&icon, const QString &text);
+
+ void removeTab(int index);
+ void moveTab(int from, int to);
+
+ bool isTabEnabled(int index) const;
+ void setTabEnabled(int index, bool);
+
+ QString tabText(int index) const;
+ void setTabText(int index, const QString &text);
+
+ QColor tabTextColor(int index) const;
+ void setTabTextColor(int index, const QColor &color);
+
+ QIcon tabIcon(int index) const;
+ void setTabIcon(int index, const QIcon &icon);
+
+ Qt::TextElideMode elideMode() const;
+ void setElideMode(Qt::TextElideMode);
+
+#ifndef QT_NO_TOOLTIP
+ void setTabToolTip(int index, const QString &tip);
+ QString tabToolTip(int index) const;
+#endif
+
+#ifndef QT_NO_WHATSTHIS
+ void setTabWhatsThis(int index, const QString &text);
+ QString tabWhatsThis(int index) const;
+#endif
+
+ void setTabData(int index, const QVariant &data);
+ QVariant tabData(int index) const;
+
+ QRect tabRect(int index) const;
+ int tabAt(const QPoint &pos) const;
+
+ int currentIndex() const;
+ int count() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setDrawBase(bool drawTheBase);
+ bool drawBase() const;
+
+ QSize iconSize() const;
+ void setIconSize(const QSize &size);
+
+ bool usesScrollButtons() const;
+ void setUsesScrollButtons(bool useButtons);
+
+ bool tabsClosable() const;
+ void setTabsClosable(bool closable);
+
+ void setTabButton(int index, ButtonPosition position, QWidget *widget);
+ QWidget *tabButton(int index, ButtonPosition position) const;
+
+ SelectionBehavior selectionBehaviorOnRemove() const;
+ void setSelectionBehaviorOnRemove(SelectionBehavior behavior);
+
+ bool expanding() const;
+ void setExpanding(bool enabled);
+
+ bool isMovable() const;
+ void setMovable(bool movable);
+
+ bool documentMode() const;
+ void setDocumentMode(bool set);
+
+public Q_SLOTS:
+ void setCurrentIndex(int index);
+
+Q_SIGNALS:
+ void currentChanged(int index);
+ void tabCloseRequested(int index);
+ void tabMoved(int from, int to);
+
+protected:
+ virtual QSize tabSizeHint(int index) const;
+ virtual void tabInserted(int index);
+ virtual void tabRemoved(int index);
+ virtual void tabLayoutChange();
+
+ bool event(QEvent *);
+ void resizeEvent(QResizeEvent *);
+ void showEvent(QShowEvent *);
+ void hideEvent(QHideEvent *);
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent (QMouseEvent *);
+ void mouseMoveEvent (QMouseEvent *);
+ void mouseReleaseEvent (QMouseEvent *);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *event);
+#endif
+ void keyPressEvent(QKeyEvent *);
+ void changeEvent(QEvent *);
+ void initStyleOption(QStyleOptionTab *option, int tabIndex) const;
+
+#ifdef QT3_SUPPORT
+public Q_SLOTS:
+ QT_MOC_COMPAT void setCurrentTab(int index) { setCurrentIndex(index); }
+Q_SIGNALS:
+ QT_MOC_COMPAT void selected(int);
+#endif
+
+ friend class QAccessibleTabBar;
+private:
+ Q_DISABLE_COPY(QTabBar)
+ Q_DECLARE_PRIVATE(QTabBar)
+ Q_PRIVATE_SLOT(d_func(), void _q_scrollTabs())
+ Q_PRIVATE_SLOT(d_func(), void _q_closeTab())
+};
+
+#endif // QT_NO_TABBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTABBAR_H
diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h
new file mode 100644
index 0000000000..69ca361967
--- /dev/null
+++ b/src/widgets/widgets/qtabbar_p.h
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTABBAR_P_H
+#define QTABBAR_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 "qtabbar.h"
+#include "private/qwidget_p.h"
+
+#include <qicon.h>
+#include <qtoolbutton.h>
+#include <qdebug.h>
+#include <qvariantanimation.h>
+
+#ifndef QT_NO_TABBAR
+
+#define ANIMATION_DURATION 250
+
+#include <qstyleoption.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTabBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QTabBar)
+public:
+ QTabBarPrivate()
+ :currentIndex(-1), pressedIndex(-1), shape(QTabBar::RoundedNorth), layoutDirty(false),
+ drawBase(true), scrollOffset(0), elideModeSetByUser(false), useScrollButtonsSetByUser(false), expanding(true), closeButtonOnTabs(false),
+ selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false),
+ dragInProgress(false), documentMode(false), movingTab(0)
+#ifdef Q_WS_MAC
+ , previousPressedIndex(-1)
+#endif
+ {}
+
+ int currentIndex;
+ int pressedIndex;
+ QTabBar::Shape shape;
+ bool layoutDirty;
+ bool drawBase;
+ int scrollOffset;
+
+ struct Tab {
+ inline Tab(const QIcon &ico, const QString &txt)
+ : enabled(true) , shortcutId(0), text(txt), icon(ico),
+ leftWidget(0), rightWidget(0), lastTab(-1), dragOffset(0)
+#ifndef QT_NO_ANIMATION
+ , animation(0)
+#endif //QT_NO_ANIMATION
+ {}
+ bool operator==(const Tab &other) const { return &other == this; }
+ bool enabled;
+ int shortcutId;
+ QString text;
+#ifndef QT_NO_TOOLTIP
+ QString toolTip;
+#endif
+#ifndef QT_NO_WHATSTHIS
+ QString whatsThis;
+#endif
+ QIcon icon;
+ QRect rect;
+ QRect minRect;
+ QRect maxRect;
+
+ QColor textColor;
+ QVariant data;
+ QWidget *leftWidget;
+ QWidget *rightWidget;
+ int lastTab;
+ int dragOffset;
+
+#ifndef QT_NO_ANIMATION
+ ~Tab() { delete animation; }
+ struct TabBarAnimation : public QVariantAnimation {
+ TabBarAnimation(Tab *t, QTabBarPrivate *_priv) : tab(t), priv(_priv)
+ { setEasingCurve(QEasingCurve::InOutQuad); }
+
+ void updateCurrentValue(const QVariant &current)
+ { priv->moveTab(priv->tabList.indexOf(*tab), current.toInt()); }
+
+ void updateState(State, State newState)
+ { if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(*tab)); }
+ private:
+ //these are needed for the callbacks
+ Tab *tab;
+ QTabBarPrivate *priv;
+ } *animation;
+
+ void startAnimation(QTabBarPrivate *priv, int duration) {
+ if (!animation)
+ animation = new TabBarAnimation(this, priv);
+ animation->setStartValue(dragOffset);
+ animation->setEndValue(0);
+ animation->setDuration(duration);
+ animation->start();
+ }
+#else
+ void startAnimation(QTabBarPrivate *priv, int duration)
+ { Q_UNUSED(duration); priv->moveTabFinished(priv->tabList.indexOf(*this)); }
+#endif //QT_NO_ANIMATION
+ };
+ QList<Tab> tabList;
+
+ int calculateNewPosition(int from, int to, int index) const;
+ void slide(int from, int to);
+ void init();
+ int extraWidth() const;
+
+ Tab *at(int index);
+ const Tab *at(int index) const;
+
+ int indexAtPos(const QPoint &p) const;
+
+ inline bool validIndex(int index) const { return index >= 0 && index < tabList.count(); }
+ void setCurrentNextEnabledIndex(int offset);
+
+ QSize minimumTabSizeHint(int index);
+
+ QToolButton* rightB; // right or bottom
+ QToolButton* leftB; // left or top
+
+ void _q_scrollTabs();
+ void _q_closeTab();
+ void moveTab(int index, int offset);
+ void moveTabFinished(int index);
+ QRect hoverRect;
+
+ void refresh();
+ void layoutTabs();
+ void layoutWidgets(int start = 0);
+ void layoutTab(int index);
+ void updateMacBorderMetrics();
+ void setupMovableTab();
+
+ void makeVisible(int index);
+ QSize iconSize;
+ Qt::TextElideMode elideMode;
+ bool elideModeSetByUser;
+ bool useScrollButtons;
+ bool useScrollButtonsSetByUser;
+
+ bool expanding;
+ bool closeButtonOnTabs;
+ QTabBar::SelectionBehavior selectionBehaviorOnRemove;
+
+ QPoint dragStartPosition;
+ bool paintWithOffsets;
+ bool movable;
+ bool dragInProgress;
+ bool documentMode;
+
+ QWidget *movingTab;
+#ifdef Q_WS_MAC
+ int previousPressedIndex;
+#endif
+ // shared by tabwidget and qtabbar
+ static void initStyleBaseOption(QStyleOptionTabBarBaseV2 *optTabBase, QTabBar *tabbar, QSize size)
+ {
+ QStyleOptionTab tabOverlap;
+ tabOverlap.shape = tabbar->shape();
+ int overlap = tabbar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, tabbar);
+ QWidget *theParent = tabbar->parentWidget();
+ optTabBase->init(tabbar);
+ optTabBase->shape = tabbar->shape();
+ optTabBase->documentMode = tabbar->documentMode();
+ if (theParent && overlap > 0) {
+ QRect rect;
+ switch (tabOverlap.shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ rect.setRect(0, size.height()-overlap, size.width(), overlap);
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ rect.setRect(0, 0, size.width(), overlap);
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ rect.setRect(0, 0, overlap, size.height());
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ rect.setRect(size.width() - overlap, 0, overlap, size.height());
+ break;
+ }
+ optTabBase->rect = rect;
+ }
+ }
+
+};
+
+class CloseButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ CloseButton(QWidget *parent = 0);
+
+ QSize sizeHint() const;
+ inline QSize minimumSizeHint() const
+ { return sizeHint(); }
+ void enterEvent(QEvent *event);
+ void leaveEvent(QEvent *event);
+ void paintEvent(QPaintEvent *event);
+};
+
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif
diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp
new file mode 100644
index 0000000000..c6551e591e
--- /dev/null
+++ b/src/widgets/widgets/qtabwidget.cpp
@@ -0,0 +1,1516 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtabwidget.h"
+
+#ifndef QT_NO_TABWIDGET
+#include "private/qwidget_p.h"
+#include "private/qtabbar_p.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "qlayout.h"
+#include "qstackedwidget.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qstylepainter.h"
+#include "qtabbar.h"
+#include "qtoolbutton.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QTabWidget
+ \brief The QTabWidget class provides a stack of tabbed widgets.
+
+ \ingroup organizers
+ \ingroup basicwidgets
+
+
+ A tab widget provides a tab bar (see QTabBar) and a "page area"
+ that is used to display pages related to each tab. By default, the
+ tab bar is shown above the page area, but different configurations
+ are available (see \l{TabPosition}). Each tab is associated with a
+ different widget (called a page). Only the current page is shown in
+ the page area; all the other pages are hidden. The user can show a
+ different page by clicking on its tab or by pressing its
+ Alt+\e{letter} shortcut if it has one.
+
+ The normal way to use QTabWidget is to do the following:
+ \list 1
+ \i Create a QTabWidget.
+ \i Create a QWidget for each of the pages in the tab dialog, but
+ do not specify parent widgets for them.
+ \i Insert child widgets into the page widget, using layouts to
+ position them as normal.
+ \i Call addTab() or insertTab() to put the page widgets into the
+ tab widget, giving each tab a suitable label with an optional
+ keyboard shortcut.
+ \endlist
+
+ The position of the tabs is defined by \l tabPosition, their shape
+ by \l tabShape.
+
+ The signal currentChanged() is emitted when the user selects a
+ page.
+
+ The current page index is available as currentIndex(), the current
+ page widget with currentWidget(). You can retrieve a pointer to a
+ page widget with a given index using widget(), and can find the
+ index position of a widget with indexOf(). Use setCurrentWidget()
+ or setCurrentIndex() to show a particular page.
+
+ You can change a tab's text and icon using setTabText() or
+ setTabIcon(). A tab and its associated page can be removed with
+ removeTab().
+
+ Each tab is either enabled or disabled at any given time (see
+ setTabEnabled()). If a tab is enabled, the tab text is drawn
+ normally and the user can select that tab. If it is disabled, the
+ tab is drawn in a different way and the user cannot select that
+ tab. Note that even if a tab is disabled, the page can still be
+ visible, for example if all of the tabs happen to be disabled.
+
+ Tab widgets can be a very good way to split up a complex dialog.
+ An alternative is to use a QStackedWidget for which you provide some
+ means of navigating between pages, for example, a QToolBar or a
+ QListWidget.
+
+ Most of the functionality in QTabWidget is provided by a QTabBar
+ (at the top, providing the tabs) and a QStackedWidget (most of the
+ area, organizing the individual pages).
+
+ \table 100%
+ \row \o \inlineimage windowsxp-tabwidget.png Screenshot of a Windows XP style tab widget
+ \o \inlineimage macintosh-tabwidget.png Screenshot of a Macintosh style tab widget
+ \o \inlineimage plastique-tabwidget.png Screenshot of a Plastique style tab widget
+ \row \o A Windows XP style tab widget.
+ \o A Macintosh style tab widget.
+ \o A Plastique style tab widget.
+ \endtable
+
+ \sa QTabBar, QStackedWidget, QToolBox, {Tab Dialog Example}
+*/
+
+/*!
+ \enum QTabWidget::TabPosition
+
+ This enum type defines where QTabWidget draws the tab row:
+
+ \value North The tabs are drawn above the pages.
+ \value South The tabs are drawn below the pages.
+ \value West The tabs are drawn to the left of the pages.
+ \value East The tabs are drawn to the right of the pages.
+ \omitvalue Bottom
+ \omitvalue Top
+*/
+
+/*!
+ \enum QTabWidget::TabShape
+
+ This enum type defines the shape of the tabs:
+ \value Rounded The tabs are drawn with a rounded look. This is the default
+ shape.
+ \value Triangular The tabs are drawn with a triangular look.
+*/
+
+/*!
+ \fn void QTabWidget::selected(const QString &tabLabel)
+
+ This signal is emitted whenever a tab is selected (raised),
+ including during the first show().
+
+ You can normally use currentChanged() instead.
+*/
+
+/*!
+ \fn void QTabWidget::currentChanged(int index)
+
+ This signal is emitted whenever the current page index changes.
+ The parameter is the new current page \a index position, or -1
+ if there isn't a new one (for example, if there are no widgets
+ in the QTabWidget)
+
+ \sa currentWidget() currentIndex
+*/
+
+/*!
+ \fn void QTabWidget::tabCloseRequested(int index)
+ \since 4.5
+
+ This signal is emitted when the close button on a tab is clicked.
+ The \a index is the index that should be removed.
+
+ \sa setTabsClosable()
+*/
+
+class QTabWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QTabWidget)
+
+public:
+ QTabWidgetPrivate();
+ ~QTabWidgetPrivate();
+ void updateTabBarPosition();
+ void _q_showTab(int);
+ void _q_removeTab(int);
+ void _q_tabMoved(int from, int to);
+ void init();
+ bool hasHeightForWidth() const;
+
+ QTabBar *tabs;
+ QStackedWidget *stack;
+ QRect panelRect;
+ bool dirty;
+ QTabWidget::TabPosition pos;
+ QTabWidget::TabShape shape;
+ int alignment;
+ QWidget *leftCornerWidget;
+ QWidget *rightCornerWidget;
+};
+
+QTabWidgetPrivate::QTabWidgetPrivate()
+ : tabs(0), stack(0), dirty(true),
+ pos(QTabWidget::North), shape(QTabWidget::Rounded),
+ leftCornerWidget(0), rightCornerWidget(0)
+{}
+
+QTabWidgetPrivate::~QTabWidgetPrivate()
+{}
+
+void QTabWidgetPrivate::init()
+{
+ Q_Q(QTabWidget);
+
+ stack = new QStackedWidget(q);
+ stack->setObjectName(QLatin1String("qt_tabwidget_stackedwidget"));
+ stack->setLineWidth(0);
+ // hack so that QMacStyle::layoutSpacing() can detect tab widget pages
+ stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::TabWidget));
+
+ QObject::connect(stack, SIGNAL(widgetRemoved(int)), q, SLOT(_q_removeTab(int)));
+ QTabBar *tabBar = new QTabBar(q);
+ tabBar->setObjectName(QLatin1String("qt_tabwidget_tabbar"));
+ tabBar->setDrawBase(false);
+ q->setTabBar(tabBar);
+
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding,
+ QSizePolicy::TabWidget));
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ q->setFocusPolicy(Qt::NoFocus);
+ else
+#endif
+ q->setFocusPolicy(Qt::TabFocus);
+ q->setFocusProxy(tabs);
+ q->setTabPosition(static_cast<QTabWidget::TabPosition> (q->style()->styleHint(
+ QStyle::SH_TabWidget_DefaultTabPosition, 0, q )));
+
+}
+
+bool QTabWidgetPrivate::hasHeightForWidth() const
+{
+ bool has = size_policy.hasHeightForWidth();
+ if (!has && stack)
+ has = qt_widget_private(stack)->hasHeightForWidth();
+ return has;
+}
+
+
+/*!
+ Initialize \a option with the values from this QTabWidget. This method is useful
+ for subclasses when they need a QStyleOptionTabWidgetFrame, but don't want to fill
+ in all the information themselves.
+
+ \sa QStyleOption::initFrom() QTabBar::initStyleOption()
+*/
+void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QTabWidget);
+ option->initFrom(this);
+
+ if (documentMode())
+ option->lineWidth = 0;
+ else
+ option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this);
+
+ int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0, this);
+ QSize t(0, d->stack->frameWidth());
+ if (d->tabs->isVisibleTo(const_cast<QTabWidget *>(this))) {
+ t = d->tabs->sizeHint();
+ if (documentMode()) {
+ if (tabPosition() == East || tabPosition() == West) {
+ t.setHeight(height());
+ } else {
+ t.setWidth(width());
+ }
+ }
+ }
+
+ if (d->rightCornerWidget) {
+ const QSize rightCornerSizeHint = d->rightCornerWidget->sizeHint();
+ const QSize bounds(rightCornerSizeHint.width(), t.height() - exth);
+ option->rightCornerWidgetSize = rightCornerSizeHint.boundedTo(bounds);
+ } else {
+ option->rightCornerWidgetSize = QSize(0, 0);
+ }
+
+ if (d->leftCornerWidget) {
+ const QSize leftCornerSizeHint = d->leftCornerWidget->sizeHint();
+ const QSize bounds(leftCornerSizeHint.width(), t.height() - exth);
+ option->leftCornerWidgetSize = leftCornerSizeHint.boundedTo(bounds);
+ } else {
+ option->leftCornerWidgetSize = QSize(0, 0);
+ }
+
+ switch (d->pos) {
+ case QTabWidget::North:
+ option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedNorth
+ : QTabBar::TriangularNorth;
+ break;
+ case QTabWidget::South:
+ option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedSouth
+ : QTabBar::TriangularSouth;
+ break;
+ case QTabWidget::West:
+ option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedWest
+ : QTabBar::TriangularWest;
+ break;
+ case QTabWidget::East:
+ option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedEast
+ : QTabBar::TriangularEast;
+ break;
+ }
+
+ option->tabBarSize = t;
+
+ if (QStyleOptionTabWidgetFrameV2 *tabframe = qstyleoption_cast<QStyleOptionTabWidgetFrameV2*>(option)) {
+ QRect tbRect = tabBar()->geometry();
+ QRect selectedTabRect = tabBar()->tabRect(tabBar()->currentIndex());
+ tabframe->tabBarRect = tbRect;
+ selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + tbRect.topLeft());
+ tabframe->selectedTabRect = selectedTabRect;
+ }
+}
+
+/*!
+ Constructs a tabbed widget with parent \a parent.
+*/
+QTabWidget::QTabWidget(QWidget *parent)
+ : QWidget(*new QTabWidgetPrivate, parent, 0)
+{
+ Q_D(QTabWidget);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QTabWidget::QTabWidget(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QWidget(*new QTabWidgetPrivate, parent, f)
+{
+ Q_D(QTabWidget);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+#endif
+
+/*!
+ Destroys the tabbed widget.
+*/
+QTabWidget::~QTabWidget()
+{
+}
+
+/*!
+ \fn int QTabWidget::addTab(QWidget *page, const QString &label)
+
+ Adds a tab with the given \a page and \a label to the tab widget,
+ and returns the index of the tab in the tab bar.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as a shortcut for the tab, e.g. if the
+ label is "Bro\&wse" then Alt+W becomes a shortcut which will
+ move the focus to this tab.
+
+ \note If you call addTab() after show(), the layout system will try
+ to adjust to the changes in its widgets hierarchy and may cause
+ flicker. To prevent this, you can set the QWidget::updatesEnabled
+ property to false prior to changes; remember to set the property
+ to true when the changes are done, making the widget receive paint
+ events again.
+
+ \sa insertTab()
+*/
+int QTabWidget::addTab(QWidget *child, const QString &label)
+{
+ return insertTab(-1, child, label);
+}
+
+
+/*!
+ \fn int QTabWidget::addTab(QWidget *page, const QIcon &icon, const QString &label)
+ \overload
+
+ Adds a tab with the given \a page, \a icon, and \a label to the tab
+ widget, and returns the index of the tab in the tab bar.
+
+ This function is the same as addTab(), but with an additional \a
+ icon.
+*/
+int QTabWidget::addTab(QWidget *child, const QIcon& icon, const QString &label)
+{
+ return insertTab(-1, child, icon, label);
+}
+
+
+/*!
+ \fn int QTabWidget::insertTab(int index, QWidget *page, const QString &label)
+
+ Inserts a tab with the given \a label and \a page into the tab
+ widget at the specified \a index, and returns the index of the
+ inserted tab in the tab bar.
+
+ The label is displayed in the tab and may vary in appearance depending
+ on the configuration of the tab widget.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as a shortcut for the tab, e.g. if the
+ label is "Bro\&wse" then Alt+W becomes a shortcut which will
+ move the focus to this tab.
+
+ If \a index is out of range, the tab is simply appended.
+ Otherwise it is inserted at the specified position.
+
+ If the QTabWidget was empty before this function is called, the
+ new page becomes the current page. Inserting a new tab at an index
+ less than or equal to the current index will increment the current
+ index, but keep the current page.
+
+ \note If you call insertTab() after show(), the layout system will try
+ to adjust to the changes in its widgets hierarchy and may cause
+ flicker. To prevent this, you can set the QWidget::updatesEnabled
+ property to false prior to changes; remember to set the property
+ to true when the changes are done, making the widget receive paint
+ events again.
+
+ \sa addTab()
+*/
+int QTabWidget::insertTab(int index, QWidget *w, const QString &label)
+{
+ return insertTab(index, w, QIcon(), label);
+}
+
+
+/*!
+ \fn int QTabWidget::insertTab(int index, QWidget *page, const QIcon& icon, const QString &label)
+ \overload
+
+ Inserts a tab with the given \a label, \a page, and \a icon into
+ the tab widget at the specified \a index, and returns the index of the
+ inserted tab in the tab bar.
+
+ This function is the same as insertTab(), but with an additional
+ \a icon.
+*/
+int QTabWidget::insertTab(int index, QWidget *w, const QIcon& icon, const QString &label)
+{
+ Q_D(QTabWidget);
+ if(!w)
+ return -1;
+ index = d->stack->insertWidget(index, w);
+ d->tabs->insertTab(index, icon, label);
+ setUpLayout();
+ tabInserted(index);
+
+ return index;
+}
+
+
+/*!
+ Defines a new \a label for the page at position \a index's tab.
+
+ If the provided text contains an ampersand character ('&'), a
+ shortcut is automatically created for it. The character that
+ follows the '&' will be used as the shortcut key. Any previous
+ shortcut will be overwritten, or cleared if no shortcut is defined
+ by the text. See the \l {QShortcut#mnemonic}{QShortcut}
+ documentation for details (to display an actual ampersand, use
+ '&&').
+
+*/
+void QTabWidget::setTabText(int index, const QString &label)
+{
+ Q_D(QTabWidget);
+ d->tabs->setTabText(index, label);
+ setUpLayout();
+}
+
+/*!
+ Returns the label text for the tab on the page at position \a index.
+*/
+
+QString QTabWidget::tabText(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->tabText(index);
+}
+
+/*!
+ \overload
+
+ Sets the \a icon for the tab at position \a index.
+*/
+void QTabWidget::setTabIcon(int index, const QIcon &icon)
+{
+ Q_D(QTabWidget);
+ d->tabs->setTabIcon(index, icon);
+ setUpLayout();
+}
+
+/*!
+ Returns the icon for the tab on the page at position \a index.
+*/
+
+QIcon QTabWidget::tabIcon(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->tabIcon(index);
+}
+
+/*!
+ Returns true if the page at position \a index is enabled; otherwise returns false.
+
+ \sa setTabEnabled(), QWidget::isEnabled()
+*/
+
+bool QTabWidget::isTabEnabled(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->isTabEnabled(index);
+}
+
+/*!
+ If \a enable is true, the page at position \a index is enabled; otherwise the page at position \a index is
+ disabled. The page's tab is redrawn appropriately.
+
+ QTabWidget uses QWidget::setEnabled() internally, rather than
+ keeping a separate flag.
+
+ Note that even a disabled tab/page may be visible. If the page is
+ visible already, QTabWidget will not hide it; if all the pages are
+ disabled, QTabWidget will show one of them.
+
+ \sa isTabEnabled(), QWidget::setEnabled()
+*/
+
+void QTabWidget::setTabEnabled(int index, bool enable)
+{
+ Q_D(QTabWidget);
+ d->tabs->setTabEnabled(index, enable);
+ if (QWidget *widget = d->stack->widget(index))
+ widget->setEnabled(enable);
+}
+
+/*!
+ \fn void QTabWidget::setCornerWidget(QWidget *widget, Qt::Corner corner)
+
+ Sets the given \a widget to be shown in the specified \a corner of the
+ tab widget. The geometry of the widget is determined based on the widget's
+ sizeHint() and the style().
+
+ Only the horizontal element of the \a corner will be used.
+
+ Passing 0 shows no widget in the corner.
+
+ Any previously set corner widget is hidden.
+
+ All widgets set here will be deleted by the tab widget when it is
+ destroyed unless you separately reparent the widget after setting
+ some other corner widget (or 0).
+
+ Note: Corner widgets are designed for \l North and \l South tab positions;
+ other orientations are known to not work properly.
+
+ \sa cornerWidget(), setTabPosition()
+*/
+void QTabWidget::setCornerWidget(QWidget * widget, Qt::Corner corner)
+{
+ Q_D(QTabWidget);
+ if (widget && widget->parentWidget() != this)
+ widget->setParent(this);
+
+ if (corner & Qt::TopRightCorner) {
+ if (d->rightCornerWidget)
+ d->rightCornerWidget->hide();
+ d->rightCornerWidget = widget;
+ } else {
+ if (d->leftCornerWidget)
+ d->leftCornerWidget->hide();
+ d->leftCornerWidget = widget;
+ }
+ setUpLayout();
+}
+
+/*!
+ Returns the widget shown in the \a corner of the tab widget or 0.
+*/
+QWidget * QTabWidget::cornerWidget(Qt::Corner corner) const
+{
+ Q_D(const QTabWidget);
+ if (corner & Qt::TopRightCorner)
+ return d->rightCornerWidget;
+ return d->leftCornerWidget;
+}
+
+/*!
+ Removes the tab at position \a index from this stack of widgets.
+ The page widget itself is not deleted.
+
+ \sa addTab(), insertTab()
+*/
+void QTabWidget::removeTab(int index)
+{
+ Q_D(QTabWidget);
+ if (QWidget *w = d->stack->widget(index))
+ d->stack->removeWidget(w);
+}
+
+/*!
+ Returns a pointer to the page currently being displayed by the tab
+ dialog. The tab dialog does its best to make sure that this value
+ is never 0 (but if you try hard enough, it can be).
+
+ \sa currentIndex(), setCurrentWidget()
+*/
+
+QWidget * QTabWidget::currentWidget() const
+{
+ Q_D(const QTabWidget);
+ return d->stack->currentWidget();
+}
+
+/*!
+ Makes \a widget the current widget. The \a widget used must be a page in
+ this tab widget.
+
+ \sa addTab(), setCurrentIndex(), currentWidget()
+ */
+void QTabWidget::setCurrentWidget(QWidget *widget)
+{
+ Q_D(const QTabWidget);
+ d->tabs->setCurrentIndex(indexOf(widget));
+}
+
+
+/*!
+ \property QTabWidget::currentIndex
+ \brief the index position of the current tab page
+
+ The current index is -1 if there is no current widget.
+
+ By default, this property contains a value of -1 because there are initially
+ no tabs in the widget.
+*/
+
+int QTabWidget::currentIndex() const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->currentIndex();
+}
+
+void QTabWidget::setCurrentIndex(int index)
+{
+ Q_D(QTabWidget);
+ d->tabs->setCurrentIndex(index);
+}
+
+
+/*!
+ Returns the index position of the page occupied by the widget \a
+ w, or -1 if the widget cannot be found.
+*/
+int QTabWidget::indexOf(QWidget* w) const
+{
+ Q_D(const QTabWidget);
+ return d->stack->indexOf(w);
+}
+
+
+/*!
+ \reimp
+*/
+void QTabWidget::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+ setUpLayout();
+}
+
+/*!
+ Replaces the dialog's QTabBar heading with the tab bar \a tb. Note
+ that this must be called \e before any tabs have been added, or
+ the behavior is undefined.
+
+ \sa tabBar()
+*/
+void QTabWidget::setTabBar(QTabBar* tb)
+{
+ Q_D(QTabWidget);
+ Q_ASSERT(tb);
+
+ if (tb->parentWidget() != this) {
+ tb->setParent(this);
+ tb->show();
+ }
+ delete d->tabs;
+ d->tabs = tb;
+ setFocusProxy(d->tabs);
+ connect(d->tabs, SIGNAL(currentChanged(int)),
+ this, SLOT(_q_showTab(int)));
+ connect(d->tabs, SIGNAL(tabMoved(int,int)),
+ this, SLOT(_q_tabMoved(int,int)));
+ if (d->tabs->tabsClosable())
+ connect(d->tabs, SIGNAL(tabCloseRequested(int)),
+ this, SIGNAL(tabCloseRequested(int)));
+ tb->setExpanding(!documentMode());
+ setUpLayout();
+}
+
+
+/*!
+ Returns the current QTabBar.
+
+ \sa setTabBar()
+*/
+QTabBar* QTabWidget::tabBar() const
+{
+ Q_D(const QTabWidget);
+ return d->tabs;
+}
+
+/*!
+ Ensures that the selected tab's page is visible and appropriately
+ sized.
+*/
+
+void QTabWidgetPrivate::_q_showTab(int index)
+{
+ Q_Q(QTabWidget);
+ if (index < stack->count() && index >= 0)
+ stack->setCurrentIndex(index);
+ emit q->currentChanged(index);
+#ifdef QT3_SUPPORT
+ emit q->selected(q->tabText(index));
+ emit q->currentChanged(stack->widget(index));
+#endif
+}
+
+void QTabWidgetPrivate::_q_removeTab(int index)
+{
+ Q_Q(QTabWidget);
+ tabs->removeTab(index);
+ q->setUpLayout();
+ q->tabRemoved(index);
+}
+
+void QTabWidgetPrivate::_q_tabMoved(int from, int to)
+{
+ stack->blockSignals(true);
+ QWidget *w = stack->widget(from);
+ stack->removeWidget(w);
+ stack->insertWidget(to, w);
+ stack->blockSignals(false);
+}
+
+/*
+ Set up the layout.
+ Get subrect from the current style, and set the geometry for the
+ stack widget, tab bar and corner widgets.
+*/
+void QTabWidget::setUpLayout(bool onlyCheck)
+{
+ Q_D(QTabWidget);
+ if (onlyCheck && !d->dirty)
+ return; // nothing to do
+
+ QStyleOptionTabWidgetFrameV2 option;
+ initStyleOption(&option);
+
+ // this must be done immediately, because QWidgetItem relies on it (even if !isVisible())
+ d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option);
+
+ if (!isVisible()) {
+ d->dirty = true;
+ return; // we'll do it later
+ }
+
+ QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this);
+ d->panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
+ QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this);
+ QRect leftCornerRect = style()->subElementRect(QStyle::SE_TabWidgetLeftCorner, &option, this);
+ QRect rightCornerRect = style()->subElementRect(QStyle::SE_TabWidgetRightCorner, &option, this);
+
+ d->tabs->setGeometry(tabRect);
+ d->stack->setGeometry(contentsRect);
+ if (d->leftCornerWidget)
+ d->leftCornerWidget->setGeometry(leftCornerRect);
+ if (d->rightCornerWidget)
+ d->rightCornerWidget->setGeometry(rightCornerRect);
+
+ if (!onlyCheck)
+ update();
+ updateGeometry();
+}
+
+/*!
+ \internal
+*/
+static inline QSize basicSize(
+ bool horizontal, const QSize &lc, const QSize &rc, const QSize &s, const QSize &t)
+{
+ return horizontal
+ ? QSize(qMax(s.width(), t.width() + rc.width() + lc.width()),
+ s.height() + (qMax(rc.height(), qMax(lc.height(), t.height()))))
+ : QSize(s.width() + (qMax(rc.width(), qMax(lc.width(), t.width()))),
+ qMax(s.height(), t.height() + rc.height() + lc.height()));
+}
+
+/*!
+ \reimp
+*/
+QSize QTabWidget::sizeHint() const
+{
+ Q_D(const QTabWidget);
+ QSize lc(0, 0), rc(0, 0);
+ QStyleOptionTabWidgetFrameV2 opt;
+ initStyleOption(&opt);
+ opt.state = QStyle::State_None;
+
+ if (d->leftCornerWidget)
+ lc = d->leftCornerWidget->sizeHint();
+ if(d->rightCornerWidget)
+ rc = d->rightCornerWidget->sizeHint();
+ if (!d->dirty) {
+ QTabWidget *that = (QTabWidget*)this;
+ that->setUpLayout(true);
+ }
+ QSize s(d->stack->sizeHint());
+ QSize t(d->tabs->sizeHint());
+ if(usesScrollButtons())
+ t = t.boundedTo(QSize(200,200));
+ else
+ t = t.boundedTo(QApplication::desktop()->size());
+
+ QSize sz = basicSize(d->pos == North || d->pos == South, lc, rc, s, t);
+
+ return style()->sizeFromContents(QStyle::CT_TabWidget, &opt, sz, this)
+ .expandedTo(QApplication::globalStrut());
+}
+
+
+/*!
+ \reimp
+
+ Returns a suitable minimum size for the tab widget.
+*/
+QSize QTabWidget::minimumSizeHint() const
+{
+ Q_D(const QTabWidget);
+ QSize lc(0, 0), rc(0, 0);
+
+ if(d->leftCornerWidget)
+ lc = d->leftCornerWidget->minimumSizeHint();
+ if(d->rightCornerWidget)
+ rc = d->rightCornerWidget->minimumSizeHint();
+ if (!d->dirty) {
+ QTabWidget *that = (QTabWidget*)this;
+ that->setUpLayout(true);
+ }
+ QSize s(d->stack->minimumSizeHint());
+ QSize t(d->tabs->minimumSizeHint());
+
+ QSize sz = basicSize(d->pos == North || d->pos == South, lc, rc, s, t);
+
+ QStyleOptionTabWidgetFrameV2 opt;
+ initStyleOption(&opt);
+ opt.palette = palette();
+ opt.state = QStyle::State_None;
+ return style()->sizeFromContents(QStyle::CT_TabWidget, &opt, sz, this)
+ .expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+int QTabWidget::heightForWidth(int width) const
+{
+ Q_D(const QTabWidget);
+ QStyleOptionTabWidgetFrameV2 opt;
+ initStyleOption(&opt);
+ opt.state = QStyle::State_None;
+
+ QSize zero(0,0);
+ const QSize padding = style()->sizeFromContents(QStyle::CT_TabWidget, &opt, zero, this)
+ .expandedTo(QApplication::globalStrut());
+
+ QSize lc(0, 0), rc(0, 0);
+ if (d->leftCornerWidget)
+ lc = d->leftCornerWidget->sizeHint();
+ if(d->rightCornerWidget)
+ rc = d->rightCornerWidget->sizeHint();
+ if (!d->dirty) {
+ QTabWidget *that = (QTabWidget*)this;
+ that->setUpLayout(true);
+ }
+ QSize t(d->tabs->sizeHint());
+
+ if(usesScrollButtons())
+ t = t.boundedTo(QSize(200,200));
+ else
+ t = t.boundedTo(QApplication::desktop()->size());
+
+ const bool tabIsHorizontal = (d->pos == North || d->pos == South);
+ const int contentsWidth = width - padding.width();
+ int stackWidth = contentsWidth;
+ if (!tabIsHorizontal)
+ stackWidth -= qMax(t.width(), qMax(lc.width(), rc.width()));
+
+ int stackHeight = d->stack->heightForWidth(stackWidth);
+ QSize s(stackWidth, stackHeight);
+
+ QSize contentSize = basicSize(tabIsHorizontal, lc, rc, s, t);
+ return (contentSize + padding).expandedTo(QApplication::globalStrut()).height();
+}
+
+
+/*!
+ \reimp
+ */
+void QTabWidget::showEvent(QShowEvent *)
+{
+ setUpLayout();
+}
+
+void QTabWidgetPrivate::updateTabBarPosition()
+{
+ Q_Q(QTabWidget);
+ switch (pos) {
+ case QTabWidget::North:
+ tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedNorth
+ : QTabBar::TriangularNorth);
+ break;
+ case QTabWidget::South:
+ tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedSouth
+ : QTabBar::TriangularSouth);
+ break;
+ case QTabWidget::West:
+ tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedWest
+ : QTabBar::TriangularWest);
+ break;
+ case QTabWidget::East:
+ tabs->setShape(shape == QTabWidget::Rounded ? QTabBar::RoundedEast
+ : QTabBar::TriangularEast);
+ break;
+ }
+ q->setUpLayout();
+}
+
+/*!
+ \property QTabWidget::tabPosition
+ \brief the position of the tabs in this tab widget
+
+ Possible values for this property are described by the TabPosition
+ enum.
+
+ By default, this property is set to \l North.
+
+ \sa TabPosition
+*/
+QTabWidget::TabPosition QTabWidget::tabPosition() const
+{
+ Q_D(const QTabWidget);
+ return d->pos;
+}
+
+void QTabWidget::setTabPosition(TabPosition pos)
+{
+ Q_D(QTabWidget);
+ if (d->pos == pos)
+ return;
+ d->pos = pos;
+ d->updateTabBarPosition();
+}
+
+/*!
+ \property QTabWidget::tabsClosable
+ \brief whether close buttons are automatically added to each tab.
+
+ \since 4.5
+
+ \sa QTabBar::tabsClosable()
+*/
+bool QTabWidget::tabsClosable() const
+{
+ return tabBar()->tabsClosable();
+}
+
+void QTabWidget::setTabsClosable(bool closeable)
+{
+ if (tabsClosable() == closeable)
+ return;
+
+ tabBar()->setTabsClosable(closeable);
+ if (closeable)
+ connect(tabBar(), SIGNAL(tabCloseRequested(int)),
+ this, SIGNAL(tabCloseRequested(int)));
+ else
+ disconnect(tabBar(), SIGNAL(tabCloseRequested(int)),
+ this, SIGNAL(tabCloseRequested(int)));
+ setUpLayout();
+}
+
+/*!
+ \property QTabWidget::movable
+ \brief This property holds whether the user can move the tabs
+ within the tabbar area.
+
+ \since 4.5
+
+ By default, this property is false;
+*/
+
+bool QTabWidget::isMovable() const
+{
+ return tabBar()->isMovable();
+}
+
+void QTabWidget::setMovable(bool movable)
+{
+ tabBar()->setMovable(movable);
+}
+
+/*!
+ \property QTabWidget::tabShape
+ \brief the shape of the tabs in this tab widget
+
+ Possible values for this property are QTabWidget::Rounded
+ (default) or QTabWidget::Triangular.
+
+ \sa TabShape
+*/
+
+QTabWidget::TabShape QTabWidget::tabShape() const
+{
+ Q_D(const QTabWidget);
+ return d->shape;
+}
+
+void QTabWidget::setTabShape(TabShape s)
+{
+ Q_D(QTabWidget);
+ if (d->shape == s)
+ return;
+ d->shape = s;
+ d->updateTabBarPosition();
+}
+
+/*!
+ \reimp
+ */
+bool QTabWidget::event(QEvent *ev)
+{
+ if (ev->type() == QEvent::LayoutRequest)
+ setUpLayout();
+ return QWidget::event(ev);
+}
+
+/*!
+ \reimp
+ */
+void QTabWidget::changeEvent(QEvent *ev)
+{
+ if (ev->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || ev->type() == QEvent::MacSizeChange
+#endif
+ )
+ setUpLayout();
+ QWidget::changeEvent(ev);
+}
+
+
+/*!
+ \reimp
+ */
+void QTabWidget::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QTabWidget);
+ if (((e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) &&
+ count() > 1 && e->modifiers() & Qt::ControlModifier)
+#ifdef QT_KEYPAD_NAVIGATION
+ || QApplication::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right) && count() > 1
+#endif
+ ) {
+ int pageCount = d->tabs->count();
+ int page = currentIndex();
+ int dx = (e->key() == Qt::Key_Backtab || e->modifiers() & Qt::ShiftModifier) ? -1 : 1;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
+ dx = e->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1;
+#endif
+ for (int pass = 0; pass < pageCount; ++pass) {
+ page+=dx;
+ if (page < 0
+#ifdef QT_KEYPAD_NAVIGATION
+ && !e->isAutoRepeat()
+#endif
+ ) {
+ page = count() - 1;
+ } else if (page >= pageCount
+#ifdef QT_KEYPAD_NAVIGATION
+ && !e->isAutoRepeat()
+#endif
+ ) {
+ page = 0;
+ }
+ if (d->tabs->isTabEnabled(page)) {
+ setCurrentIndex(page);
+ break;
+ }
+ }
+ if (!QApplication::focusWidget())
+ d->tabs->setFocus();
+ } else {
+ e->ignore();
+ }
+}
+
+/*!
+ Returns the tab page at index position \a index or 0 if the \a
+ index is out of range.
+*/
+QWidget *QTabWidget::widget(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->stack->widget(index);
+}
+
+/*!
+ \property QTabWidget::count
+ \brief the number of tabs in the tab bar
+
+ By default, this property contains a value of 0.
+*/
+int QTabWidget::count() const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->count();
+}
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Sets the tab tool tip for the page at position \a index to \a tip.
+
+ \sa tabToolTip()
+*/
+void QTabWidget::setTabToolTip(int index, const QString & tip)
+{
+ Q_D(QTabWidget);
+ d->tabs->setTabToolTip(index, tip);
+}
+
+/*!
+ Returns the tab tool tip for the page at position \a index or
+ an empty string if no tool tip has been set.
+
+ \sa setTabToolTip()
+*/
+QString QTabWidget::tabToolTip(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->tabToolTip(index);
+}
+#endif // QT_NO_TOOLTIP
+
+#ifndef QT_NO_WHATSTHIS
+/*!
+ \since 4.1
+
+ Sets the What's This help text for the page at position \a index
+ to \a text.
+*/
+void QTabWidget::setTabWhatsThis(int index, const QString &text)
+{
+ Q_D(QTabWidget);
+ d->tabs->setTabWhatsThis(index, text);
+}
+
+/*!
+ \since 4.1
+
+ Returns the What's This help text for the page at position \a index,
+ or an empty string if no help text has been set.
+*/
+QString QTabWidget::tabWhatsThis(int index) const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->tabWhatsThis(index);
+}
+#endif // QT_NO_WHATSTHIS
+
+/*!
+ This virtual handler is called after a new tab was added or
+ inserted at position \a index.
+
+ \sa tabRemoved()
+ */
+void QTabWidget::tabInserted(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ This virtual handler is called after a tab was removed from
+ position \a index.
+
+ \sa tabInserted()
+ */
+void QTabWidget::tabRemoved(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ \fn void QTabWidget::paintEvent(QPaintEvent *event)
+
+ Paints the tab widget's tab bar in response to the paint \a event.
+*/
+void QTabWidget::paintEvent(QPaintEvent *)
+{
+ Q_D(QTabWidget);
+ if (documentMode()) {
+ QStylePainter p(this, tabBar());
+ if (QWidget *w = cornerWidget(Qt::TopLeftCorner)) {
+ QStyleOptionTabBarBaseV2 opt;
+ QTabBarPrivate::initStyleBaseOption(&opt, tabBar(), w->size());
+ opt.rect.moveLeft(w->x() + opt.rect.x());
+ opt.rect.moveTop(w->y() + opt.rect.y());
+ p.drawPrimitive(QStyle::PE_FrameTabBarBase, opt);
+ }
+ if (QWidget *w = cornerWidget(Qt::TopRightCorner)) {
+ QStyleOptionTabBarBaseV2 opt;
+ QTabBarPrivate::initStyleBaseOption(&opt, tabBar(), w->size());
+ opt.rect.moveLeft(w->x() + opt.rect.x());
+ opt.rect.moveTop(w->y() + opt.rect.y());
+ p.drawPrimitive(QStyle::PE_FrameTabBarBase, opt);
+ }
+ return;
+ }
+ QStylePainter p(this);
+
+ QStyleOptionTabWidgetFrameV2 opt;
+ initStyleOption(&opt);
+ opt.rect = d->panelRect;
+ p.drawPrimitive(QStyle::PE_FrameTabWidget, opt);
+}
+
+/*!
+ \property QTabWidget::iconSize
+ \brief The size for icons in the tab bar
+ \since 4.2
+
+ The default value is style-dependent. This is the maximum size
+ that the icons will have. Icons are not scaled up if they are of
+ smaller size.
+
+ \sa QTabBar::iconSize
+*/
+QSize QTabWidget::iconSize() const
+{
+ return d_func()->tabs->iconSize();
+}
+
+void QTabWidget::setIconSize(const QSize &size)
+{
+ d_func()->tabs->setIconSize(size);
+}
+
+/*!
+ \property QTabWidget::elideMode
+ \brief how to elide text in the tab bar
+ \since 4.2
+
+ This property controls how items are elided when there is not
+ enough space to show them for a given tab bar size.
+
+ By default the value is style dependant.
+
+ \sa QTabBar::elideMode usesScrollButtons QStyle::SH_TabBar_ElideMode
+*/
+Qt::TextElideMode QTabWidget::elideMode() const
+{
+ return d_func()->tabs->elideMode();
+}
+
+void QTabWidget::setElideMode(Qt::TextElideMode mode)
+{
+ d_func()->tabs->setElideMode(mode);
+}
+
+/*!
+ \property QTabWidget::usesScrollButtons
+ \brief Whether or not a tab bar should use buttons to scroll tabs when it
+ has many tabs.
+ \since 4.2
+
+ When there are too many tabs in a tab bar for its size, the tab bar can either choose
+ to expand its size or to add buttons that allow you to scroll through the tabs.
+
+ By default the value is style dependant.
+
+ \sa elideMode QTabBar::usesScrollButtons QStyle::SH_TabBar_PreferNoArrows
+*/
+bool QTabWidget::usesScrollButtons() const
+{
+ return d_func()->tabs->usesScrollButtons();
+}
+
+void QTabWidget::setUsesScrollButtons(bool useButtons)
+{
+ d_func()->tabs->setUsesScrollButtons(useButtons);
+}
+
+/*!
+ \property QTabWidget::documentMode
+ \brief Whether or not the tab widget is rendered in a mode suitable for document
+ pages. This is the same as document mode on Mac OS X.
+ \since 4.5
+
+ When this property is set the tab widget frame is not rendered. This mode is useful
+ for showing document-type pages where the page covers most of the tab widget
+ area.
+
+ \sa elideMode, QTabBar::documentMode, QTabBar::usesScrollButtons, QStyle::SH_TabBar_PreferNoArrows
+*/
+bool QTabWidget::documentMode() const
+{
+ Q_D(const QTabWidget);
+ return d->tabs->documentMode();
+}
+
+void QTabWidget::setDocumentMode(bool enabled)
+{
+ Q_D(QTabWidget);
+ d->tabs->setDocumentMode(enabled);
+ d->tabs->setExpanding(!enabled);
+ d->tabs->setDrawBase(enabled);
+ setUpLayout();
+}
+
+/*!
+ Removes all the pages, but does not delete them. Calling this function
+ is equivalent to calling removeTab() until the tab widget is empty.
+*/
+void QTabWidget::clear()
+{
+ // ### optimize by introduce QStackedLayout::clear()
+ while (count())
+ removeTab(0);
+}
+
+/*!
+ \fn void QTabWidget::insertTab(QWidget *widget, const QString &label, int index)
+
+ Use insertTab(index, widget, label) instead.
+*/
+
+/*!
+ \fn void QTabWidget::insertTab(QWidget *widget, const QIcon& icon, const QString &label, int index)
+
+ Use insertTab(index, widget, icon, label) instead.
+*/
+
+/*!
+ \fn void QTabWidget::changeTab(QWidget *widget, const QString
+ &label)
+
+ Use setTabText() instead.
+
+*/
+
+/*!
+ \fn void QTabWidget::changeTab(QWidget *widget, const QIcon& icon, const QString &label)
+
+ Use setTabText() and setTabIcon() instead.
+*/
+
+/*!
+ \fn bool QTabWidget::isTabEnabled( QWidget *widget) const
+
+ Use isTabEnabled(tabWidget->indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QTabWidget::setTabEnabled(QWidget *widget, bool b)
+
+ Use setTabEnabled(tabWidget->indexOf(widget), b) instead.
+*/
+
+/*!
+ \fn QString QTabWidget::tabLabel(QWidget *widget) const
+
+ Use tabText(tabWidget->indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QTabWidget::setTabLabel(QWidget *widget, const QString
+ &label)
+
+ Use setTabText(tabWidget->indexOf(widget), label) instead.
+*/
+
+/*!
+ \fn QIcon QTabWidget::tabIconSet(QWidget * widget) const
+
+ Use tabIcon(tabWidget->indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QTabWidget::setTabIconSet(QWidget * widget, const QIcon & icon)
+
+ Use setTabIcon(tabWidget->indexOf(widget), icon) instead.
+*/
+
+/*!
+ \fn void QTabWidget::removeTabToolTip(QWidget * widget)
+
+ Use setTabToolTip(tabWidget->indexOf(widget), QString()) instead.
+*/
+
+/*!
+ \fn void QTabWidget::setTabToolTip(QWidget * widget, const QString & tip)
+
+ Use setTabToolTip(tabWidget->indexOf(widget), tip) instead.
+*/
+
+/*!
+ \fn QString QTabWidget::tabToolTip(QWidget * widget) const
+
+ Use tabToolTip(tabWidget->indexOf(widget)) instead.
+*/
+
+/*!
+ \fn QWidget * QTabWidget::currentPage() const
+
+ Use currentWidget() instead.
+*/
+
+/*!
+ \fn QWidget *QTabWidget::page(int index) const
+
+ Use widget() instead.
+*/
+
+/*!
+ \fn QString QTabWidget::label(int index) const
+
+ Use tabText() instead.
+*/
+
+/*!
+ \fn int QTabWidget::currentPageIndex() const
+
+ Use currentIndex() instead.
+*/
+
+/*!
+ \fn int QTabWidget::margin() const
+
+ This function is kept only to make old code compile.
+ This functionality is no longer supported by QTabWidget.
+
+ \sa contentsRect(), setContentsMargins()
+*/
+
+/*!
+ \fn void QTabWidget::setMargin(int margin)
+
+ This function is kept only to make old code compile.
+ This functionality is no longer supported by QTabWidget.
+
+ \sa contentsRect(), setContentsMargins()
+*/
+
+/*!
+ \fn void QTabWidget::setCurrentPage(int index)
+
+ Use setCurrentIndex() instead.
+*/
+
+/*!
+ \fn void QTabWidget::showPage(QWidget *widget)
+
+ Use setCurrentIndex(indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QTabWidget::removePage(QWidget *widget)
+
+ Use removeTab(indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QTabWidget::currentChanged(QWidget *widget)
+
+ Use currentChanged(int) instead.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qtabwidget.cpp"
+
+#endif //QT_NO_TABWIDGET
diff --git a/src/widgets/widgets/qtabwidget.h b/src/widgets/widgets/qtabwidget.h
new file mode 100644
index 0000000000..899b7a5dba
--- /dev/null
+++ b/src/widgets/widgets/qtabwidget.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTABWIDGET_H
+#define QTABWIDGET_H
+
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qicon.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TABWIDGET
+
+class QTabBar;
+class QTabWidgetPrivate;
+class QStyleOptionTabWidgetFrame;
+
+class Q_WIDGETS_EXPORT QTabWidget : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS(TabPosition TabShape)
+ Q_PROPERTY(TabPosition tabPosition READ tabPosition WRITE setTabPosition)
+ Q_PROPERTY(TabShape tabShape READ tabShape WRITE setTabShape)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+ Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode)
+ Q_PROPERTY(bool usesScrollButtons READ usesScrollButtons WRITE setUsesScrollButtons)
+ Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
+ Q_PROPERTY(bool tabsClosable READ tabsClosable WRITE setTabsClosable)
+ Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
+
+public:
+ explicit QTabWidget(QWidget *parent = 0);
+ ~QTabWidget();
+
+ int addTab(QWidget *widget, const QString &);
+ int addTab(QWidget *widget, const QIcon& icon, const QString &label);
+
+ int insertTab(int index, QWidget *widget, const QString &);
+ int insertTab(int index, QWidget *widget, const QIcon& icon, const QString &label);
+
+ void removeTab(int index);
+
+ bool isTabEnabled(int index) const;
+ void setTabEnabled(int index, bool);
+
+ QString tabText(int index) const;
+ void setTabText(int index, const QString &);
+
+ QIcon tabIcon(int index) const;
+ void setTabIcon(int index, const QIcon & icon);
+
+#ifndef QT_NO_TOOLTIP
+ void setTabToolTip(int index, const QString & tip);
+ QString tabToolTip(int index) const;
+#endif
+
+#ifndef QT_NO_WHATSTHIS
+ void setTabWhatsThis(int index, const QString &text);
+ QString tabWhatsThis(int index) const;
+#endif
+
+ int currentIndex() const;
+ QWidget *currentWidget() const;
+ QWidget *widget(int index) const;
+ int indexOf(QWidget *widget) const;
+ int count() const;
+
+ enum TabPosition { North, South, West, East
+#if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ , Top = North, Bottom = South
+#endif
+ };
+ TabPosition tabPosition() const;
+ void setTabPosition(TabPosition);
+
+ bool tabsClosable() const;
+ void setTabsClosable(bool closeable);
+
+ bool isMovable() const;
+ void setMovable(bool movable);
+
+ enum TabShape { Rounded, Triangular };
+ TabShape tabShape() const;
+ void setTabShape(TabShape s);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ int heightForWidth(int width) const;
+
+ void setCornerWidget(QWidget * w, Qt::Corner corner = Qt::TopRightCorner);
+ QWidget * cornerWidget(Qt::Corner corner = Qt::TopRightCorner) const;
+
+ Qt::TextElideMode elideMode() const;
+ void setElideMode(Qt::TextElideMode);
+
+ QSize iconSize() const;
+ void setIconSize(const QSize &size);
+
+ bool usesScrollButtons() const;
+ void setUsesScrollButtons(bool useButtons);
+
+ bool documentMode() const;
+ void setDocumentMode(bool set);
+
+ void clear();
+
+ QTabBar* tabBar() const;
+
+public Q_SLOTS:
+ void setCurrentIndex(int index);
+ void setCurrentWidget(QWidget *widget);
+
+Q_SIGNALS:
+ void currentChanged(int index);
+ void tabCloseRequested(int index);
+
+protected:
+ virtual void tabInserted(int index);
+ virtual void tabRemoved(int index);
+
+ void showEvent(QShowEvent *);
+ void resizeEvent(QResizeEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void paintEvent(QPaintEvent *);
+ void setTabBar(QTabBar *);
+ void changeEvent(QEvent *);
+ bool event(QEvent *);
+ void initStyleOption(QStyleOptionTabWidgetFrame *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QTabWidget(QWidget *parent, const char *name, Qt::WindowFlags f = 0);
+
+ inline QT3_SUPPORT void insertTab(QWidget * w, const QString &s, int index = -1) { insertTab(index, w, s); }
+ inline QT3_SUPPORT void insertTab(QWidget *child, const QIcon& icon,
+ const QString &label, int index = -1) { insertTab(index, child, icon, label); }
+
+ inline QT3_SUPPORT void changeTab(QWidget *w, const QString &s) {setTabText(indexOf(w), s); }
+ inline QT3_SUPPORT void changeTab(QWidget *w, const QIcon& icon,
+ const QString &label) { int idx = indexOf(w); setTabText(idx, label); setTabIcon(idx, icon); }
+
+ inline QT3_SUPPORT bool isTabEnabled( QWidget *w) const {return isTabEnabled(indexOf(w)); }
+ inline QT3_SUPPORT void setTabEnabled(QWidget *w, bool b) { setTabEnabled(indexOf(w), b); }
+
+ inline QT3_SUPPORT QString tabLabel(QWidget *w) const {return tabText(indexOf(w)); }
+ inline QT3_SUPPORT void setTabLabel(QWidget *w, const QString &l) { setTabText(indexOf(w), l); }
+
+ inline QT3_SUPPORT QIcon tabIconSet(QWidget * w) const {return tabIcon(indexOf(w)); }
+ inline QT3_SUPPORT void setTabIconSet(QWidget * w, const QIcon & icon) { setTabIcon(indexOf(w), icon); }
+
+ inline QT3_SUPPORT void removeTabToolTip(QWidget * w) {
+#ifndef QT_NO_TOOLTIP
+ setTabToolTip(indexOf(w), QString());
+#else
+ Q_UNUSED(w);
+#endif
+ }
+ inline QT3_SUPPORT void setTabToolTip(QWidget * w, const QString & tip) {
+#ifndef QT_NO_TOOLTIP
+ setTabToolTip(indexOf(w), tip);
+#else
+ Q_UNUSED(w);
+ Q_UNUSED(tip);
+#endif
+ }
+
+ inline QT3_SUPPORT QString tabToolTip(QWidget * w) const {
+#ifndef QT_NO_TOOLTIP
+ return tabToolTip(indexOf(w));
+#else
+ Q_UNUSED(w);
+ return QString();
+#endif
+ }
+
+ inline QT3_SUPPORT QWidget * currentPage() const { return currentWidget(); }
+ inline QT3_SUPPORT QWidget *page(int index) const { return widget(index); }
+ inline QT3_SUPPORT QString label(int index) const { return tabText(index); }
+ inline QT3_SUPPORT int currentPageIndex() const { return currentIndex(); }
+
+ inline QT3_SUPPORT int margin() const { return 0; }
+ inline QT3_SUPPORT void setMargin(int) {}
+
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void setCurrentPage(int index) { setCurrentIndex(index); }
+ inline QT_MOC_COMPAT void showPage(QWidget *w) { setCurrentIndex(indexOf(w)); }
+ inline QT_MOC_COMPAT void removePage(QWidget *w) { removeTab(indexOf(w)); }
+
+Q_SIGNALS:
+ QT_MOC_COMPAT void currentChanged(QWidget *);
+ QT_MOC_COMPAT void selected(const QString&);
+#endif // QT3_SUPPORT
+
+private:
+ Q_DECLARE_PRIVATE(QTabWidget)
+ Q_DISABLE_COPY(QTabWidget)
+ Q_PRIVATE_SLOT(d_func(), void _q_showTab(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_removeTab(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_tabMoved(int, int))
+ void setUpLayout(bool = false);
+ friend class Q3TabDialog;
+};
+
+#endif // QT_NO_TABWIDGET
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTABWIDGET_H
diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp
new file mode 100644
index 0000000000..cd8fa117b7
--- /dev/null
+++ b/src/widgets/widgets/qtextbrowser.cpp
@@ -0,0 +1,1275 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtextbrowser.h"
+#include "qtextedit_p.h"
+
+#ifndef QT_NO_TEXTBROWSER
+
+#include <qstack.h>
+#include <qapplication.h>
+#include <qevent.h>
+#include <qdesktopwidget.h>
+#include <qdebug.h>
+#include <qabstracttextdocumentlayout.h>
+#include "private/qtextdocumentlayout_p.h"
+#include <qtextcodec.h>
+#include <qpainter.h>
+#include <qdir.h>
+#include <qwhatsthis.h>
+#include <qtextobject.h>
+#include <qdesktopservices.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextBrowserPrivate : public QTextEditPrivate
+{
+ Q_DECLARE_PUBLIC(QTextBrowser)
+public:
+ inline QTextBrowserPrivate()
+ : textOrSourceChanged(false), forceLoadOnSourceChange(false), openExternalLinks(false),
+ openLinks(true)
+#ifdef QT_KEYPAD_NAVIGATION
+ , lastKeypadScrollValue(-1)
+#endif
+ {}
+
+ void init();
+
+ struct HistoryEntry {
+ inline HistoryEntry()
+ : hpos(0), vpos(0), focusIndicatorPosition(-1),
+ focusIndicatorAnchor(-1) {}
+ QUrl url;
+ QString title;
+ int hpos;
+ int vpos;
+ int focusIndicatorPosition, focusIndicatorAnchor;
+ };
+
+ HistoryEntry history(int i) const
+ {
+ if (i <= 0)
+ if (-i < stack.count())
+ return stack[stack.count()+i-1];
+ else
+ return HistoryEntry();
+ else
+ if (i <= forwardStack.count())
+ return forwardStack[forwardStack.count()-i];
+ else
+ return HistoryEntry();
+ }
+
+
+ HistoryEntry createHistoryEntry() const;
+ void restoreHistoryEntry(const HistoryEntry entry);
+
+ QStack<HistoryEntry> stack;
+ QStack<HistoryEntry> forwardStack;
+ QUrl home;
+ QUrl currentURL;
+
+ QStringList searchPaths;
+
+ /*flag necessary to give the linkClicked() signal some meaningful
+ semantics when somebody connected to it calls setText() or
+ setSource() */
+ bool textOrSourceChanged;
+ bool forceLoadOnSourceChange;
+
+ bool openExternalLinks;
+ bool openLinks;
+
+#ifndef QT_NO_CURSOR
+ QCursor oldCursor;
+#endif
+
+ QString findFile(const QUrl &name) const;
+
+ inline void _q_documentModified()
+ {
+ textOrSourceChanged = true;
+ forceLoadOnSourceChange = !currentURL.path().isEmpty();
+ }
+
+ void _q_activateAnchor(const QString &href);
+ void _q_highlightLink(const QString &href);
+
+ void setSource(const QUrl &url);
+
+ // re-imlemented from QTextEditPrivate
+ virtual QUrl resolveUrl(const QUrl &url) const;
+ inline QUrl resolveUrl(const QString &url) const
+ { return resolveUrl(QUrl::fromEncoded(url.toUtf8())); }
+
+#ifdef QT_KEYPAD_NAVIGATION
+ void keypadMove(bool next);
+ QTextCursor prevFocus;
+ int lastKeypadScrollValue;
+#endif
+};
+
+QString QTextBrowserPrivate::findFile(const QUrl &name) const
+{
+ QString fileName;
+ if (name.scheme() == QLatin1String("qrc"))
+ fileName = QLatin1String(":/") + name.path();
+ else
+ fileName = name.toLocalFile();
+
+ if (QFileInfo(fileName).isAbsolute())
+ return fileName;
+
+ foreach (QString path, searchPaths) {
+ if (!path.endsWith(QLatin1Char('/')))
+ path.append(QLatin1Char('/'));
+ path.append(fileName);
+ if (QFileInfo(path).isReadable())
+ return path;
+ }
+
+ return fileName;
+}
+
+QUrl QTextBrowserPrivate::resolveUrl(const QUrl &url) const
+{
+ if (!url.isRelative())
+ return url;
+
+ // For the second case QUrl can merge "#someanchor" with "foo.html"
+ // correctly to "foo.html#someanchor"
+ if (!(currentURL.isRelative()
+ || (currentURL.scheme() == QLatin1String("file")
+ && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
+ || (url.hasFragment() && url.path().isEmpty())) {
+ return currentURL.resolved(url);
+ }
+
+ // this is our last resort when current url and new url are both relative
+ // we try to resolve against the current working directory in the local
+ // file system.
+ QFileInfo fi(currentURL.toLocalFile());
+ if (fi.exists()) {
+ return QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(url);
+ }
+
+ return url;
+}
+
+void QTextBrowserPrivate::_q_activateAnchor(const QString &href)
+{
+ if (href.isEmpty())
+ return;
+ Q_Q(QTextBrowser);
+
+#ifndef QT_NO_CURSOR
+ viewport->setCursor(oldCursor);
+#endif
+
+ const QUrl url = resolveUrl(href);
+
+ if (!openLinks) {
+ emit q->anchorClicked(url);
+ return;
+ }
+
+ textOrSourceChanged = false;
+
+#ifndef QT_NO_DESKTOPSERVICES
+ if ((openExternalLinks
+ && url.scheme() != QLatin1String("file")
+ && url.scheme() != QLatin1String("qrc")
+ && !url.isRelative())
+ || (url.isRelative() && !currentURL.isRelative()
+ && currentURL.scheme() != QLatin1String("file")
+ && currentURL.scheme() != QLatin1String("qrc"))) {
+ QDesktopServices::openUrl(url);
+ return;
+ }
+#endif
+
+ emit q->anchorClicked(url);
+
+ if (textOrSourceChanged)
+ return;
+
+ q->setSource(url);
+}
+
+void QTextBrowserPrivate::_q_highlightLink(const QString &anchor)
+{
+ Q_Q(QTextBrowser);
+ if (anchor.isEmpty()) {
+#ifndef QT_NO_CURSOR
+ if (viewport->cursor().shape() != Qt::PointingHandCursor)
+ oldCursor = viewport->cursor();
+ viewport->setCursor(oldCursor);
+#endif
+ emit q->highlighted(QUrl());
+ emit q->highlighted(QString());
+ } else {
+#ifndef QT_NO_CURSOR
+ viewport->setCursor(Qt::PointingHandCursor);
+#endif
+
+ const QUrl url = resolveUrl(anchor);
+ emit q->highlighted(url);
+ // convenience to ease connecting to QStatusBar::showMessage(const QString &)
+ emit q->highlighted(url.toString());
+ }
+}
+
+void QTextBrowserPrivate::setSource(const QUrl &url)
+{
+ Q_Q(QTextBrowser);
+#ifndef QT_NO_CURSOR
+ if (q->isVisible())
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+#endif
+ textOrSourceChanged = true;
+
+ QString txt;
+
+ bool doSetText = false;
+
+ QUrl currentUrlWithoutFragment = currentURL;
+ currentUrlWithoutFragment.setFragment(QString());
+ QUrl newUrlWithoutFragment = currentURL.resolved(url);
+ newUrlWithoutFragment.setFragment(QString());
+
+ if (url.isValid()
+ && (newUrlWithoutFragment != currentUrlWithoutFragment || forceLoadOnSourceChange)) {
+ QVariant data = q->loadResource(QTextDocument::HtmlResource, resolveUrl(url));
+ if (data.type() == QVariant::String) {
+ txt = data.toString();
+ } else if (data.type() == QVariant::ByteArray) {
+#ifndef QT_NO_TEXTCODEC
+ QByteArray ba = data.toByteArray();
+ QTextCodec *codec = Qt::codecForHtml(ba);
+ txt = codec->toUnicode(ba);
+#else
+ txt = data.toString();
+#endif
+ }
+ if (txt.isEmpty())
+ qWarning("QTextBrowser: No document for %s", url.toString().toLatin1().constData());
+
+ if (q->isVisible()) {
+ QString firstTag = txt.left(txt.indexOf(QLatin1Char('>')) + 1);
+ if (firstTag.startsWith(QLatin1String("<qt")) && firstTag.contains(QLatin1String("type")) && firstTag.contains(QLatin1String("detail"))) {
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::showText(QCursor::pos(), txt, q);
+#endif
+ return;
+ }
+ }
+
+ currentURL = resolveUrl(url);
+ doSetText = true;
+ }
+
+ if (!home.isValid())
+ home = url;
+
+ if (doSetText) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ q->QTextEdit::setHtml(txt);
+ q->document()->setMetaInformation(QTextDocument::DocumentUrl, currentURL.toString());
+#else
+ q->QTextEdit::setPlainText(txt);
+#endif
+
+#ifdef QT_KEYPAD_NAVIGATION
+ prevFocus.movePosition(QTextCursor::Start);
+#endif
+ }
+
+ forceLoadOnSourceChange = false;
+
+ if (!url.fragment().isEmpty()) {
+ q->scrollToAnchor(url.fragment());
+ } else {
+ hbar->setValue(0);
+ vbar->setValue(0);
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ lastKeypadScrollValue = vbar->value();
+ emit q->highlighted(QUrl());
+ emit q->highlighted(QString());
+#endif
+
+#ifndef QT_NO_CURSOR
+ if (q->isVisible())
+ QApplication::restoreOverrideCursor();
+#endif
+ emit q->sourceChanged(url);
+}
+
+#ifdef QT_KEYPAD_NAVIGATION
+void QTextBrowserPrivate::keypadMove(bool next)
+{
+ Q_Q(QTextBrowser);
+
+ const int height = viewport->height();
+ const int overlap = qBound(20, height / 5, 40); // XXX arbitrary, but a good balance
+ const int visibleLinkAmount = overlap; // consistent, but maybe not the best choice (?)
+ int yOffset = vbar->value();
+ int scrollYOffset = qBound(0, next ? yOffset + height - overlap : yOffset - height + overlap, vbar->maximum());
+
+ bool foundNextAnchor = false;
+ bool focusIt = false;
+ int focusedPos = -1;
+
+ QTextCursor anchorToFocus;
+
+ QRectF viewRect = QRectF(0, yOffset, control->size().width(), height);
+ QRectF newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
+ QRectF bothViewRects = viewRect.united(newViewRect);
+
+ // If we don't have a previous anchor, pretend that we had the first/last character
+ // on the screen selected.
+ if (prevFocus.isNull()) {
+ if (next)
+ prevFocus = control->cursorForPosition(QPointF(0, yOffset));
+ else
+ prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
+ }
+
+ // First, check to see if someone has moved the scroll bars independently
+ if (lastKeypadScrollValue != yOffset) {
+ // Someone (user or programmatically) has moved us, so we might
+ // need to start looking from the current position instead of prevFocus
+
+ bool findOnScreen = true;
+
+ // If prevFocus is on screen at all, we just use it.
+ if (prevFocus.hasSelection()) {
+ QRectF prevRect = control->selectionRect(prevFocus);
+ if (viewRect.intersects(prevRect))
+ findOnScreen = false;
+ }
+
+ // Otherwise, we find a new anchor that's on screen.
+ // Basically, create a cursor with the last/first character
+ // on screen
+ if (findOnScreen) {
+ if (next)
+ prevFocus = control->cursorForPosition(QPointF(0, yOffset));
+ else
+ prevFocus = control->cursorForPosition(QPointF(control->size().width(), yOffset + height));
+ }
+ foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
+ } else if (prevFocus.hasSelection()) {
+ // Check the pathological case that the current anchor is higher
+ // than the screen, and just scroll through it in that case
+ QRectF prevRect = control->selectionRect(prevFocus);
+ if ((next && prevRect.bottom() > (yOffset + height)) ||
+ (!next && prevRect.top() < yOffset)) {
+ anchorToFocus = prevFocus;
+ focusedPos = scrollYOffset;
+ focusIt = true;
+ } else {
+ // This is the "normal" case - no scroll bar adjustments, no large anchors,
+ // and no wrapping.
+ foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
+ }
+ }
+
+ // If not found yet, see if we need to wrap
+ if (!focusIt && !foundNextAnchor) {
+ if (next) {
+ if (yOffset == vbar->maximum()) {
+ prevFocus.movePosition(QTextCursor::Start);
+ yOffset = scrollYOffset = 0;
+
+ // Refresh the rectangles
+ viewRect = QRectF(0, yOffset, control->size().width(), height);
+ newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
+ bothViewRects = viewRect.united(newViewRect);
+ }
+ } else {
+ if (yOffset == 0) {
+ prevFocus.movePosition(QTextCursor::End);
+ yOffset = scrollYOffset = vbar->maximum();
+
+ // Refresh the rectangles
+ viewRect = QRectF(0, yOffset, control->size().width(), height);
+ newViewRect = QRectF(0, scrollYOffset, control->size().width(), height);
+ bothViewRects = viewRect.united(newViewRect);
+ }
+ }
+
+ // Try looking now
+ foundNextAnchor = control->findNextPrevAnchor(prevFocus, next, anchorToFocus);
+ }
+
+ // If we did actually find an anchor to use...
+ if (foundNextAnchor) {
+ QRectF desiredRect = control->selectionRect(anchorToFocus);
+
+ // XXX This is an arbitrary heuristic
+ // Decide to focus an anchor if it will be at least be
+ // in the middle region of the screen after a scroll.
+ // This can result in partial anchors with focus, but
+ // insisting on links being completely visible before
+ // selecting them causes disparities between links that
+ // take up 90% of the screen height and those that take
+ // up e.g. 110%
+ // Obviously if a link is entirely visible, we still
+ // focus it.
+ if(bothViewRects.contains(desiredRect)
+ || bothViewRects.adjusted(0, visibleLinkAmount, 0, -visibleLinkAmount).intersects(desiredRect)) {
+ focusIt = true;
+
+ // We aim to put the new link in the middle of the screen,
+ // unless the link is larger than the screen (we just move to
+ // display the first page of the link)
+ if (desiredRect.height() > height) {
+ if (next)
+ focusedPos = (int) desiredRect.top();
+ else
+ focusedPos = (int) desiredRect.bottom() - height;
+ } else
+ focusedPos = (int) ((desiredRect.top() + desiredRect.bottom()) / 2 - (height / 2));
+
+ // and clamp it to make sure we don't skip content.
+ if (next)
+ focusedPos = qBound(yOffset, focusedPos, scrollYOffset);
+ else
+ focusedPos = qBound(scrollYOffset, focusedPos, yOffset);
+ }
+ }
+
+ // If we didn't get a new anchor, check if the old one is still on screen when we scroll
+ // Note that big (larger than screen height) anchors also have some handling at the
+ // start of this function.
+ if (!focusIt && prevFocus.hasSelection()) {
+ QRectF desiredRect = control->selectionRect(prevFocus);
+ // XXX this may be better off also using the visibleLinkAmount value
+ if(newViewRect.intersects(desiredRect)) {
+ focusedPos = scrollYOffset;
+ focusIt = true;
+ anchorToFocus = prevFocus;
+ }
+ }
+
+ // setTextCursor ensures that the cursor is visible. save & restore
+ // the scroll bar values therefore
+ const int savedXOffset = hbar->value();
+
+ // Now actually process our decision
+ if (focusIt && control->setFocusToAnchor(anchorToFocus)) {
+ // Save the focus for next time
+ prevFocus = control->textCursor();
+
+ // Scroll
+ vbar->setValue(focusedPos);
+ lastKeypadScrollValue = focusedPos;
+ hbar->setValue(savedXOffset);
+
+ // Ensure that the new selection is highlighted.
+ const QString href = control->anchorAtCursor();
+ QUrl url = resolveUrl(href);
+ emit q->highlighted(url);
+ emit q->highlighted(url.toString());
+ } else {
+ // Scroll
+ vbar->setValue(scrollYOffset);
+ lastKeypadScrollValue = scrollYOffset;
+
+ // now make sure we don't have a focused anchor
+ QTextCursor cursor = control->textCursor();
+ cursor.clearSelection();
+
+ control->setTextCursor(cursor);
+
+ hbar->setValue(savedXOffset);
+ vbar->setValue(scrollYOffset);
+
+ emit q->highlighted(QUrl());
+ emit q->highlighted(QString());
+ }
+}
+#endif
+
+QTextBrowserPrivate::HistoryEntry QTextBrowserPrivate::createHistoryEntry() const
+{
+ HistoryEntry entry;
+ entry.url = q_func()->source();
+ entry.title = q_func()->documentTitle();
+ entry.hpos = hbar->value();
+ entry.vpos = vbar->value();
+
+ const QTextCursor cursor = control->textCursor();
+ if (control->cursorIsFocusIndicator()
+ && cursor.hasSelection()) {
+
+ entry.focusIndicatorPosition = cursor.position();
+ entry.focusIndicatorAnchor = cursor.anchor();
+ }
+ return entry;
+}
+
+void QTextBrowserPrivate::restoreHistoryEntry(const HistoryEntry entry)
+{
+ setSource(entry.url);
+ hbar->setValue(entry.hpos);
+ vbar->setValue(entry.vpos);
+ if (entry.focusIndicatorAnchor != -1 && entry.focusIndicatorPosition != -1) {
+ QTextCursor cursor(control->document());
+ cursor.setPosition(entry.focusIndicatorAnchor);
+ cursor.setPosition(entry.focusIndicatorPosition, QTextCursor::KeepAnchor);
+ control->setTextCursor(cursor);
+ control->setCursorIsFocusIndicator(true);
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ lastKeypadScrollValue = vbar->value();
+ prevFocus = control->textCursor();
+
+ Q_Q(QTextBrowser);
+ const QString href = prevFocus.charFormat().anchorHref();
+ QUrl url = resolveUrl(href);
+ emit q->highlighted(url);
+ emit q->highlighted(url.toString());
+#endif
+}
+
+/*!
+ \class QTextBrowser
+ \brief The QTextBrowser class provides a rich text browser with hypertext navigation.
+
+ \ingroup richtext-processing
+
+ This class extends QTextEdit (in read-only mode), adding some navigation
+ functionality so that users can follow links in hypertext documents.
+
+ If you want to provide your users with an editable rich text editor,
+ use QTextEdit. If you want a text browser without hypertext navigation
+ use QTextEdit, and use QTextEdit::setReadOnly() to disable
+ editing. If you just need to display a small piece of rich text
+ use QLabel.
+
+ \section1 Document Source and Contents
+
+ The contents of QTextEdit are set with setHtml() or setPlainText(),
+ but QTextBrowser also implements the setSource() function, making it
+ possible to use a named document as the source text. The name is looked
+ up in a list of search paths and in the directory of the current document
+ factory.
+
+ If a document name ends with
+ an anchor (for example, "\c #anchor"), the text browser automatically
+ scrolls to that position (using scrollToAnchor()). When the user clicks
+ on a hyperlink, the browser will call setSource() itself with the link's
+ \c href value as argument. You can track the current source by connecting
+ to the sourceChanged() signal.
+
+ \section1 Navigation
+
+ QTextBrowser provides backward() and forward() slots which you can
+ use to implement Back and Forward buttons. The home() slot sets
+ the text to the very first document displayed. The anchorClicked()
+ signal is emitted when the user clicks an anchor. To override the
+ default navigation behavior of the browser, call the setSource()
+ function to supply new document text in a slot connected to this
+ signal.
+
+ If you want to load documents stored in the Qt resource system use
+ \c{qrc} as the scheme in the URL to load. For example, for the document
+ resource path \c{:/docs/index.html} use \c{qrc:/docs/index.html} as
+ the URL with setSource().
+
+ \sa QTextEdit, QTextDocument
+*/
+
+/*!
+ \property QTextBrowser::modified
+ \brief whether the contents of the text browser have been modified
+*/
+
+/*!
+ \property QTextBrowser::readOnly
+ \brief whether the text browser is read-only
+
+ By default, this property is true.
+*/
+
+/*!
+ \property QTextBrowser::undoRedoEnabled
+ \brief whether the text browser supports undo/redo operations
+
+ By default, this property is false.
+*/
+
+void QTextBrowserPrivate::init()
+{
+ Q_Q(QTextBrowser);
+ control->setTextInteractionFlags(Qt::TextBrowserInteraction);
+#ifndef QT_NO_CURSOR
+ viewport->setCursor(oldCursor);
+#endif
+ q->setUndoRedoEnabled(false);
+ viewport->setMouseTracking(true);
+ QObject::connect(q->document(), SIGNAL(contentsChanged()), q, SLOT(_q_documentModified()));
+ QObject::connect(control, SIGNAL(linkActivated(QString)),
+ q, SLOT(_q_activateAnchor(QString)));
+ QObject::connect(control, SIGNAL(linkHovered(QString)),
+ q, SLOT(_q_highlightLink(QString)));
+}
+
+/*!
+ Constructs an empty QTextBrowser with parent \a parent.
+*/
+QTextBrowser::QTextBrowser(QWidget *parent)
+ : QTextEdit(*new QTextBrowserPrivate, parent)
+{
+ Q_D(QTextBrowser);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QTextBrowser::QTextBrowser(QWidget *parent, const char *name)
+ : QTextEdit(*new QTextBrowserPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ Q_D(QTextBrowser);
+ d->init();
+}
+#endif
+
+/*!
+ \internal
+*/
+QTextBrowser::~QTextBrowser()
+{
+}
+
+/*!
+ \property QTextBrowser::source
+ \brief the name of the displayed document.
+
+ This is a an invalid url if no document is displayed or if the
+ source is unknown.
+
+ When setting this property QTextBrowser tries to find a document
+ with the specified name in the paths of the searchPaths property
+ and directory of the current source, unless the value is an absolute
+ file path. It also checks for optional anchors and scrolls the document
+ accordingly
+
+ If the first tag in the document is \c{<qt type=detail>}, the
+ document is displayed as a popup rather than as new document in
+ the browser window itself. Otherwise, the document is displayed
+ normally in the text browser with the text set to the contents of
+ the named document with setHtml().
+
+ By default, this property contains an empty URL.
+*/
+QUrl QTextBrowser::source() const
+{
+ Q_D(const QTextBrowser);
+ if (d->stack.isEmpty())
+ return QUrl();
+ else
+ return d->stack.top().url;
+}
+
+/*!
+ \property QTextBrowser::searchPaths
+ \brief the search paths used by the text browser to find supporting
+ content
+
+ QTextBrowser uses this list to locate images and documents.
+
+ By default, this property contains an empty string list.
+*/
+
+QStringList QTextBrowser::searchPaths() const
+{
+ Q_D(const QTextBrowser);
+ return d->searchPaths;
+}
+
+void QTextBrowser::setSearchPaths(const QStringList &paths)
+{
+ Q_D(QTextBrowser);
+ d->searchPaths = paths;
+}
+
+/*!
+ Reloads the current set source.
+*/
+void QTextBrowser::reload()
+{
+ Q_D(QTextBrowser);
+ QUrl s = d->currentURL;
+ d->currentURL = QUrl();
+ setSource(s);
+}
+
+void QTextBrowser::setSource(const QUrl &url)
+{
+ Q_D(QTextBrowser);
+
+ const QTextBrowserPrivate::HistoryEntry historyEntry = d->createHistoryEntry();
+
+ d->setSource(url);
+
+ if (!url.isValid())
+ return;
+
+ // the same url you are already watching?
+ if (!d->stack.isEmpty() && d->stack.top().url == url)
+ return;
+
+ if (!d->stack.isEmpty())
+ d->stack.top() = historyEntry;
+
+ QTextBrowserPrivate::HistoryEntry entry;
+ entry.url = url;
+ entry.title = documentTitle();
+ entry.hpos = 0;
+ entry.vpos = 0;
+ d->stack.push(entry);
+
+ emit backwardAvailable(d->stack.count() > 1);
+
+ if (!d->forwardStack.isEmpty() && d->forwardStack.top().url == url) {
+ d->forwardStack.pop();
+ emit forwardAvailable(d->forwardStack.count() > 0);
+ } else {
+ d->forwardStack.clear();
+ emit forwardAvailable(false);
+ }
+
+ emit historyChanged();
+}
+
+/*!
+ \fn void QTextBrowser::backwardAvailable(bool available)
+
+ This signal is emitted when the availability of backward()
+ changes. \a available is false when the user is at home();
+ otherwise it is true.
+*/
+
+/*!
+ \fn void QTextBrowser::forwardAvailable(bool available)
+
+ This signal is emitted when the availability of forward() changes.
+ \a available is true after the user navigates backward() and false
+ when the user navigates or goes forward().
+*/
+
+/*!
+ \fn void QTextBrowser::historyChanged()
+ \since 4.4
+
+ This signal is emitted when the history changes.
+
+ \sa historyTitle(), historyUrl()
+*/
+
+/*!
+ \fn void QTextBrowser::sourceChanged(const QUrl &src)
+
+ This signal is emitted when the source has changed, \a src
+ being the new source.
+
+ Source changes happen both programmatically when calling
+ setSource(), forward(), backword() or home() or when the user
+ clicks on links or presses the equivalent key sequences.
+*/
+
+/*! \fn void QTextBrowser::highlighted(const QUrl &link)
+
+ This signal is emitted when the user has selected but not
+ activated an anchor in the document. The URL referred to by the
+ anchor is passed in \a link.
+*/
+
+/*! \fn void QTextBrowser::highlighted(const QString &link)
+ \overload
+
+ Convenience signal that allows connecting to a slot
+ that takes just a QString, like for example QStatusBar's
+ message().
+*/
+
+
+/*!
+ \fn void QTextBrowser::anchorClicked(const QUrl &link)
+
+ This signal is emitted when the user clicks an anchor. The
+ URL referred to by the anchor is passed in \a link.
+
+ Note that the browser will automatically handle navigation to the
+ location specified by \a link unless the openLinks property
+ is set to false or you call setSource() in a slot connected.
+ This mechanism is used to override the default navigation features of the browser.
+*/
+
+/*!
+ Changes the document displayed to the previous document in the
+ list of documents built by navigating links. Does nothing if there
+ is no previous document.
+
+ \sa forward(), backwardAvailable()
+*/
+void QTextBrowser::backward()
+{
+ Q_D(QTextBrowser);
+ if (d->stack.count() <= 1)
+ return;
+
+ // Update the history entry
+ d->forwardStack.push(d->createHistoryEntry());
+ d->stack.pop(); // throw away the old version of the current entry
+ d->restoreHistoryEntry(d->stack.top()); // previous entry
+ emit backwardAvailable(d->stack.count() > 1);
+ emit forwardAvailable(true);
+ emit historyChanged();
+}
+
+/*!
+ Changes the document displayed to the next document in the list of
+ documents built by navigating links. Does nothing if there is no
+ next document.
+
+ \sa backward(), forwardAvailable()
+*/
+void QTextBrowser::forward()
+{
+ Q_D(QTextBrowser);
+ if (d->forwardStack.isEmpty())
+ return;
+ if (!d->stack.isEmpty()) {
+ // Update the history entry
+ d->stack.top() = d->createHistoryEntry();
+ }
+ d->stack.push(d->forwardStack.pop());
+ d->restoreHistoryEntry(d->stack.top());
+ emit backwardAvailable(true);
+ emit forwardAvailable(!d->forwardStack.isEmpty());
+ emit historyChanged();
+}
+
+/*!
+ Changes the document displayed to be the first document from
+ the history.
+*/
+void QTextBrowser::home()
+{
+ Q_D(QTextBrowser);
+ if (d->home.isValid())
+ setSource(d->home);
+}
+
+/*!
+ The event \a ev is used to provide the following keyboard shortcuts:
+ \table
+ \header \i Keypress \i Action
+ \row \i Alt+Left Arrow \i \l backward()
+ \row \i Alt+Right Arrow \i \l forward()
+ \row \i Alt+Up Arrow \i \l home()
+ \endtable
+*/
+void QTextBrowser::keyPressEvent(QKeyEvent *ev)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_D(QTextBrowser);
+ switch (ev->key()) {
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus()) {
+ setEditFocus(true);
+ return;
+ } else {
+ QTextCursor cursor = d->control->textCursor();
+ QTextCharFormat charFmt = cursor.charFormat();
+ if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
+ ev->accept();
+ return;
+ }
+ }
+ }
+ break;
+ case Qt::Key_Back:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (hasEditFocus()) {
+ setEditFocus(false);
+ ev->accept();
+ return;
+ }
+ }
+ QTextEdit::keyPressEvent(ev);
+ return;
+ default:
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
+ ev->ignore();
+ return;
+ }
+ }
+#endif
+
+ if (ev->modifiers() & Qt::AltModifier) {
+ switch (ev->key()) {
+ case Qt::Key_Right:
+ forward();
+ ev->accept();
+ return;
+ case Qt::Key_Left:
+ backward();
+ ev->accept();
+ return;
+ case Qt::Key_Up:
+ home();
+ ev->accept();
+ return;
+ }
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ else {
+ if (ev->key() == Qt::Key_Up) {
+ d->keypadMove(false);
+ return;
+ } else if (ev->key() == Qt::Key_Down) {
+ d->keypadMove(true);
+ return;
+ }
+ }
+#endif
+ QTextEdit::keyPressEvent(ev);
+}
+
+/*!
+ \reimp
+*/
+void QTextBrowser::mouseMoveEvent(QMouseEvent *e)
+{
+ QTextEdit::mouseMoveEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QTextBrowser::mousePressEvent(QMouseEvent *e)
+{
+ QTextEdit::mousePressEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QTextBrowser::mouseReleaseEvent(QMouseEvent *e)
+{
+ QTextEdit::mouseReleaseEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QTextBrowser::focusOutEvent(QFocusEvent *ev)
+{
+#ifndef QT_NO_CURSOR
+ Q_D(QTextBrowser);
+ d->viewport->setCursor((!(d->control->textInteractionFlags() & Qt::TextEditable)) ? d->oldCursor : Qt::IBeamCursor);
+#endif
+ QTextEdit::focusOutEvent(ev);
+}
+
+/*!
+ \reimp
+*/
+bool QTextBrowser::focusNextPrevChild(bool next)
+{
+ Q_D(QTextBrowser);
+ if (d->control->setFocusToNextOrPreviousAnchor(next)) {
+#ifdef QT_KEYPAD_NAVIGATION
+ // Might need to synthesize a highlight event.
+ if (d->prevFocus != d->control->textCursor() && d->control->textCursor().hasSelection()) {
+ const QString href = d->control->anchorAtCursor();
+ QUrl url = d->resolveUrl(href);
+ emit highlighted(url);
+ emit highlighted(url.toString());
+ }
+ d->prevFocus = d->control->textCursor();
+#endif
+ return true;
+ } else {
+#ifdef QT_KEYPAD_NAVIGATION
+ // We assume we have no highlight now.
+ emit highlighted(QUrl());
+ emit highlighted(QString());
+#endif
+ }
+ return QTextEdit::focusNextPrevChild(next);
+}
+
+/*!
+ \reimp
+*/
+void QTextBrowser::paintEvent(QPaintEvent *e)
+{
+ Q_D(QTextBrowser);
+ QPainter p(d->viewport);
+ d->paint(&p, e);
+}
+
+/*!
+ This function is called when the document is loaded and for
+ each image in the document. The \a type indicates the type of resource
+ to be loaded. An invalid QVariant is returned if the resource cannot be
+ loaded.
+
+ The default implementation ignores \a type and tries to locate
+ the resources by interpreting \a name as a file name. If it is
+ not an absolute path it tries to find the file in the paths of
+ the \l searchPaths property and in the same directory as the
+ current source. On success, the result is a QVariant that stores
+ a QByteArray with the contents of the file.
+
+ If you reimplement this function, you can return other QVariant
+ types. The table below shows which variant types are supported
+ depending on the resource type:
+
+ \table
+ \header \i ResourceType \i QVariant::Type
+ \row \i QTextDocument::HtmlResource \i QString or QByteArray
+ \row \i QTextDocument::ImageResource \i QImage, QPixmap or QByteArray
+ \row \i QTextDocument::StyleSheetResource \i QString or QByteArray
+ \endtable
+*/
+QVariant QTextBrowser::loadResource(int /*type*/, const QUrl &name)
+{
+ Q_D(QTextBrowser);
+
+ QByteArray data;
+ QString fileName = d->findFile(d->resolveUrl(name));
+ QFile f(fileName);
+ if (f.open(QFile::ReadOnly)) {
+ data = f.readAll();
+ f.close();
+ } else {
+ return QVariant();
+ }
+
+ return data;
+}
+
+/*!
+ \since 4.2
+
+ Returns true if the text browser can go backward in the document history
+ using backward().
+
+ \sa backwardAvailable(), backward()
+*/
+bool QTextBrowser::isBackwardAvailable() const
+{
+ Q_D(const QTextBrowser);
+ return d->stack.count() > 1;
+}
+
+/*!
+ \since 4.2
+
+ Returns true if the text browser can go forward in the document history
+ using forward().
+
+ \sa forwardAvailable(), forward()
+*/
+bool QTextBrowser::isForwardAvailable() const
+{
+ Q_D(const QTextBrowser);
+ return !d->forwardStack.isEmpty();
+}
+
+/*!
+ \since 4.2
+
+ Clears the history of visited documents and disables the forward and
+ backward navigation.
+
+ \sa backward(), forward()
+*/
+void QTextBrowser::clearHistory()
+{
+ Q_D(QTextBrowser);
+ d->forwardStack.clear();
+ if (!d->stack.isEmpty()) {
+ QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top();
+ d->stack.resize(0);
+ d->stack.push(historyEntry);
+ d->home = historyEntry.url;
+ }
+ emit forwardAvailable(false);
+ emit backwardAvailable(false);
+ emit historyChanged();
+}
+
+/*!
+ Returns the url of the HistoryItem.
+
+ \table
+ \header \i Input \i Return
+ \row \i \a{i} < 0 \i \l backward() history
+ \row \i\a{i} == 0 \i current, see QTextBrowser::source()
+ \row \i \a{i} > 0 \i \l forward() history
+ \endtable
+
+ \since 4.4
+*/
+QUrl QTextBrowser::historyUrl(int i) const
+{
+ Q_D(const QTextBrowser);
+ return d->history(i).url;
+}
+
+/*!
+ Returns the documentTitle() of the HistoryItem.
+
+ \table
+ \header \i Input \i Return
+ \row \i \a{i} < 0 \i \l backward() history
+ \row \i \a{i} == 0 \i current, see QTextBrowser::source()
+ \row \i \a{i} > 0 \i \l forward() history
+ \endtable
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qtextbrowser.cpp 0
+
+ \since 4.4
+*/
+QString QTextBrowser::historyTitle(int i) const
+{
+ Q_D(const QTextBrowser);
+ return d->history(i).title;
+}
+
+
+/*!
+ Returns the number of locations forward in the history.
+
+ \since 4.4
+*/
+int QTextBrowser::forwardHistoryCount() const
+{
+ Q_D(const QTextBrowser);
+ return d->forwardStack.count();
+}
+
+/*!
+ Returns the number of locations backward in the history.
+
+ \since 4.4
+*/
+int QTextBrowser::backwardHistoryCount() const
+{
+ Q_D(const QTextBrowser);
+ return d->stack.count()-1;
+}
+
+/*!
+ \property QTextBrowser::openExternalLinks
+ \since 4.2
+
+ Specifies whether QTextBrowser should automatically open links to external
+ sources using QDesktopServices::openUrl() instead of emitting the
+ anchorClicked signal. Links are considered external if their scheme is
+ neither file or qrc.
+
+ The default value is false.
+*/
+bool QTextBrowser::openExternalLinks() const
+{
+ Q_D(const QTextBrowser);
+ return d->openExternalLinks;
+}
+
+void QTextBrowser::setOpenExternalLinks(bool open)
+{
+ Q_D(QTextBrowser);
+ d->openExternalLinks = open;
+}
+
+/*!
+ \property QTextBrowser::openLinks
+ \since 4.3
+
+ This property specifies whether QTextBrowser should automatically open links the user tries to
+ activate by mouse or keyboard.
+
+ Regardless of the value of this property the anchorClicked signal is always emitted.
+
+ The default value is true.
+*/
+
+bool QTextBrowser::openLinks() const
+{
+ Q_D(const QTextBrowser);
+ return d->openLinks;
+}
+
+void QTextBrowser::setOpenLinks(bool open)
+{
+ Q_D(QTextBrowser);
+ d->openLinks = open;
+}
+
+/*! \reimp */
+bool QTextBrowser::event(QEvent *e)
+{
+ return QTextEdit::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtextbrowser.cpp"
+
+#endif // QT_NO_TEXTBROWSER
diff --git a/src/widgets/widgets/qtextbrowser.h b/src/widgets/widgets/qtextbrowser.h
new file mode 100644
index 0000000000..3f488975ec
--- /dev/null
+++ b/src/widgets/widgets/qtextbrowser.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTBROWSER_H
+#define QTEXTBROWSER_H
+
+#include <QtWidgets/qtextedit.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TEXTBROWSER
+
+class QTextBrowserPrivate;
+
+class Q_WIDGETS_EXPORT QTextBrowser : public QTextEdit
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QUrl source READ source WRITE setSource)
+ Q_OVERRIDE(bool modified SCRIPTABLE false)
+ Q_OVERRIDE(bool readOnly DESIGNABLE false SCRIPTABLE false)
+ Q_OVERRIDE(bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false)
+ Q_PROPERTY(QStringList searchPaths READ searchPaths WRITE setSearchPaths)
+ Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
+ Q_PROPERTY(bool openLinks READ openLinks WRITE setOpenLinks)
+
+public:
+ explicit QTextBrowser(QWidget* parent = 0);
+ virtual ~QTextBrowser();
+
+ QUrl source() const;
+
+ QStringList searchPaths() const;
+ void setSearchPaths(const QStringList &paths);
+
+ virtual QVariant loadResource(int type, const QUrl &name);
+
+ bool isBackwardAvailable() const;
+ bool isForwardAvailable() const;
+ void clearHistory();
+ QString historyTitle(int) const;
+ QUrl historyUrl(int) const;
+ int backwardHistoryCount() const;
+ int forwardHistoryCount() const;
+
+ bool openExternalLinks() const;
+ void setOpenExternalLinks(bool open);
+
+ bool openLinks() const;
+ void setOpenLinks(bool open);
+
+public Q_SLOTS:
+ virtual void setSource(const QUrl &name);
+ virtual void backward();
+ virtual void forward();
+ virtual void home();
+ virtual void reload();
+
+Q_SIGNALS:
+ void backwardAvailable(bool);
+ void forwardAvailable(bool);
+ void historyChanged();
+ void sourceChanged(const QUrl &);
+ void highlighted(const QUrl &);
+ void highlighted(const QString &);
+ void anchorClicked(const QUrl &);
+
+protected:
+ bool event(QEvent *e);
+ virtual void keyPressEvent(QKeyEvent *ev);
+ virtual void mouseMoveEvent(QMouseEvent *ev);
+ virtual void mousePressEvent(QMouseEvent *ev);
+ virtual void mouseReleaseEvent(QMouseEvent *ev);
+ virtual void focusOutEvent(QFocusEvent *ev);
+ virtual bool focusNextPrevChild(bool next);
+ virtual void paintEvent(QPaintEvent *e);
+
+#if defined(QT3_SUPPORT)
+public:
+ QT3_SUPPORT_CONSTRUCTOR QTextBrowser(QWidget *parent, const char *name);
+#endif
+
+private:
+ Q_DISABLE_COPY(QTextBrowser)
+ Q_DECLARE_PRIVATE(QTextBrowser)
+ Q_PRIVATE_SLOT(d_func(), void _q_documentModified())
+ Q_PRIVATE_SLOT(d_func(), void _q_activateAnchor(const QString &))
+ Q_PRIVATE_SLOT(d_func(), void _q_highlightLink(const QString &))
+};
+
+#endif // QT_NO_TEXTBROWSER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTEXTBROWSER_H
diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp
new file mode 100644
index 0000000000..67be9dbed3
--- /dev/null
+++ b/src/widgets/widgets/qtextedit.cpp
@@ -0,0 +1,2809 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtextedit_p.h"
+#include "qlineedit.h"
+#include "qtextbrowser.h"
+
+#ifndef QT_NO_TEXTEDIT
+#include <qfont.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qdebug.h>
+#include <qmime.h>
+#include <qdrag.h>
+#include <qclipboard.h>
+#include <qmenu.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include "private/qtextdocumentlayout_p.h"
+#include "qtextdocument.h"
+#include "private/qtextdocument_p.h"
+#include "qtextlist.h"
+#include "private/qwidgettextcontrol_p.h"
+
+#include <qtextformat.h>
+#include <qdatetime.h>
+#include <qapplication.h>
+#include <limits.h>
+#include <qtexttable.h>
+#include <qvariant.h>
+
+#include <qinputcontext.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+
+#ifndef QT_NO_TEXTEDIT
+static inline bool shouldEnableInputMethod(QTextEdit *textedit)
+{
+ return !textedit->isReadOnly();
+}
+
+class QTextEditControl : public QWidgetTextControl
+{
+public:
+ inline QTextEditControl(QObject *parent) : QWidgetTextControl(parent) {}
+
+ virtual QMimeData *createMimeDataFromSelection() const {
+ QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
+ if (!ed)
+ return QWidgetTextControl::createMimeDataFromSelection();
+ return ed->createMimeDataFromSelection();
+ }
+ virtual bool canInsertFromMimeData(const QMimeData *source) const {
+ QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
+ if (!ed)
+ return QWidgetTextControl::canInsertFromMimeData(source);
+ return ed->canInsertFromMimeData(source);
+ }
+ virtual void insertFromMimeData(const QMimeData *source) {
+ QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
+ if (!ed)
+ QWidgetTextControl::insertFromMimeData(source);
+ else
+ ed->insertFromMimeData(source);
+ }
+};
+
+QTextEditPrivate::QTextEditPrivate()
+ : control(0),
+ autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false),
+ lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0),
+ wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0),
+ textFormat(Qt::AutoText)
+{
+ ignoreAutomaticScrollbarAdjustment = false;
+ preferRichText = false;
+ showCursorOnInitialShow = true;
+ inDrag = false;
+}
+
+void QTextEditPrivate::createAutoBulletList()
+{
+ QTextCursor cursor = control->textCursor();
+ cursor.beginEditBlock();
+
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextListFormat listFmt;
+ listFmt.setStyle(QTextListFormat::ListDisc);
+ listFmt.setIndent(blockFmt.indent() + 1);
+
+ blockFmt.setIndent(0);
+ cursor.setBlockFormat(blockFmt);
+
+ cursor.createList(listFmt);
+
+ cursor.endEditBlock();
+ control->setTextCursor(cursor);
+}
+
+void QTextEditPrivate::init(const QString &html)
+{
+ Q_Q(QTextEdit);
+ control = new QTextEditControl(q);
+ control->setPalette(q->palette());
+
+ QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));
+ QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));
+ QObject::connect(control, SIGNAL(visibilityRequest(QRectF)), q, SLOT(_q_ensureVisible(QRectF)));
+ QObject::connect(control, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
+ q, SLOT(_q_currentCharFormatChanged(QTextCharFormat)));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));
+ QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
+ QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
+ QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
+
+ QTextDocument *doc = control->document();
+ // set a null page size initially to avoid any relayouting until the textedit
+ // is shown. relayoutDocument() will take care of setting the page size to the
+ // viewport dimensions later.
+ doc->setPageSize(QSize(0, 0));
+ doc->documentLayout()->setPaintDevice(viewport);
+ doc->setDefaultFont(q->font());
+ doc->setUndoRedoEnabled(false); // flush undo buffer.
+ doc->setUndoRedoEnabled(true);
+
+ if (!html.isEmpty())
+ control->setHtml(html);
+
+ hbar->setSingleStep(20);
+ vbar->setSingleStep(20);
+
+ viewport->setBackgroundRole(QPalette::Base);
+ q->setAcceptDrops(true);
+ q->setFocusPolicy(Qt::WheelFocus);
+ q->setAttribute(Qt::WA_KeyCompression);
+ q->setAttribute(Qt::WA_InputMethodEnabled);
+ q->setInputMethodHints(Qt::ImhMultiLine);
+
+#ifndef QT_NO_CURSOR
+ viewport->setCursor(Qt::IBeamCursor);
+#endif
+#ifdef Q_WS_WIN
+ setSingleFingerPanEnabled(true);
+#endif
+}
+
+void QTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
+{
+ if (!contentsRect.isValid()) {
+ viewport->update();
+ return;
+ }
+ const int xOffset = horizontalOffset();
+ const int yOffset = verticalOffset();
+ const QRectF visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
+
+ QRect r = contentsRect.intersected(visibleRect).toAlignedRect();
+ if (r.isEmpty())
+ return;
+
+ r.translate(-xOffset, -yOffset);
+ viewport->update(r);
+}
+
+void QTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode)
+{
+ QTextCursor cursor = control->textCursor();
+ bool moved = false;
+ qreal lastY = control->cursorRect(cursor).top();
+ qreal distance = 0;
+ // move using movePosition to keep the cursor's x
+ do {
+ qreal y = control->cursorRect(cursor).top();
+ distance += qAbs(y - lastY);
+ lastY = y;
+ moved = cursor.movePosition(op, moveMode);
+ } while (moved && distance < viewport->height());
+
+ if (moved) {
+ if (op == QTextCursor::Up) {
+ cursor.movePosition(QTextCursor::Down, moveMode);
+ vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
+ } else {
+ cursor.movePosition(QTextCursor::Up, moveMode);
+ vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
+ }
+ }
+ control->setTextCursor(cursor);
+}
+
+#ifndef QT_NO_SCROLLBAR
+static QSize documentSize(QWidgetTextControl *control)
+{
+ QTextDocument *doc = control->document();
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+
+ QSize docSize;
+
+ if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
+ docSize = tlayout->dynamicDocumentSize().toSize();
+ int percentageDone = tlayout->layoutStatus();
+ // extrapolate height
+ if (percentageDone > 0)
+ docSize.setHeight(docSize.height() * 100 / percentageDone);
+ } else {
+ docSize = layout->documentSize().toSize();
+ }
+
+ return docSize;
+}
+
+void QTextEditPrivate::_q_adjustScrollbars()
+{
+ if (ignoreAutomaticScrollbarAdjustment)
+ return;
+ ignoreAutomaticScrollbarAdjustment = true; // avoid recursion, #106108
+
+ QSize viewportSize = viewport->size();
+ QSize docSize = documentSize(control);
+
+ // due to the recursion guard we have to repeat this step a few times,
+ // as adding/removing a scroll bar will cause the document or viewport
+ // size to change
+ // ideally we should loop until the viewport size and doc size stabilize,
+ // but in corner cases they might fluctuate, so we need to limit the
+ // number of iterations
+ for (int i = 0; i < 4; ++i) {
+ hbar->setRange(0, docSize.width() - viewportSize.width());
+ hbar->setPageStep(viewportSize.width());
+
+ vbar->setRange(0, docSize.height() - viewportSize.height());
+ vbar->setPageStep(viewportSize.height());
+
+ // if we are in left-to-right mode widening the document due to
+ // lazy layouting does not require a repaint. If in right-to-left
+ // the scroll bar has the value zero and it visually has the maximum
+ // value (it is visually at the right), then widening the document
+ // keeps it at value zero but visually adjusts it to the new maximum
+ // on the right, hence we need an update.
+ if (q_func()->isRightToLeft())
+ viewport->update();
+
+ _q_showOrHideScrollBars();
+
+ const QSize oldViewportSize = viewportSize;
+ const QSize oldDocSize = docSize;
+
+ // make sure the document is layouted if the viewport width changes
+ viewportSize = viewport->size();
+ if (viewportSize.width() != oldViewportSize.width())
+ relayoutDocument();
+
+ docSize = documentSize(control);
+ if (viewportSize == oldViewportSize && docSize == oldDocSize)
+ break;
+ }
+ ignoreAutomaticScrollbarAdjustment = false;
+}
+#endif
+
+// rect is in content coordinates
+void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
+{
+ const QRect rect = _rect.toRect();
+ if ((vbar->isVisible() && vbar->maximum() < rect.bottom())
+ || (hbar->isVisible() && hbar->maximum() < rect.right()))
+ _q_adjustScrollbars();
+ const int visibleWidth = viewport->width();
+ const int visibleHeight = viewport->height();
+ const bool rtl = q_func()->isRightToLeft();
+
+ if (rect.x() < horizontalOffset()) {
+ if (rtl)
+ hbar->setValue(hbar->maximum() - rect.x());
+ else
+ hbar->setValue(rect.x());
+ } else if (rect.x() + rect.width() > horizontalOffset() + visibleWidth) {
+ if (rtl)
+ hbar->setValue(hbar->maximum() - (rect.x() + rect.width() - visibleWidth));
+ else
+ hbar->setValue(rect.x() + rect.width() - visibleWidth);
+ }
+
+ if (rect.y() < verticalOffset())
+ vbar->setValue(rect.y());
+ else if (rect.y() + rect.height() > verticalOffset() + visibleHeight)
+ vbar->setValue(rect.y() + rect.height() - visibleHeight);
+}
+
+/*!
+ \class QTextEdit
+ \brief The QTextEdit class provides a widget that is used to edit and display
+ both plain and rich text.
+
+ \ingroup richtext-processing
+
+
+ \tableofcontents
+
+ \section1 Introduction and Concepts
+
+ QTextEdit is an advanced WYSIWYG viewer/editor supporting rich
+ text formatting using HTML-style tags. It is optimized to handle
+ large documents and to respond quickly to user input.
+
+ QTextEdit works on paragraphs and characters. A paragraph is a
+ formatted string which is word-wrapped to fit into the width of
+ the widget. By default when reading plain text, one newline
+ signifies a paragraph. A document consists of zero or more
+ paragraphs. The words in the paragraph are aligned in accordance
+ with the paragraph's alignment. Paragraphs are separated by hard
+ line breaks. Each character within a paragraph has its own
+ attributes, for example, font and color.
+
+ QTextEdit can display images, lists and tables. If the text is
+ too large to view within the text edit's viewport, scroll bars will
+ appear. The text edit can load both plain text and HTML files (a
+ subset of HTML 3.2 and 4).
+
+ If you just need to display a small piece of rich text use QLabel.
+
+ The rich text support in Qt is designed to provide a fast, portable and
+ efficient way to add reasonable online help facilities to
+ applications, and to provide a basis for rich text editors. If
+ you find the HTML support insufficient for your needs you may consider
+ the use of QtWebKit, which provides a full-featured web browser
+ widget.
+
+ The shape of the mouse cursor on a QTextEdit is Qt::IBeamCursor by default.
+ It can be changed through the viewport()'s cursor property.
+
+ \section1 Using QTextEdit as a Display Widget
+
+ QTextEdit can display a large HTML subset, including tables and
+ images.
+
+ The text is set or replaced using setHtml() which deletes any
+ existing text and replaces it with the text passed in the
+ setHtml() call. If you call setHtml() with legacy HTML, and then
+ call toHtml(), the text that is returned may have different markup,
+ but will render the same. The entire text can be deleted with clear().
+
+ Text itself can be inserted using the QTextCursor class or using the
+ convenience functions insertHtml(), insertPlainText(), append() or
+ paste(). QTextCursor is also able to insert complex objects like tables
+ or lists into the document, and it deals with creating selections
+ and applying changes to selected text.
+
+ By default the text edit wraps words at whitespace to fit within
+ the text edit widget. The setLineWrapMode() function is used to
+ specify the kind of line wrap you want, or \l NoWrap if you don't
+ want any wrapping. Call setLineWrapMode() to set a fixed pixel width
+ \l FixedPixelWidth, or character column (e.g. 80 column) \l
+ FixedColumnWidth with the pixels or columns specified with
+ setLineWrapColumnOrWidth(). If you use word wrap to the widget's width
+ \l WidgetWidth, you can specify whether to break on whitespace or
+ anywhere with setWordWrapMode().
+
+ The find() function can be used to find and select a given string
+ within the text.
+
+ If you want to limit the total number of paragraphs in a QTextEdit,
+ as it is for example open useful in a log viewer, then you can use
+ QTextDocument's maximumBlockCount property for that.
+
+ \section2 Read-only Key Bindings
+
+ When QTextEdit is used read-only the key bindings are limited to
+ navigation, and text may only be selected with the mouse:
+ \table
+ \header \i Keypresses \i Action
+ \row \i Up \i Moves one line up.
+ \row \i Down \i Moves one line down.
+ \row \i Left \i Moves one character to the left.
+ \row \i Right \i Moves one character to the right.
+ \row \i PageUp \i Moves one (viewport) page up.
+ \row \i PageDown \i Moves one (viewport) page down.
+ \row \i Home \i Moves to the beginning of the text.
+ \row \i End \i Moves to the end of the text.
+ \row \i Alt+Wheel
+ \i Scrolls the page horizontally (the Wheel is the mouse wheel).
+ \row \i Ctrl+Wheel \i Zooms the text.
+ \row \i Ctrl+A \i Selects all text.
+ \endtable
+
+ The text edit may be able to provide some meta-information. For
+ example, the documentTitle() function will return the text from
+ within HTML \c{<title>} tags.
+
+ \section1 Using QTextEdit as an Editor
+
+ All the information about using QTextEdit as a display widget also
+ applies here.
+
+ The current char format's attributes are set with setFontItalic(),
+ setFontWeight(), setFontUnderline(), setFontFamily(),
+ setFontPointSize(), setTextColor() and setCurrentFont(). The current
+ paragraph's alignment is set with setAlignment().
+
+ Selection of text is handled by the QTextCursor class, which provides
+ functionality for creating selections, retrieving the text contents or
+ deleting selections. You can retrieve the object that corresponds with
+ the user-visible cursor using the textCursor() method. If you want to set
+ a selection in QTextEdit just create one on a QTextCursor object and
+ then make that cursor the visible cursor using setTextCursor(). The selection
+ can be copied to the clipboard with copy(), or cut to the clipboard with
+ cut(). The entire text can be selected using selectAll().
+
+ When the cursor is moved and the underlying formatting attributes change,
+ the currentCharFormatChanged() signal is emitted to reflect the new attributes
+ at the new cursor position.
+
+ QTextEdit holds a QTextDocument object which can be retrieved using the
+ document() method. You can also set your own document object using setDocument().
+ QTextDocument emits a textChanged() signal if the text changes and it also
+ provides a isModified() function which will return true if the text has been
+ modified since it was either loaded or since the last call to setModified
+ with false as argument. In addition it provides methods for undo and redo.
+
+ \section2 Drag and Drop
+
+ QTextEdit also supports custom drag and drop behavior. By default,
+ QTextEdit will insert plain text, HTML and rich text when the user drops
+ data of these MIME types onto a document. Reimplement
+ canInsertFromMimeData() and insertFromMimeData() to add support for
+ additional MIME types.
+
+ For example, to allow the user to drag and drop an image onto a QTextEdit,
+ you could the implement these functions in the following way:
+
+ \snippet doc/src/snippets/textdocument-imagedrop/textedit.cpp 0
+
+ We add support for image MIME types by returning true. For all other
+ MIME types, we use the default implementation.
+
+ \snippet doc/src/snippets/textdocument-imagedrop/textedit.cpp 1
+
+ We unpack the image from the QVariant held by the MIME source and insert
+ it into the document as a resource.
+
+ \section2 Editing Key Bindings
+
+ The list of key bindings which are implemented for editing:
+ \table
+ \header \i Keypresses \i Action
+ \row \i Backspace \i Deletes the character to the left of the cursor.
+ \row \i Delete \i Deletes the character to the right of the cursor.
+ \row \i Ctrl+C \i Copy the selected text to the clipboard.
+ \row \i Ctrl+Insert \i Copy the selected text to the clipboard.
+ \row \i Ctrl+K \i Deletes to the end of the line.
+ \row \i Ctrl+V \i Pastes the clipboard text into text edit.
+ \row \i Shift+Insert \i Pastes the clipboard text into text edit.
+ \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
+ \row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.
+ \row \i Ctrl+Z \i Undoes the last operation.
+ \row \i Ctrl+Y \i Redoes the last operation.
+ \row \i Left \i Moves the cursor one character to the left.
+ \row \i Ctrl+Left \i Moves the cursor one word to the left.
+ \row \i Right \i Moves the cursor one character to the right.
+ \row \i Ctrl+Right \i Moves the cursor one word to the right.
+ \row \i Up \i Moves the cursor one line up.
+ \row \i Down \i Moves the cursor one line down.
+ \row \i PageUp \i Moves the cursor one page up.
+ \row \i PageDown \i Moves the cursor one page down.
+ \row \i Home \i Moves the cursor to the beginning of the line.
+ \row \i Ctrl+Home \i Moves the cursor to the beginning of the text.
+ \row \i End \i Moves the cursor to the end of the line.
+ \row \i Ctrl+End \i Moves the cursor to the end of the text.
+ \row \i Alt+Wheel \i Scrolls the page horizontally (the Wheel is the mouse wheel).
+ \endtable
+
+ To select (mark) text hold down the Shift key whilst pressing one
+ of the movement keystrokes, for example, \e{Shift+Right}
+ will select the character to the right, and \e{Shift+Ctrl+Right} will select the word to the right, etc.
+
+ \sa QTextDocument, QTextCursor, {Application Example},
+ {Syntax Highlighter Example}, {Rich Text Processing}
+*/
+
+/*!
+ \property QTextEdit::plainText
+ \since 4.3
+
+ This property gets and sets the text editor's contents as plain
+ text. Previous contents are removed and undo/redo history is reset
+ when the property is set.
+
+ If the text edit has another content type, it will not be replaced
+ by plain text if you call toPlainText(). The only exception to this
+ is the non-break space, \e{nbsp;}, that will be converted into
+ standard space.
+
+ By default, for an editor with no contents, this property contains
+ an empty string.
+
+ \sa html
+*/
+
+/*!
+ \property QTextEdit::undoRedoEnabled
+ \brief whether undo and redo are enabled
+
+ Users are only able to undo or redo actions if this property is
+ true, and if there is an action that can be undone (or redone).
+*/
+
+/*!
+ \enum QTextEdit::LineWrapMode
+
+ \value NoWrap
+ \value WidgetWidth
+ \value FixedPixelWidth
+ \value FixedColumnWidth
+*/
+
+/*!
+ \enum QTextEdit::AutoFormattingFlag
+
+ \value AutoNone Don't do any automatic formatting.
+ \value AutoBulletList Automatically create bullet lists (e.g. when
+ the user enters an asterisk ('*') in the left most column, or
+ presses Enter in an existing list item.
+ \value AutoAll Apply all automatic formatting. Currently only
+ automatic bullet lists are supported.
+*/
+
+#ifdef QT3_SUPPORT
+/*!
+ \enum QTextEdit::CursorAction
+ \compat
+
+ \value MoveBackward
+ \value MoveForward
+ \value MoveWordBackward
+ \value MoveWordForward
+ \value MoveUp
+ \value MoveDown
+ \value MoveLineStart
+ \value MoveLineEnd
+ \value MoveHome
+ \value MoveEnd
+ \value MovePageUp
+ \value MovePageDown
+
+ \omitvalue MovePgUp
+ \omitvalue MovePgDown
+*/
+#endif
+
+/*!
+ Constructs an empty QTextEdit with parent \a
+ parent.
+*/
+QTextEdit::QTextEdit(QWidget *parent)
+ : QAbstractScrollArea(*new QTextEditPrivate, parent)
+{
+ Q_D(QTextEdit);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+QTextEdit::QTextEdit(QTextEditPrivate &dd, QWidget *parent)
+ : QAbstractScrollArea(dd, parent)
+{
+ Q_D(QTextEdit);
+ d->init();
+}
+
+/*!
+ Constructs a QTextEdit with parent \a parent. The text edit will display
+ the text \a text. The text is interpreted as html.
+*/
+QTextEdit::QTextEdit(const QString &text, QWidget *parent)
+ : QAbstractScrollArea(*new QTextEditPrivate, parent)
+{
+ Q_D(QTextEdit);
+ d->init(text);
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QTextEdit::QTextEdit(QWidget *parent, const char *name)
+ : QAbstractScrollArea(*new QTextEditPrivate, parent)
+{
+ Q_D(QTextEdit);
+ d->init();
+ setObjectName(QString::fromAscii(name));
+}
+#endif
+
+
+/*!
+ Destructor.
+*/
+QTextEdit::~QTextEdit()
+{
+}
+
+/*!
+ Returns the point size of the font of the current format.
+
+ \sa setFontFamily() setCurrentFont() setFontPointSize()
+*/
+qreal QTextEdit::fontPointSize() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().fontPointSize();
+}
+
+/*!
+ Returns the font family of the current format.
+
+ \sa setFontFamily() setCurrentFont() setFontPointSize()
+*/
+QString QTextEdit::fontFamily() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().fontFamily();
+}
+
+/*!
+ Returns the font weight of the current format.
+
+ \sa setFontWeight() setCurrentFont() setFontPointSize() QFont::Weight
+*/
+int QTextEdit::fontWeight() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().fontWeight();
+}
+
+/*!
+ Returns true if the font of the current format is underlined; otherwise returns
+ false.
+
+ \sa setFontUnderline()
+*/
+bool QTextEdit::fontUnderline() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().fontUnderline();
+}
+
+/*!
+ Returns true if the font of the current format is italic; otherwise returns
+ false.
+
+ \sa setFontItalic()
+*/
+bool QTextEdit::fontItalic() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().fontItalic();
+}
+
+/*!
+ Returns the text color of the current format.
+
+ \sa setTextColor()
+*/
+QColor QTextEdit::textColor() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().foreground().color();
+}
+
+/*!
+ \since 4.4
+
+ Returns the text background color of the current format.
+
+ \sa setTextBackgroundColor()
+*/
+QColor QTextEdit::textBackgroundColor() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().background().color();
+}
+
+/*!
+ Returns the font of the current format.
+
+ \sa setCurrentFont() setFontFamily() setFontPointSize()
+*/
+QFont QTextEdit::currentFont() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().charFormat().font();
+}
+
+/*!
+ Sets the alignment of the current paragraph to \a a. Valid
+ alignments are Qt::AlignLeft, Qt::AlignRight,
+ Qt::AlignJustify and Qt::AlignCenter (which centers
+ horizontally).
+*/
+void QTextEdit::setAlignment(Qt::Alignment a)
+{
+ Q_D(QTextEdit);
+ QTextBlockFormat fmt;
+ fmt.setAlignment(a);
+ QTextCursor cursor = d->control->textCursor();
+ cursor.mergeBlockFormat(fmt);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Returns the alignment of the current paragraph.
+
+ \sa setAlignment()
+*/
+Qt::Alignment QTextEdit::alignment() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor().blockFormat().alignment();
+}
+
+/*!
+ Makes \a document the new document of the text editor.
+
+ \note The editor \e{does not take ownership of the document} unless it
+ is the document's parent object. The parent object of the provided document
+ remains the owner of the object.
+
+ The editor does not delete the current document, even if it is a child of the editor.
+
+ \sa document()
+*/
+void QTextEdit::setDocument(QTextDocument *document)
+{
+ Q_D(QTextEdit);
+ d->control->setDocument(document);
+ d->updateDefaultTextOption();
+ d->relayoutDocument();
+}
+
+/*!
+ Returns a pointer to the underlying document.
+
+ \sa setDocument()
+*/
+QTextDocument *QTextEdit::document() const
+{
+ Q_D(const QTextEdit);
+ return d->control->document();
+}
+
+/*!
+ Sets the visible \a cursor.
+*/
+void QTextEdit::setTextCursor(const QTextCursor &cursor)
+{
+ Q_D(QTextEdit);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Returns a copy of the QTextCursor that represents the currently visible cursor.
+ Note that changes on the returned cursor do not affect QTextEdit's cursor; use
+ setTextCursor() to update the visible cursor.
+ */
+QTextCursor QTextEdit::textCursor() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textCursor();
+}
+
+/*!
+ Sets the font family of the current format to \a fontFamily.
+
+ \sa fontFamily() setCurrentFont()
+*/
+void QTextEdit::setFontFamily(const QString &fontFamily)
+{
+ QTextCharFormat fmt;
+ fmt.setFontFamily(fontFamily);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ Sets the point size of the current format to \a s.
+
+ Note that if \a s is zero or negative, the behavior of this
+ function is not defined.
+
+ \sa fontPointSize() setCurrentFont() setFontFamily()
+*/
+void QTextEdit::setFontPointSize(qreal s)
+{
+ QTextCharFormat fmt;
+ fmt.setFontPointSize(s);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ \fn void QTextEdit::setFontWeight(int weight)
+
+ Sets the font weight of the current format to the given \a weight,
+ where the value used is in the range defined by the QFont::Weight
+ enum.
+
+ \sa fontWeight(), setCurrentFont(), setFontFamily()
+*/
+void QTextEdit::setFontWeight(int w)
+{
+ QTextCharFormat fmt;
+ fmt.setFontWeight(w);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ If \a underline is true, sets the current format to underline;
+ otherwise sets the current format to non-underline.
+
+ \sa fontUnderline()
+*/
+void QTextEdit::setFontUnderline(bool underline)
+{
+ QTextCharFormat fmt;
+ fmt.setFontUnderline(underline);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ If \a italic is true, sets the current format to italic;
+ otherwise sets the current format to non-italic.
+
+ \sa fontItalic()
+*/
+void QTextEdit::setFontItalic(bool italic)
+{
+ QTextCharFormat fmt;
+ fmt.setFontItalic(italic);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ Sets the text color of the current format to \a c.
+
+ \sa textColor()
+*/
+void QTextEdit::setTextColor(const QColor &c)
+{
+ QTextCharFormat fmt;
+ fmt.setForeground(QBrush(c));
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ \since 4.4
+
+ Sets the text background color of the current format to \a c.
+
+ \sa textBackgroundColor()
+*/
+void QTextEdit::setTextBackgroundColor(const QColor &c)
+{
+ QTextCharFormat fmt;
+ fmt.setBackground(QBrush(c));
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ Sets the font of the current format to \a f.
+
+ \sa currentFont() setFontPointSize() setFontFamily()
+*/
+void QTextEdit::setCurrentFont(const QFont &f)
+{
+ QTextCharFormat fmt;
+ fmt.setFont(f);
+ mergeCurrentCharFormat(fmt);
+}
+
+/*!
+ \since 4.2
+
+ Undoes the last operation.
+
+ If there is no operation to undo, i.e. there is no undo step in
+ the undo/redo history, nothing happens.
+
+ \sa redo()
+*/
+void QTextEdit::undo()
+{
+ Q_D(QTextEdit);
+ d->control->undo();
+}
+
+void QTextEdit::redo()
+{
+ Q_D(QTextEdit);
+ d->control->redo();
+}
+
+/*!
+ \fn void QTextEdit::undo() const
+ \fn void QTextEdit::redo() const
+ \overload
+
+ Use the non-const overload instead.
+*/
+
+/*!
+ \fn void QTextEdit::redo()
+ \since 4.2
+
+ Redoes the last operation.
+
+ If there is no operation to redo, i.e. there is no redo step in
+ the undo/redo history, nothing happens.
+
+ \sa undo()
+*/
+
+#ifndef QT_NO_CLIPBOARD
+/*!
+ Copies the selected text to the clipboard and deletes it from
+ the text edit.
+
+ If there is no selected text nothing happens.
+
+ \sa copy() paste()
+*/
+
+void QTextEdit::cut()
+{
+ Q_D(QTextEdit);
+ d->control->cut();
+}
+
+/*!
+ Copies any selected text to the clipboard.
+
+ \sa copyAvailable()
+*/
+
+void QTextEdit::copy()
+{
+ Q_D(QTextEdit);
+ d->control->copy();
+}
+
+/*!
+ Pastes the text from the clipboard into the text edit at the
+ current cursor position.
+
+ If there is no text in the clipboard nothing happens.
+
+ To change the behavior of this function, i.e. to modify what
+ QTextEdit can paste and how it is being pasted, reimplement the
+ virtual canInsertFromMimeData() and insertFromMimeData()
+ functions.
+
+ \sa cut() copy()
+*/
+
+void QTextEdit::paste()
+{
+ Q_D(QTextEdit);
+ d->control->paste();
+}
+#endif
+
+/*!
+ Deletes all the text in the text edit.
+
+ Note that the undo/redo history is cleared by this function.
+
+ \sa cut() setPlainText() setHtml()
+*/
+void QTextEdit::clear()
+{
+ Q_D(QTextEdit);
+ // clears and sets empty content
+ d->control->clear();
+}
+
+
+/*!
+ Selects all text.
+
+ \sa copy() cut() textCursor()
+ */
+void QTextEdit::selectAll()
+{
+ Q_D(QTextEdit);
+ d->control->selectAll();
+}
+
+/*! \internal
+*/
+bool QTextEdit::event(QEvent *e)
+{
+ Q_D(QTextEdit);
+#ifndef QT_NO_CONTEXTMENU
+ if (e->type() == QEvent::ContextMenu
+ && static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
+ Q_D(QTextEdit);
+ ensureCursorVisible();
+ const QPoint cursorPos = cursorRect().center();
+ QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
+ ce.setAccepted(e->isAccepted());
+ const bool result = QAbstractScrollArea::event(&ce);
+ e->setAccepted(ce.isAccepted());
+ return result;
+ } else if (e->type() == QEvent::ShortcutOverride
+ || e->type() == QEvent::ToolTip) {
+ d->sendControlEvent(e);
+ }
+#endif // QT_NO_CONTEXTMENU
+#ifdef QT_KEYPAD_NAVIGATION
+ if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {
+ if (QApplication::keypadNavigationEnabled())
+ d->sendControlEvent(e);
+ }
+#endif
+ return QAbstractScrollArea::event(e);
+}
+
+/*! \internal
+*/
+
+void QTextEdit::timerEvent(QTimerEvent *e)
+{
+ Q_D(QTextEdit);
+ if (e->timerId() == d->autoScrollTimer.timerId()) {
+ QRect visible = d->viewport->rect();
+ QPoint pos;
+ if (d->inDrag) {
+ pos = d->autoScrollDragPos;
+ visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
+ -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
+ } else {
+ const QPoint globalPos = QCursor::pos();
+ pos = d->viewport->mapFromGlobal(globalPos);
+ QMouseEvent ev(QEvent::MouseMove, pos, mapTo(topLevelWidget(), pos), globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ mouseMoveEvent(&ev);
+ }
+ int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
+ int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
+ int delta = qMax(deltaX, deltaY);
+ if (delta >= 0) {
+ if (delta < 7)
+ delta = 7;
+ int timeout = 4900 / (delta * delta);
+ d->autoScrollTimer.start(timeout, this);
+
+ if (deltaY > 0)
+ d->vbar->triggerAction(pos.y() < visible.center().y() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ if (deltaX > 0)
+ d->hbar->triggerAction(pos.x() < visible.center().x() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ }
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ else if (e->timerId() == d->deleteAllTimer.timerId()) {
+ d->deleteAllTimer.stop();
+ clear();
+ }
+#endif
+}
+
+/*!
+ Changes the text of the text edit to the string \a text.
+ Any previous text is removed.
+
+ \a text is interpreted as plain text.
+
+ Note that the undo/redo history is cleared by this function.
+
+ \sa toPlainText()
+*/
+
+void QTextEdit::setPlainText(const QString &text)
+{
+ Q_D(QTextEdit);
+ d->control->setPlainText(text);
+ d->preferRichText = false;
+}
+
+/*!
+ \fn QString QTextEdit::toPlainText() const
+
+ Returns the text of the text edit as plain text.
+
+ \sa QTextEdit::setPlainText()
+ */
+
+
+/*!
+ \property QTextEdit::html
+
+ This property provides an HTML interface to the text of the text edit.
+
+ toHtml() returns the text of the text edit as html.
+
+ setHtml() changes the text of the text edit. Any previous text is
+ removed and the undo/redo history is cleared. The input text is
+ interpreted as rich text in html format.
+
+ \note It is the responsibility of the caller to make sure that the
+ text is correctly decoded when a QString containing HTML is created
+ and passed to setHtml().
+
+ By default, for a newly-created, empty document, this property contains
+ text to describe an HTML 4.0 document with no body text.
+
+ \sa {Supported HTML Subset}, plainText
+*/
+
+#ifndef QT_NO_TEXTHTMLPARSER
+void QTextEdit::setHtml(const QString &text)
+{
+ Q_D(QTextEdit);
+ d->control->setHtml(text);
+ d->preferRichText = true;
+}
+#endif
+
+/*! \reimp
+*/
+void QTextEdit::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QTextEdit);
+
+#ifdef QT_KEYPAD_NAVIGATION
+ switch (e->key()) {
+ case Qt::Key_Select:
+ if (QApplication::keypadNavigationEnabled()) {
+ // code assumes linksaccessible + editable isn't meaningful
+ if (d->control->textInteractionFlags() & Qt::TextEditable) {
+ setEditFocus(!hasEditFocus());
+ } else {
+ if (!hasEditFocus())
+ setEditFocus(true);
+ else {
+ QTextCursor cursor = d->control->textCursor();
+ QTextCharFormat charFmt = cursor.charFormat();
+ if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard)
+ || !cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
+ e->accept();
+ return;
+ }
+ }
+ }
+ }
+ break;
+ case Qt::Key_Back:
+ case Qt::Key_No:
+ if (!QApplication::keypadNavigationEnabled()
+ || (QApplication::keypadNavigationEnabled() && !hasEditFocus())) {
+ e->ignore();
+ return;
+ }
+ break;
+ default:
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
+ if (e->text()[0].isPrint())
+ setEditFocus(true);
+ else {
+ e->ignore();
+ return;
+ }
+ }
+ }
+ break;
+ }
+#endif
+#ifndef QT_NO_SHORTCUT
+
+ Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
+
+ if (tif & Qt::TextSelectableByKeyboard){
+ if (e == QKeySequence::SelectPreviousPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
+ return;
+ } else if (e ==QKeySequence::SelectNextPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
+ return;
+ }
+ }
+ if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
+ if (e == QKeySequence::MoveToPreviousPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
+ return;
+ } else if (e == QKeySequence::MoveToNextPage) {
+ e->accept();
+ d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
+ return;
+ }
+ }
+
+ if (!(tif & Qt::TextEditable)) {
+ switch (e->key()) {
+ case Qt::Key_Space:
+ e->accept();
+ if (e->modifiers() & Qt::ShiftModifier)
+ d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
+ else
+ d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
+ break;
+ default:
+ d->sendControlEvent(e);
+ if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
+ if (e->key() == Qt::Key_Home) {
+ d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
+ e->accept();
+ } else if (e->key() == Qt::Key_End) {
+ d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
+ e->accept();
+ }
+ }
+ if (!e->isAccepted()) {
+ QAbstractScrollArea::keyPressEvent(e);
+ }
+ }
+ return;
+ }
+#endif // QT_NO_SHORTCUT
+
+ {
+ QTextCursor cursor = d->control->textCursor();
+ const QString text = e->text();
+ if (cursor.atBlockStart()
+ && (d->autoFormatting & AutoBulletList)
+ && (text.length() == 1)
+ && (text.at(0) == QLatin1Char('-') || text.at(0) == QLatin1Char('*'))
+ && (!cursor.currentList())) {
+
+ d->createAutoBulletList();
+ e->accept();
+ return;
+ }
+ }
+
+ d->sendControlEvent(e);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!e->isAccepted()) {
+ switch (e->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ if (QApplication::keypadNavigationEnabled()) {
+ // Cursor position didn't change, so we want to leave
+ // these keys to change focus.
+ e->ignore();
+ return;
+ }
+ break;
+ case Qt::Key_Back:
+ if (!e->isAutoRepeat()) {
+ if (QApplication::keypadNavigationEnabled()) {
+ if (document()->isEmpty() || !(d->control->textInteractionFlags() & Qt::TextEditable)) {
+ setEditFocus(false);
+ e->accept();
+ } else if (!d->deleteAllTimer.isActive()) {
+ e->accept();
+ d->deleteAllTimer.start(750, this);
+ }
+ } else {
+ e->ignore();
+ return;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+#endif
+}
+
+/*! \reimp
+*/
+void QTextEdit::keyReleaseEvent(QKeyEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ Q_D(QTextEdit);
+ if (QApplication::keypadNavigationEnabled()) {
+ if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
+ && d->deleteAllTimer.isActive()) {
+ d->deleteAllTimer.stop();
+ QTextCursor cursor = d->control->textCursor();
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextList *list = cursor.currentList();
+ if (list && cursor.atBlockStart()) {
+ list->remove(cursor.block());
+ } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
+ blockFmt.setIndent(blockFmt.indent() - 1);
+ cursor.setBlockFormat(blockFmt);
+ } else {
+ cursor.deletePreviousChar();
+ }
+ setTextCursor(cursor);
+ e->accept();
+ return;
+ }
+ }
+#endif
+ e->ignore();
+}
+
+/*!
+ Loads the resource specified by the given \a type and \a name.
+
+ This function is an extension of QTextDocument::loadResource().
+
+ \sa QTextDocument::loadResource()
+*/
+QVariant QTextEdit::loadResource(int type, const QUrl &name)
+{
+ Q_UNUSED(type);
+ Q_UNUSED(name);
+ return QVariant();
+}
+
+/*! \reimp
+*/
+void QTextEdit::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QTextEdit);
+
+ if (d->lineWrap == NoWrap) {
+ QTextDocument *doc = d->control->document();
+ QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
+
+ if (!doc->pageSize().isNull()
+ && alignmentProperty.type() == QVariant::Bool
+ && !alignmentProperty.toBool()) {
+
+ d->_q_adjustScrollbars();
+ return;
+ }
+ }
+
+ if (d->lineWrap != FixedPixelWidth
+ && e->oldSize().width() != e->size().width())
+ d->relayoutDocument();
+ else
+ d->_q_adjustScrollbars();
+}
+
+void QTextEditPrivate::relayoutDocument()
+{
+ QTextDocument *doc = control->document();
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+
+ if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
+ if (lineWrap == QTextEdit::FixedColumnWidth)
+ tlayout->setFixedColumnWidth(lineWrapColumnOrWidth);
+ else
+ tlayout->setFixedColumnWidth(-1);
+ }
+
+ QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout);
+ QSize lastUsedSize;
+ if (tlayout)
+ lastUsedSize = tlayout->dynamicDocumentSize().toSize();
+ else
+ lastUsedSize = layout->documentSize().toSize();
+
+ // ignore calls to _q_adjustScrollbars caused by an emission of the
+ // usedSizeChanged() signal in the layout, as we're calling it
+ // later on our own anyway (or deliberately not) .
+ const bool oldIgnoreScrollbarAdjustment = ignoreAutomaticScrollbarAdjustment;
+ ignoreAutomaticScrollbarAdjustment = true;
+
+ int width = viewport->width();
+ if (lineWrap == QTextEdit::FixedPixelWidth)
+ width = lineWrapColumnOrWidth;
+ else if (lineWrap == QTextEdit::NoWrap) {
+ QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
+ if (alignmentProperty.type() == QVariant::Bool && !alignmentProperty.toBool()) {
+
+ width = 0;
+ }
+ }
+
+ doc->setPageSize(QSize(width, -1));
+ if (tlayout)
+ tlayout->ensureLayouted(verticalOffset() + viewport->height());
+
+ ignoreAutomaticScrollbarAdjustment = oldIgnoreScrollbarAdjustment;
+
+ QSize usedSize;
+ if (tlayout)
+ usedSize = tlayout->dynamicDocumentSize().toSize();
+ else
+ usedSize = layout->documentSize().toSize();
+
+ // this is an obscure situation in the layout that can happen:
+ // if a character at the end of a line is the tallest one and therefore
+ // influencing the total height of the line and the line right below it
+ // is always taller though, then it can happen that if due to line breaking
+ // that tall character wraps into the lower line the document not only shrinks
+ // horizontally (causing the character to wrap in the first place) but also
+ // vertically, because the original line is now smaller and the one below kept
+ // its size. So a layout with less width _can_ take up less vertical space, too.
+ // If the wider case causes a vertical scroll bar to appear and the narrower one
+ // (narrower because the vertical scroll bar takes up horizontal space)) to disappear
+ // again then we have an endless loop, as _q_adjustScrollBars sets new ranges on the
+ // scroll bars, the QAbstractScrollArea will find out about it and try to show/hide
+ // the scroll bars again. That's why we try to detect this case here and break out.
+ //
+ // (if you change this please also check the layoutingLoop() testcase in
+ // QTextEdit's autotests)
+ if (lastUsedSize.isValid()
+ && !vbar->isHidden()
+ && viewport->width() < lastUsedSize.width()
+ && usedSize.height() < lastUsedSize.height()
+ && usedSize.height() <= viewport->height())
+ return;
+
+ _q_adjustScrollbars();
+}
+
+void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
+{
+ const int xOffset = horizontalOffset();
+ const int yOffset = verticalOffset();
+
+ QRect r = e->rect();
+ p->translate(-xOffset, -yOffset);
+ r.translate(xOffset, yOffset);
+
+ QTextDocument *doc = control->document();
+ QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
+
+ // the layout might need to expand the root frame to
+ // the viewport if NoWrap is set
+ if (layout)
+ layout->setViewport(viewport->rect());
+
+ control->drawContents(p, r, q_func());
+
+ if (layout)
+ layout->setViewport(QRect());
+}
+
+/*! \fn void QTextEdit::paintEvent(QPaintEvent *event)
+
+This event handler can be reimplemented in a subclass to receive paint events passed in \a event.
+It is usually unnecessary to reimplement this function in a subclass of QTextEdit.
+
+\warning The underlying text document must not be modified from within a reimplementation
+of this function.
+*/
+void QTextEdit::paintEvent(QPaintEvent *e)
+{
+ Q_D(QTextEdit);
+ QPainter p(d->viewport);
+ d->paint(&p, e);
+}
+
+void QTextEditPrivate::_q_currentCharFormatChanged(const QTextCharFormat &fmt)
+{
+ Q_Q(QTextEdit);
+ emit q->currentCharFormatChanged(fmt);
+#ifdef QT3_SUPPORT
+ // compat signals
+ emit q->currentFontChanged(fmt.font());
+ emit q->currentColorChanged(fmt.foreground().color());
+#endif
+}
+
+void QTextEditPrivate::updateDefaultTextOption()
+{
+ QTextDocument *doc = control->document();
+
+ QTextOption opt = doc->defaultTextOption();
+ QTextOption::WrapMode oldWrapMode = opt.wrapMode();
+
+ if (lineWrap == QTextEdit::NoWrap)
+ opt.setWrapMode(QTextOption::NoWrap);
+ else
+ opt.setWrapMode(wordWrap);
+
+ if (opt.wrapMode() != oldWrapMode)
+ doc->setDefaultTextOption(opt);
+}
+
+/*! \reimp
+*/
+void QTextEdit::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QTextEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
+ setEditFocus(true);
+#endif
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QTextEdit);
+ d->inDrag = false; // paranoia
+ const QPoint pos = e->pos();
+ d->sendControlEvent(e);
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+ QRect visible = d->viewport->rect();
+ if (visible.contains(pos))
+ d->autoScrollTimer.stop();
+ else if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+}
+
+/*! \reimp
+*/
+void QTextEdit::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QTextEdit);
+ d->sendControlEvent(e);
+ if (d->autoScrollTimer.isActive()) {
+ d->autoScrollTimer.stop();
+ ensureCursorVisible();
+ }
+ if (!isReadOnly() && rect().contains(e->pos()))
+ d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
+ d->clickCausedFocus = 0;
+}
+
+/*! \reimp
+*/
+void QTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ Q_D(QTextEdit);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+bool QTextEdit::focusNextPrevChild(bool next)
+{
+ Q_D(const QTextEdit);
+ if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
+ return false;
+ return QAbstractScrollArea::focusNextPrevChild(next);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+/*!
+ \fn void QTextEdit::contextMenuEvent(QContextMenuEvent *event)
+
+ Shows the standard context menu created with createStandardContextMenu().
+
+ If you do not want the text edit to have a context menu, you can set
+ its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
+ customize the context menu, reimplement this function. If you want
+ to extend the standard context menu, reimplement this function, call
+ createStandardContextMenu() and extend the menu returned.
+
+ Information about the event is passed in the \a event object.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 0
+*/
+void QTextEdit::contextMenuEvent(QContextMenuEvent *e)
+{
+ Q_D(QTextEdit);
+ d->sendControlEvent(e);
+}
+#endif // QT_NO_CONTEXTMENU
+
+#ifndef QT_NO_DRAGANDDROP
+/*! \reimp
+*/
+void QTextEdit::dragEnterEvent(QDragEnterEvent *e)
+{
+ Q_D(QTextEdit);
+ d->inDrag = true;
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
+{
+ Q_D(QTextEdit);
+ d->inDrag = false;
+ d->autoScrollTimer.stop();
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::dragMoveEvent(QDragMoveEvent *e)
+{
+ Q_D(QTextEdit);
+ d->autoScrollDragPos = e->pos();
+ if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::dropEvent(QDropEvent *e)
+{
+ Q_D(QTextEdit);
+ d->inDrag = false;
+ d->autoScrollTimer.stop();
+ d->sendControlEvent(e);
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*! \reimp
+ */
+void QTextEdit::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QTextEdit);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (d->control->textInteractionFlags() & Qt::TextEditable
+ && QApplication::keypadNavigationEnabled()
+ && !hasEditFocus())
+ setEditFocus(true);
+#endif
+ d->sendControlEvent(e);
+ ensureCursorVisible();
+}
+
+/*!\reimp
+*/
+void QTextEdit::scrollContentsBy(int dx, int dy)
+{
+ Q_D(QTextEdit);
+ if (isRightToLeft())
+ dx = -dx;
+ d->viewport->scroll(dx, dy);
+}
+
+/*!\reimp
+*/
+QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QTextEdit);
+ QVariant v = d->control->inputMethodQuery(property);
+ const QPoint offset(-d->horizontalOffset(), -d->verticalOffset());
+ if (v.type() == QVariant::RectF)
+ v = v.toRectF().toRect().translated(offset);
+ else if (v.type() == QVariant::PointF)
+ v = v.toPointF().toPoint() + offset;
+ else if (v.type() == QVariant::Rect)
+ v = v.toRect().translated(offset);
+ else if (v.type() == QVariant::Point)
+ v = v.toPoint() + offset;
+ return v;
+}
+
+/*! \reimp
+*/
+void QTextEdit::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QTextEdit);
+ if (e->reason() == Qt::MouseFocusReason) {
+ d->clickCausedFocus = 1;
+ }
+ QAbstractScrollArea::focusInEvent(e);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QTextEdit);
+ QAbstractScrollArea::focusOutEvent(e);
+ d->sendControlEvent(e);
+}
+
+/*! \reimp
+*/
+void QTextEdit::showEvent(QShowEvent *)
+{
+ Q_D(QTextEdit);
+ if (!d->anchorToScrollToWhenVisible.isEmpty()) {
+ scrollToAnchor(d->anchorToScrollToWhenVisible);
+ d->anchorToScrollToWhenVisible.clear();
+ d->showCursorOnInitialShow = false;
+ } else if (d->showCursorOnInitialShow) {
+ d->showCursorOnInitialShow = false;
+ ensureCursorVisible();
+ }
+}
+
+/*! \reimp
+*/
+void QTextEdit::changeEvent(QEvent *e)
+{
+ Q_D(QTextEdit);
+ QAbstractScrollArea::changeEvent(e);
+ if (e->type() == QEvent::ApplicationFontChange
+ || e->type() == QEvent::FontChange) {
+ d->control->document()->setDefaultFont(font());
+ } else if(e->type() == QEvent::ActivationChange) {
+ if (!isActiveWindow())
+ d->autoScrollTimer.stop();
+ } else if (e->type() == QEvent::EnabledChange) {
+ e->setAccepted(isEnabled());
+ d->control->setPalette(palette());
+ d->sendControlEvent(e);
+ } else if (e->type() == QEvent::PaletteChange) {
+ d->control->setPalette(palette());
+ } else if (e->type() == QEvent::LayoutDirectionChange) {
+ d->sendControlEvent(e);
+ }
+}
+
+/*! \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QTextEdit::wheelEvent(QWheelEvent *e)
+{
+ Q_D(QTextEdit);
+ if (!(d->control->textInteractionFlags() & Qt::TextEditable)) {
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ if (delta < 0)
+ zoomOut();
+ else if (delta > 0)
+ zoomIn();
+ return;
+ }
+ }
+ QAbstractScrollArea::wheelEvent(e);
+ updateMicroFocus();
+}
+#endif
+
+#ifndef QT_NO_CONTEXTMENU
+/*! This function creates the standard context menu which is shown
+ when the user clicks on the text edit with the right mouse
+ button. It is called from the default contextMenuEvent() handler.
+ The popup menu's ownership is transferred to the caller.
+
+ We recommend that you use the createStandardContextMenu(QPoint) version instead
+ which will enable the actions that are sensitive to where the user clicked.
+*/
+
+QMenu *QTextEdit::createStandardContextMenu()
+{
+ Q_D(QTextEdit);
+ return d->control->createStandardContextMenu(QPointF(), this);
+}
+
+/*!
+ \since 4.4
+ This function creates the standard context menu which is shown
+ when the user clicks on the text edit with the right mouse
+ button. It is called from the default contextMenuEvent() handler
+ and it takes the \a position of where the mouse click was.
+ This can enable actions that are sensitive to the position where the user clicked.
+ The popup menu's ownership is transferred to the caller.
+*/
+
+QMenu *QTextEdit::createStandardContextMenu(const QPoint &position)
+{
+ Q_D(QTextEdit);
+ return d->control->createStandardContextMenu(position, this);
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*!
+ returns a QTextCursor at position \a pos (in viewport coordinates).
+*/
+QTextCursor QTextEdit::cursorForPosition(const QPoint &pos) const
+{
+ Q_D(const QTextEdit);
+ return d->control->cursorForPosition(d->mapToContents(pos));
+}
+
+/*!
+ returns a rectangle (in viewport coordinates) that includes the
+ \a cursor.
+ */
+QRect QTextEdit::cursorRect(const QTextCursor &cursor) const
+{
+ Q_D(const QTextEdit);
+ if (cursor.isNull())
+ return QRect();
+
+ QRect r = d->control->cursorRect(cursor).toRect();
+ r.translate(-d->horizontalOffset(),-d->verticalOffset());
+ return r;
+}
+
+/*!
+ returns a rectangle (in viewport coordinates) that includes the
+ cursor of the text edit.
+ */
+QRect QTextEdit::cursorRect() const
+{
+ Q_D(const QTextEdit);
+ QRect r = d->control->cursorRect().toRect();
+ r.translate(-d->horizontalOffset(),-d->verticalOffset());
+ return r;
+}
+
+
+/*!
+ Returns the reference of the anchor at position \a pos, or an
+ empty string if no anchor exists at that point.
+*/
+QString QTextEdit::anchorAt(const QPoint& pos) const
+{
+ Q_D(const QTextEdit);
+ return d->control->anchorAt(d->mapToContents(pos));
+}
+
+/*!
+ \property QTextEdit::overwriteMode
+ \since 4.1
+ \brief whether text entered by the user will overwrite existing text
+
+ As with many text editors, the text editor widget can be configured
+ to insert or overwrite existing text with new text entered by the user.
+
+ If this property is true, existing text is overwritten, character-for-character
+ by new text; otherwise, text is inserted at the cursor position, displacing
+ existing text.
+
+ By default, this property is false (new text does not overwrite existing text).
+*/
+
+bool QTextEdit::overwriteMode() const
+{
+ Q_D(const QTextEdit);
+ return d->control->overwriteMode();
+}
+
+void QTextEdit::setOverwriteMode(bool overwrite)
+{
+ Q_D(QTextEdit);
+ d->control->setOverwriteMode(overwrite);
+}
+
+/*!
+ \property QTextEdit::tabStopWidth
+ \brief the tab stop width in pixels
+ \since 4.1
+
+ By default, this property contains a value of 80 pixels.
+*/
+
+int QTextEdit::tabStopWidth() const
+{
+ Q_D(const QTextEdit);
+ return qRound(d->control->document()->defaultTextOption().tabStop());
+}
+
+void QTextEdit::setTabStopWidth(int width)
+{
+ Q_D(QTextEdit);
+ QTextOption opt = d->control->document()->defaultTextOption();
+ if (opt.tabStop() == width || width < 0)
+ return;
+ opt.setTabStop(width);
+ d->control->document()->setDefaultTextOption(opt);
+}
+
+/*!
+ \since 4.2
+ \property QTextEdit::cursorWidth
+
+ This property specifies the width of the cursor in pixels. The default value is 1.
+*/
+int QTextEdit::cursorWidth() const
+{
+ Q_D(const QTextEdit);
+ return d->control->cursorWidth();
+}
+
+void QTextEdit::setCursorWidth(int width)
+{
+ Q_D(QTextEdit);
+ d->control->setCursorWidth(width);
+}
+
+/*!
+ \property QTextEdit::acceptRichText
+ \brief whether the text edit accepts rich text insertions by the user
+ \since 4.1
+
+ When this propery is set to false text edit will accept only
+ plain text input from the user. For example through clipboard or drag and drop.
+
+ This property's default is true.
+*/
+
+bool QTextEdit::acceptRichText() const
+{
+ Q_D(const QTextEdit);
+ return d->control->acceptRichText();
+}
+
+void QTextEdit::setAcceptRichText(bool accept)
+{
+ Q_D(QTextEdit);
+ d->control->setAcceptRichText(accept);
+}
+
+/*!
+ \class QTextEdit::ExtraSelection
+ \since 4.2
+ \brief The QTextEdit::ExtraSelection structure provides a way of specifying a
+ character format for a given selection in a document
+*/
+
+/*!
+ \variable QTextEdit::ExtraSelection::cursor
+ A cursor that contains a selection in a QTextDocument
+*/
+
+/*!
+ \variable QTextEdit::ExtraSelection::format
+ A format that is used to specify a foreground or background brush/color
+ for the selection.
+*/
+
+/*!
+ \since 4.2
+ This function allows temporarily marking certain regions in the document
+ with a given color, specified as \a selections. This can be useful for
+ example in a programming editor to mark a whole line of text with a given
+ background color to indicate the existence of a breakpoint.
+
+ \sa QTextEdit::ExtraSelection, extraSelections()
+*/
+void QTextEdit::setExtraSelections(const QList<ExtraSelection> &selections)
+{
+ Q_D(QTextEdit);
+ d->control->setExtraSelections(selections);
+}
+
+/*!
+ \since 4.2
+ Returns previously set extra selections.
+
+ \sa setExtraSelections()
+*/
+QList<QTextEdit::ExtraSelection> QTextEdit::extraSelections() const
+{
+ Q_D(const QTextEdit);
+ return d->control->extraSelections();
+}
+
+/*!
+ This function returns a new MIME data object to represent the contents
+ of the text edit's current selection. It is called when the selection needs
+ to be encapsulated into a new QMimeData object; for example, when a drag
+ and drop operation is started, or when data is copyied to the clipboard.
+
+ If you reimplement this function, note that the ownership of the returned
+ QMimeData object is passed to the caller. The selection can be retrieved
+ by using the textCursor() function.
+*/
+QMimeData *QTextEdit::createMimeDataFromSelection() const
+{
+ Q_D(const QTextEdit);
+ return d->control->QWidgetTextControl::createMimeDataFromSelection();
+}
+
+/*!
+ This function returns true if the contents of the MIME data object, specified
+ by \a source, can be decoded and inserted into the document. It is called
+ for example when during a drag operation the mouse enters this widget and it
+ is necessary to determine whether it is possible to accept the drag and drop
+ operation.
+
+ Reimplement this function to enable drag and drop support for additional MIME types.
+ */
+bool QTextEdit::canInsertFromMimeData(const QMimeData *source) const
+{
+ Q_D(const QTextEdit);
+ return d->control->QWidgetTextControl::canInsertFromMimeData(source);
+}
+
+/*!
+ This function inserts the contents of the MIME data object, specified
+ by \a source, into the text edit at the current cursor position. It is
+ called whenever text is inserted as the result of a clipboard paste
+ operation, or when the text edit accepts data from a drag and drop
+ operation.
+
+ Reimplement this function to enable drag and drop support for additional MIME types.
+ */
+void QTextEdit::insertFromMimeData(const QMimeData *source)
+{
+ Q_D(QTextEdit);
+ d->control->QWidgetTextControl::insertFromMimeData(source);
+}
+
+/*!
+ \property QTextEdit::readOnly
+ \brief whether the text edit is read-only
+
+ In a read-only text edit the user can only navigate through the
+ text and select text; modifying the text is not possible.
+
+ This property's default is false.
+*/
+
+bool QTextEdit::isReadOnly() const
+{
+ Q_D(const QTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+void QTextEdit::setReadOnly(bool ro)
+{
+ Q_D(QTextEdit);
+ Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
+ if (ro) {
+ flags = Qt::TextSelectableByMouse;
+#ifndef QT_NO_TEXTBROWSER
+ if (qobject_cast<QTextBrowser *>(this))
+ flags |= Qt::TextBrowserInteraction;
+#endif
+ } else {
+ flags = Qt::TextEditorInteraction;
+ }
+ d->control->setTextInteractionFlags(flags);
+ setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
+}
+
+/*!
+ \property QTextEdit::textInteractionFlags
+ \since 4.2
+
+ Specifies how the widget should interact with user input.
+
+ The default value depends on whether the QTextEdit is read-only
+ or editable, and whether it is a QTextBrowser or not.
+*/
+
+void QTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+Qt::TextInteractionFlags QTextEdit::textInteractionFlags() const
+{
+ Q_D(const QTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+/*!
+ Merges the properties specified in \a modifier into the current character
+ format by calling QTextCursor::mergeCharFormat on the editor's cursor.
+ If the editor has a selection then the properties of \a modifier are
+ directly applied to the selection.
+
+ \sa QTextCursor::mergeCharFormat()
+ */
+void QTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
+{
+ Q_D(QTextEdit);
+ d->control->mergeCurrentCharFormat(modifier);
+}
+
+/*!
+ Sets the char format that is be used when inserting new text to \a
+ format by calling QTextCursor::setCharFormat() on the editor's
+ cursor. If the editor has a selection then the char format is
+ directly applied to the selection.
+ */
+void QTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
+{
+ Q_D(QTextEdit);
+ d->control->setCurrentCharFormat(format);
+}
+
+/*!
+ Returns the char format that is used when inserting new text.
+ */
+QTextCharFormat QTextEdit::currentCharFormat() const
+{
+ Q_D(const QTextEdit);
+ return d->control->currentCharFormat();
+}
+
+/*!
+ \property QTextEdit::autoFormatting
+ \brief the enabled set of auto formatting features
+
+ The value can be any combination of the values in the
+ AutoFormattingFlag enum. The default is AutoNone. Choose
+ AutoAll to enable all automatic formatting.
+
+ Currently, the only automatic formatting feature provided is
+ AutoBulletList; future versions of Qt may offer more.
+*/
+
+QTextEdit::AutoFormatting QTextEdit::autoFormatting() const
+{
+ Q_D(const QTextEdit);
+ return d->autoFormatting;
+}
+
+void QTextEdit::setAutoFormatting(AutoFormatting features)
+{
+ Q_D(QTextEdit);
+ d->autoFormatting = features;
+}
+
+/*!
+ Convenience slot that inserts \a text at the current
+ cursor position.
+
+ It is equivalent to
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 1
+ */
+void QTextEdit::insertPlainText(const QString &text)
+{
+ Q_D(QTextEdit);
+ d->control->insertPlainText(text);
+}
+
+/*!
+ Convenience slot that inserts \a text which is assumed to be of
+ html formatting at the current cursor position.
+
+ It is equivalent to:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 2
+
+ \note When using this function with a style sheet, the style sheet will
+ only apply to the current block in the document. In order to apply a style
+ sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
+ instead.
+ */
+#ifndef QT_NO_TEXTHTMLPARSER
+void QTextEdit::insertHtml(const QString &text)
+{
+ Q_D(QTextEdit);
+ d->control->insertHtml(text);
+}
+#endif // QT_NO_TEXTHTMLPARSER
+
+/*!
+ Scrolls the text edit so that the anchor with the given \a name is
+ visible; does nothing if the \a name is empty, or is already
+ visible, or isn't found.
+*/
+void QTextEdit::scrollToAnchor(const QString &name)
+{
+ Q_D(QTextEdit);
+ if (name.isEmpty())
+ return;
+
+ if (!isVisible()) {
+ d->anchorToScrollToWhenVisible = name;
+ return;
+ }
+
+ QPointF p = d->control->anchorPosition(name);
+ const int newPosition = qRound(p.y());
+ if ( d->vbar->maximum() < newPosition )
+ d->_q_adjustScrollbars();
+ d->vbar->setValue(newPosition);
+}
+
+/*!
+ \fn QTextEdit::zoomIn(int range)
+
+ Zooms in on the text by making the base font size \a range
+ points larger and recalculating all font sizes to be the new size.
+ This does not change the size of any images.
+
+ \sa zoomOut()
+*/
+void QTextEdit::zoomIn(int range)
+{
+ QFont f = font();
+ const int newSize = f.pointSize() + range;
+ if (newSize <= 0)
+ return;
+ f.setPointSize(newSize);
+ setFont(f);
+}
+
+/*!
+ \fn QTextEdit::zoomOut(int range)
+
+ \overload
+
+ Zooms out on the text by making the base font size \a range points
+ smaller and recalculating all font sizes to be the new size. This
+ does not change the size of any images.
+
+ \sa zoomIn()
+*/
+void QTextEdit::zoomOut(int range)
+{
+ zoomIn(-range);
+}
+
+/*!
+ \since 4.2
+ Moves the cursor by performing the given \a operation.
+
+ If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
+ This is the same effect that the user achieves when they hold down the Shift key
+ and move the cursor with the cursor keys.
+
+ \sa QTextCursor::movePosition()
+*/
+void QTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
+{
+ Q_D(QTextEdit);
+ d->control->moveCursor(operation, mode);
+}
+
+/*!
+ \since 4.2
+ Returns whether text can be pasted from the clipboard into the textedit.
+*/
+bool QTextEdit::canPaste() const
+{
+ Q_D(const QTextEdit);
+ return d->control->canPaste();
+}
+
+/*!
+ \since 4.3
+ Convenience function to print the text edit's document to the given \a printer. This
+ is equivalent to calling the print method on the document directly except that this
+ function also supports QPrinter::Selection as print range.
+
+ \sa QTextDocument::print()
+*/
+void QTextEdit::print(QPagedPaintDevice *printer) const
+{
+ Q_D(const QTextEdit);
+ d->control->print(printer);
+}
+
+/*! \property QTextEdit::tabChangesFocus
+ \brief whether \gui Tab changes focus or is accepted as input
+
+ In some occasions text edits should not allow the user to input
+ tabulators or change indentation using the \gui Tab key, as this breaks
+ the focus chain. The default is false.
+
+*/
+
+bool QTextEdit::tabChangesFocus() const
+{
+ Q_D(const QTextEdit);
+ return d->tabChangesFocus;
+}
+
+void QTextEdit::setTabChangesFocus(bool b)
+{
+ Q_D(QTextEdit);
+ d->tabChangesFocus = b;
+}
+
+/*!
+ \property QTextEdit::documentTitle
+ \brief the title of the document parsed from the text.
+
+ By default, for a newly-created, empty document, this property contains
+ an empty string.
+*/
+
+/*!
+ \property QTextEdit::lineWrapMode
+ \brief the line wrap mode
+
+ The default mode is WidgetWidth which causes words to be
+ wrapped at the right edge of the text edit. Wrapping occurs at
+ whitespace, keeping whole words intact. If you want wrapping to
+ occur within words use setWordWrapMode(). If you set a wrap mode of
+ FixedPixelWidth or FixedColumnWidth you should also call
+ setLineWrapColumnOrWidth() with the width you want.
+
+ \sa lineWrapColumnOrWidth
+*/
+
+QTextEdit::LineWrapMode QTextEdit::lineWrapMode() const
+{
+ Q_D(const QTextEdit);
+ return d->lineWrap;
+}
+
+void QTextEdit::setLineWrapMode(LineWrapMode wrap)
+{
+ Q_D(QTextEdit);
+ if (d->lineWrap == wrap)
+ return;
+ d->lineWrap = wrap;
+ d->updateDefaultTextOption();
+ d->relayoutDocument();
+}
+
+/*!
+ \property QTextEdit::lineWrapColumnOrWidth
+ \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
+
+ If the wrap mode is FixedPixelWidth, the value is the number of
+ pixels from the left edge of the text edit at which text should be
+ wrapped. If the wrap mode is FixedColumnWidth, the value is the
+ column number (in character columns) from the left edge of the
+ text edit at which text should be wrapped.
+
+ By default, this property contains a value of 0.
+
+ \sa lineWrapMode
+*/
+
+int QTextEdit::lineWrapColumnOrWidth() const
+{
+ Q_D(const QTextEdit);
+ return d->lineWrapColumnOrWidth;
+}
+
+void QTextEdit::setLineWrapColumnOrWidth(int w)
+{
+ Q_D(QTextEdit);
+ d->lineWrapColumnOrWidth = w;
+ d->relayoutDocument();
+}
+
+/*!
+ \property QTextEdit::wordWrapMode
+ \brief the mode QTextEdit will use when wrapping text by words
+
+ By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
+
+ \sa QTextOption::WrapMode
+*/
+
+QTextOption::WrapMode QTextEdit::wordWrapMode() const
+{
+ Q_D(const QTextEdit);
+ return d->wordWrap;
+}
+
+void QTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
+{
+ Q_D(QTextEdit);
+ if (mode == d->wordWrap)
+ return;
+ d->wordWrap = mode;
+ d->updateDefaultTextOption();
+}
+
+/*!
+ Finds the next occurrence of the string, \a exp, using the given
+ \a options. Returns true if \a exp was found and changes the
+ cursor to select the match; otherwise returns false.
+*/
+bool QTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
+{
+ Q_D(QTextEdit);
+ return d->control->find(exp, options);
+}
+
+/*!
+ \fn void QTextEdit::copyAvailable(bool yes)
+
+ This signal is emitted when text is selected or de-selected in the
+ text edit.
+
+ When text is selected this signal will be emitted with \a yes set
+ to true. If no text has been selected or if the selected text is
+ de-selected this signal is emitted with \a yes set to false.
+
+ If \a yes is true then copy() can be used to copy the selection to
+ the clipboard. If \a yes is false then copy() does nothing.
+
+ \sa selectionChanged()
+*/
+
+/*!
+ \fn void QTextEdit::currentCharFormatChanged(const QTextCharFormat &f)
+
+ This signal is emitted if the current character format has changed, for
+ example caused by a change of the cursor position.
+
+ The new format is \a f.
+
+ \sa setCurrentCharFormat()
+*/
+
+/*!
+ \fn void QTextEdit::selectionChanged()
+
+ This signal is emitted whenever the selection changes.
+
+ \sa copyAvailable()
+*/
+
+/*!
+ \fn void QTextEdit::cursorPositionChanged()
+
+ This signal is emitted whenever the position of the
+ cursor changed.
+*/
+
+/*!
+ \since 4.2
+
+ Sets the text edit's \a text. The text can be plain text or HTML
+ and the text edit will try to guess the right format.
+
+ Use setHtml() or setPlainText() directly to avoid text edit's guessing.
+*/
+void QTextEdit::setText(const QString &text)
+{
+ Q_D(QTextEdit);
+ Qt::TextFormat format = d->textFormat;
+ if (d->textFormat == Qt::AutoText)
+ format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (format == Qt::RichText || format == Qt::LogText)
+ setHtml(text);
+ else
+#endif
+ setPlainText(text);
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use the QTextCursor class instead.
+*/
+void QTextEdit::moveCursor(CursorAction action, QTextCursor::MoveMode mode)
+{
+ Q_D(QTextEdit);
+ if (action == MovePageUp) {
+ d->pageUpDown(QTextCursor::Up, mode);
+ return;
+ } else if (action == MovePageDown) {
+ d->pageUpDown(QTextCursor::Down, mode);
+ return;
+ }
+
+ QTextCursor cursor = d->control->textCursor();
+ QTextCursor::MoveOperation op = QTextCursor::NoMove;
+ switch (action) {
+ case MoveBackward: op = QTextCursor::Left; break;
+ case MoveForward: op = QTextCursor::Right; break;
+ case MoveWordBackward: op = QTextCursor::WordLeft; break;
+ case MoveWordForward: op = QTextCursor::WordRight; break;
+ case MoveUp: op = QTextCursor::Up; break;
+ case MoveDown: op = QTextCursor::Down; break;
+ case MoveLineStart: op = QTextCursor::StartOfLine; break;
+ case MoveLineEnd: op = QTextCursor::EndOfLine; break;
+ case MoveHome: op = QTextCursor::Start; break;
+ case MoveEnd: op = QTextCursor::End; break;
+ default: return;
+ }
+ cursor.movePosition(op, mode);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Use the QTextCursor class instead.
+*/
+void QTextEdit::moveCursor(CursorAction action, bool select)
+{
+ moveCursor(action, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
+}
+
+/*!
+ Executes keyboard action \a action.
+
+ Use the QTextCursor class instead.
+
+ \sa textCursor()
+*/
+void QTextEdit::doKeyboardAction(KeyboardAction action)
+{
+ Q_D(QTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ switch (action) {
+ case ActionBackspace: cursor.deletePreviousChar(); break;
+ case ActionDelete: cursor.deleteChar(); break;
+ case ActionReturn: cursor.insertBlock(); break;
+ case ActionKill: {
+ QTextBlock block = cursor.block();
+ if (cursor.position() == block.position() + block.length() - 2)
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ else
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.deleteChar();
+ break;
+ }
+ case ActionWordBackspace:
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+ cursor.deletePreviousChar();
+ break;
+ case ActionWordDelete:
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ cursor.deleteChar();
+ break;
+ }
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Returns all the text in the text edit as plain text.
+*/
+QString QTextEdit::text() const
+{
+ Q_D(const QTextEdit);
+ if (d->textFormat == Qt::RichText || d->textFormat == Qt::LogText || (d->textFormat == Qt::AutoText && d->preferRichText))
+ return d->control->toHtml();
+ else
+ return d->control->toPlainText();
+}
+
+
+/*!
+ Sets the text format to format \a f.
+
+ \sa textFormat()
+*/
+void QTextEdit::setTextFormat(Qt::TextFormat f)
+{
+ Q_D(QTextEdit);
+ d->textFormat = f;
+}
+
+/*!
+ Returns the text format.
+
+ \sa setTextFormat()
+*/
+Qt::TextFormat QTextEdit::textFormat() const
+{
+ Q_D(const QTextEdit);
+ return d->textFormat;
+}
+
+#endif // QT3_SUPPORT
+
+/*!
+ Appends a new paragraph with \a text to the end of the text edit.
+
+ \note The new paragraph appended will have the same character format and
+ block format as the current paragraph, determined by the position of the cursor.
+
+ \sa currentCharFormat(), QTextCursor::blockFormat()
+*/
+
+void QTextEdit::append(const QString &text)
+{
+ Q_D(QTextEdit);
+ const bool atBottom = isReadOnly() ? d->verticalOffset() >= d->vbar->maximum() :
+ d->control->textCursor().atEnd();
+ d->control->append(text);
+ if (atBottom)
+ d->vbar->setValue(d->vbar->maximum());
+}
+
+/*!
+ Ensures that the cursor is visible by scrolling the text edit if
+ necessary.
+*/
+void QTextEdit::ensureCursorVisible()
+{
+ Q_D(QTextEdit);
+ d->control->ensureCursorVisible();
+}
+
+/*!
+ \enum QTextEdit::KeyboardAction
+
+ \compat
+
+ \value ActionBackspace
+ \value ActionDelete
+ \value ActionReturn
+ \value ActionKill
+ \value ActionWordBackspace
+ \value ActionWordDelete
+*/
+
+/*!
+ \fn bool QTextEdit::find(const QString &exp, bool cs, bool wo)
+
+ Use the find() overload that takes a QTextDocument::FindFlags
+ argument.
+*/
+
+/*!
+ \fn void QTextEdit::sync()
+
+ Does nothing.
+*/
+
+/*!
+ \fn void QTextEdit::setBold(bool b)
+
+ Use setFontWeight() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setUnderline(bool b)
+
+ Use setFontUnderline() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setItalic(bool i)
+
+ Use setFontItalic() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setFamily(const QString &family)
+
+ Use setFontFamily() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setPointSize(int size)
+
+ Use setFontPointSize() instead.
+*/
+
+/*!
+ \fn bool QTextEdit::italic() const
+
+ Use fontItalic() instead.
+*/
+
+/*!
+ \fn bool QTextEdit::bold() const
+
+ Use fontWeight() >= QFont::Bold instead.
+*/
+
+/*!
+ \fn bool QTextEdit::underline() const
+
+ Use fontUnderline() instead.
+*/
+
+/*!
+ \fn QString QTextEdit::family() const
+
+ Use fontFamily() instead.
+*/
+
+/*!
+ \fn int QTextEdit::pointSize() const
+
+ Use int(fontPointSize()+0.5) instead.
+*/
+
+/*!
+ \fn bool QTextEdit::hasSelectedText() const
+
+ Use textCursor().hasSelection() instead.
+*/
+
+/*!
+ \fn QString QTextEdit::selectedText() const
+
+ Use textCursor().selectedText() instead.
+*/
+
+/*!
+ \fn bool QTextEdit::isUndoAvailable() const
+
+ Use document()->isUndoAvailable() instead.
+*/
+
+/*!
+ \fn bool QTextEdit::isRedoAvailable() const
+
+ Use document()->isRedoAvailable() instead.
+*/
+
+/*!
+ \fn void QTextEdit::insert(const QString &text)
+
+ Use insertPlainText() instead.
+*/
+
+/*!
+ \fn bool QTextEdit::isModified() const
+
+ Use document()->isModified() instead.
+*/
+
+/*!
+ \fn QColor QTextEdit::color() const
+
+ Use textColor() instead.
+*/
+
+/*!
+ \fn void QTextEdit::textChanged()
+
+ This signal is emitted whenever the document's content changes; for
+ example, when text is inserted or deleted, or when formatting is applied.
+*/
+
+/*!
+ \fn void QTextEdit::undoAvailable(bool available)
+
+ This signal is emitted whenever undo operations become available
+ (\a available is true) or unavailable (\a available is false).
+*/
+
+/*!
+ \fn void QTextEdit::redoAvailable(bool available)
+
+ This signal is emitted whenever redo operations become available
+ (\a available is true) or unavailable (\a available is false).
+*/
+
+/*!
+ \fn void QTextEdit::currentFontChanged(const QFont &font)
+
+ Use currentCharFormatChanged() instead.
+*/
+
+/*!
+ \fn void QTextEdit::currentColorChanged(const QColor &color)
+
+ Use currentCharFormatChanged() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setModified(bool m)
+
+ Use document->setModified() instead.
+*/
+
+/*!
+ \fn void QTextEdit::setColor(const QColor &color)
+
+ Use setTextColor() instead.
+*/
+#endif // QT_NO_TEXTEDIT
+
+QT_END_NAMESPACE
+
+#include "moc_qtextedit.cpp"
diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h
new file mode 100644
index 0000000000..69f5ac23d5
--- /dev/null
+++ b/src/widgets/widgets/qtextedit.h
@@ -0,0 +1,430 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTEDIT_H
+#define QTEXTEDIT_H
+
+#include <QtWidgets/qabstractscrollarea.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextoption.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qtextformat.h>
+
+#ifndef QT_NO_TEXTEDIT
+
+#ifdef QT3_SUPPORT
+#include <QtGui/qtextobject.h>
+#include <QtGui/qtextlayout.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QStyleSheet;
+class QTextDocument;
+class QMenu;
+class QTextEditPrivate;
+class QMimeData;
+class QPagedPaintDevice;
+
+class Q_WIDGETS_EXPORT QTextEdit : public QAbstractScrollArea
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QTextEdit)
+ Q_FLAGS(AutoFormatting)
+ Q_ENUMS(LineWrapMode)
+ Q_PROPERTY(AutoFormatting autoFormatting READ autoFormatting WRITE setAutoFormatting)
+ Q_PROPERTY(bool tabChangesFocus READ tabChangesFocus WRITE setTabChangesFocus)
+ Q_PROPERTY(QString documentTitle READ documentTitle WRITE setDocumentTitle)
+ Q_PROPERTY(bool undoRedoEnabled READ isUndoRedoEnabled WRITE setUndoRedoEnabled)
+ Q_PROPERTY(LineWrapMode lineWrapMode READ lineWrapMode WRITE setLineWrapMode)
+ QDOC_PROPERTY(QTextOption::WrapMode wordWrapMode READ wordWrapMode WRITE setWordWrapMode)
+ Q_PROPERTY(int lineWrapColumnOrWidth READ lineWrapColumnOrWidth WRITE setLineWrapColumnOrWidth)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+#ifndef QT_NO_TEXTHTMLPARSER
+ Q_PROPERTY(QString html READ toHtml WRITE setHtml NOTIFY textChanged USER true)
+#endif
+ Q_PROPERTY(QString plainText READ toPlainText WRITE setPlainText DESIGNABLE false)
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
+ Q_PROPERTY(int tabStopWidth READ tabStopWidth WRITE setTabStopWidth)
+ Q_PROPERTY(bool acceptRichText READ acceptRichText WRITE setAcceptRichText)
+ Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
+ Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
+ Q_PROPERTY(QObject *document READ document)
+public:
+ enum LineWrapMode {
+ NoWrap,
+ WidgetWidth,
+ FixedPixelWidth,
+ FixedColumnWidth
+ };
+
+ enum AutoFormattingFlag {
+ AutoNone = 0,
+ AutoBulletList = 0x00000001,
+ AutoAll = 0xffffffff
+ };
+
+ Q_DECLARE_FLAGS(AutoFormatting, AutoFormattingFlag)
+
+#if defined(QT3_SUPPORT)
+ enum CursorAction {
+ MoveBackward,
+ MoveForward,
+ MoveWordBackward,
+ MoveWordForward,
+ MoveUp,
+ MoveDown,
+ MoveLineStart,
+ MoveLineEnd,
+ MoveHome,
+ MoveEnd,
+ MovePageUp,
+ MovePageDown
+#if !defined(Q_MOC_RUN)
+ ,
+ MovePgUp = MovePageUp,
+ MovePgDown = MovePageDown
+#endif
+ };
+#endif
+
+ explicit QTextEdit(QWidget *parent = 0);
+ explicit QTextEdit(const QString &text, QWidget *parent = 0);
+ virtual ~QTextEdit();
+
+ void setDocument(QTextDocument *document);
+ QTextDocument *document() const;
+
+ void setTextCursor(const QTextCursor &cursor);
+ QTextCursor textCursor() const;
+
+ bool isReadOnly() const;
+ void setReadOnly(bool ro);
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ qreal fontPointSize() const;
+ QString fontFamily() const;
+ int fontWeight() const;
+ bool fontUnderline() const;
+ bool fontItalic() const;
+ QColor textColor() const;
+ QColor textBackgroundColor() const;
+ QFont currentFont() const;
+ Qt::Alignment alignment() const;
+
+ void mergeCurrentCharFormat(const QTextCharFormat &modifier);
+
+ void setCurrentCharFormat(const QTextCharFormat &format);
+ QTextCharFormat currentCharFormat() const;
+
+ AutoFormatting autoFormatting() const;
+ void setAutoFormatting(AutoFormatting features);
+
+ bool tabChangesFocus() const;
+ void setTabChangesFocus(bool b);
+
+ inline void setDocumentTitle(const QString &title)
+ { document()->setMetaInformation(QTextDocument::DocumentTitle, title); }
+ inline QString documentTitle() const
+ { return document()->metaInformation(QTextDocument::DocumentTitle); }
+
+ inline bool isUndoRedoEnabled() const
+ { return document()->isUndoRedoEnabled(); }
+ inline void setUndoRedoEnabled(bool enable)
+ { document()->setUndoRedoEnabled(enable); }
+
+ LineWrapMode lineWrapMode() const;
+ void setLineWrapMode(LineWrapMode mode);
+
+ int lineWrapColumnOrWidth() const;
+ void setLineWrapColumnOrWidth(int w);
+
+ QTextOption::WrapMode wordWrapMode() const;
+ void setWordWrapMode(QTextOption::WrapMode policy);
+
+ bool find(const QString &exp, QTextDocument::FindFlags options = 0);
+
+ inline QString toPlainText() const
+ { return document()->toPlainText(); }
+#ifndef QT_NO_TEXTHTMLPARSER
+ inline QString toHtml() const
+ { return document()->toHtml(); }
+#endif
+
+ void ensureCursorVisible();
+
+ virtual QVariant loadResource(int type, const QUrl &name);
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *createStandardContextMenu();
+ QMenu *createStandardContextMenu(const QPoint &position);
+#endif
+
+ QTextCursor cursorForPosition(const QPoint &pos) const;
+ QRect cursorRect(const QTextCursor &cursor) const;
+ QRect cursorRect() const;
+
+ QString anchorAt(const QPoint& pos) const;
+
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
+
+ int tabStopWidth() const;
+ void setTabStopWidth(int width);
+
+ int cursorWidth() const;
+ void setCursorWidth(int width);
+
+ bool acceptRichText() const;
+ void setAcceptRichText(bool accept);
+
+ struct ExtraSelection
+ {
+ QTextCursor cursor;
+ QTextCharFormat format;
+ };
+ void setExtraSelections(const QList<ExtraSelection> &selections);
+ QList<ExtraSelection> extraSelections() const;
+
+ void moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+
+ bool canPaste() const;
+
+ void print(QPagedPaintDevice *printer) const;
+
+public Q_SLOTS:
+ void setFontPointSize(qreal s);
+ void setFontFamily(const QString &fontFamily);
+ void setFontWeight(int w);
+ void setFontUnderline(bool b);
+ void setFontItalic(bool b);
+ void setTextColor(const QColor &c);
+ void setTextBackgroundColor(const QColor &c);
+ void setCurrentFont(const QFont &f);
+ void setAlignment(Qt::Alignment a);
+
+ void setPlainText(const QString &text);
+#ifndef QT_NO_TEXTHTMLPARSER
+ void setHtml(const QString &text);
+#endif
+ void setText(const QString &text);
+
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+ void undo();
+ void redo();
+
+ void clear();
+ void selectAll();
+
+ void insertPlainText(const QString &text);
+#ifndef QT_NO_TEXTHTMLPARSER
+ void insertHtml(const QString &text);
+#endif // QT_NO_TEXTHTMLPARSER
+
+ void append(const QString &text);
+
+ void scrollToAnchor(const QString &name);
+
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+
+Q_SIGNALS:
+ void textChanged();
+ void undoAvailable(bool b);
+ void redoAvailable(bool b);
+ void currentCharFormatChanged(const QTextCharFormat &format);
+ void copyAvailable(bool b);
+ void selectionChanged();
+ void cursorPositionChanged();
+
+protected:
+ virtual bool event(QEvent *e);
+ virtual void timerEvent(QTimerEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+ virtual void keyReleaseEvent(QKeyEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void paintEvent(QPaintEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void mouseDoubleClickEvent(QMouseEvent *e);
+ virtual bool focusNextPrevChild(bool next);
+#ifndef QT_NO_CONTEXTMENU
+ virtual void contextMenuEvent(QContextMenuEvent *e);
+#endif
+#ifndef QT_NO_DRAGANDDROP
+ virtual void dragEnterEvent(QDragEnterEvent *e);
+ virtual void dragLeaveEvent(QDragLeaveEvent *e);
+ virtual void dragMoveEvent(QDragMoveEvent *e);
+ virtual void dropEvent(QDropEvent *e);
+#endif
+ virtual void focusInEvent(QFocusEvent *e);
+ virtual void focusOutEvent(QFocusEvent *e);
+ virtual void showEvent(QShowEvent *);
+ virtual void changeEvent(QEvent *e);
+#ifndef QT_NO_WHEELEVENT
+ virtual void wheelEvent(QWheelEvent *e);
+#endif
+
+ virtual QMimeData *createMimeDataFromSelection() const;
+ virtual bool canInsertFromMimeData(const QMimeData *source) const;
+ virtual void insertFromMimeData(const QMimeData *source);
+
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ QTextEdit(QTextEditPrivate &dd, QWidget *parent);
+
+ virtual void scrollContentsBy(int dx, int dy);
+
+#ifdef QT3_SUPPORT
+Q_SIGNALS:
+ QT_MOC_COMPAT void currentFontChanged(const QFont &f);
+ QT_MOC_COMPAT void currentColorChanged(const QColor &c);
+
+public:
+ QT3_SUPPORT_CONSTRUCTOR QTextEdit(QWidget *parent, const char *name);
+ inline QT3_SUPPORT bool find(const QString &exp, bool cs, bool wo)
+ {
+ QTextDocument::FindFlags flags = 0;
+ if (cs)
+ flags |= QTextDocument::FindCaseSensitively;
+ if (wo)
+ flags |= QTextDocument::FindWholeWords;
+ return find(exp, flags);
+ }
+
+ inline QT3_SUPPORT void sync() {}
+
+ QT3_SUPPORT void moveCursor(CursorAction action, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+ QT3_SUPPORT void moveCursor(CursorAction action, bool select);
+
+ enum KeyboardAction {
+ ActionBackspace,
+ ActionDelete,
+ ActionReturn,
+ ActionKill,
+ ActionWordBackspace,
+ ActionWordDelete
+ };
+
+ QT3_SUPPORT void doKeyboardAction(KeyboardAction action);
+
+ QT3_SUPPORT QString text() const;
+ QT3_SUPPORT void setTextFormat(Qt::TextFormat);
+ QT3_SUPPORT Qt::TextFormat textFormat() const;
+
+ inline QT3_SUPPORT void setBold(bool b) { setFontWeight(b ? QFont::Bold : QFont::Normal); }
+ inline QT3_SUPPORT void setUnderline(bool b) { setFontUnderline(b); }
+ inline QT3_SUPPORT void setItalic(bool i) { setFontItalic(i); }
+ inline QT3_SUPPORT void setFamily(const QString &family) { setFontFamily(family); }
+ inline QT3_SUPPORT void setPointSize(int size) { setFontPointSize(size); }
+
+ inline QT3_SUPPORT bool italic() const { return fontItalic(); }
+ inline QT3_SUPPORT bool bold() const { return fontWeight() >= QFont::Bold; }
+ inline QT3_SUPPORT bool underline() const { return fontUnderline(); }
+ inline QT3_SUPPORT QString family() const { return fontFamily(); }
+ inline QT3_SUPPORT int pointSize() const { return (int)(fontPointSize()+0.5); }
+
+ inline QT3_SUPPORT bool hasSelectedText() const
+ { return textCursor().hasSelection(); }
+ inline QT3_SUPPORT QString selectedText() const
+ { return textCursor().selectedText(); }
+
+ inline QT3_SUPPORT bool isUndoAvailable() const
+ { return document()->isUndoAvailable(); }
+ inline QT3_SUPPORT bool isRedoAvailable() const
+ { return document()->isRedoAvailable(); }
+
+ inline QT3_SUPPORT void insert(const QString &text)
+ { insertPlainText(text); }
+
+ inline QT3_SUPPORT bool isModified() const
+ { return document()->isModified(); }
+
+ inline QT3_SUPPORT QColor color() const
+ { return textColor(); }
+
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void setModified(bool m = true)
+ { document()->setModified(m); }
+public:
+ inline QT3_SUPPORT void undo() const
+ { document()->undo(); }
+ inline QT3_SUPPORT void redo() const
+ { document()->redo(); }
+
+public Q_SLOTS:
+ inline QT_MOC_COMPAT void setColor(const QColor &c)
+ { setTextColor(c); }
+
+#endif
+
+private:
+ Q_DISABLE_COPY(QTextEdit)
+ Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r))
+ Q_PRIVATE_SLOT(d_func(), void _q_currentCharFormatChanged(const QTextCharFormat &))
+ Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars())
+ Q_PRIVATE_SLOT(d_func(), void _q_ensureVisible(const QRectF &))
+ friend class QTextEditControl;
+ friend class QTextDocument;
+ friend class QWidgetTextControl;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEdit::AutoFormatting)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_TEXTEDIT
+
+#endif // QTEXTEDIT_H
diff --git a/src/widgets/widgets/qtextedit_p.h b/src/widgets/widgets/qtextedit_p.h
new file mode 100644
index 0000000000..3512c80ac4
--- /dev/null
+++ b/src/widgets/widgets/qtextedit_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTEDIT_P_H
+#define QTEXTEDIT_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/qabstractscrollarea_p.h"
+#include "QtGui/qtextdocumentfragment.h"
+#include "QtWidgets/qscrollbar.h"
+#include "QtGui/qtextcursor.h"
+#include "QtGui/qtextformat.h"
+#include "QtWidgets/qmenu.h"
+#include "QtGui/qabstracttextdocumentlayout.h"
+#include "QtCore/qbasictimer.h"
+#include "QtCore/qurl.h"
+#include "private/qwidgettextcontrol_p.h"
+#include "qtextedit.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TEXTEDIT
+
+class QMimeData;
+class QTextEditPrivate : public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QTextEdit)
+public:
+ QTextEditPrivate();
+
+ void init(const QString &html = QString());
+ void paint(QPainter *p, QPaintEvent *e);
+ void _q_repaintContents(const QRectF &contentsRect);
+
+ inline QPoint mapToContents(const QPoint &point) const
+ { return QPoint(point.x() + horizontalOffset(), point.y() + verticalOffset()); }
+
+ void _q_adjustScrollbars();
+ void _q_ensureVisible(const QRectF &rect);
+ void relayoutDocument();
+
+ void createAutoBulletList();
+ void pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode);
+
+ inline int horizontalOffset() const
+ { return q_func()->isRightToLeft() ? (hbar->maximum() - hbar->value()) : hbar->value(); }
+ inline int verticalOffset() const
+ { return vbar->value(); }
+
+ inline void sendControlEvent(QEvent *e)
+ { control->processEvent(e, QPointF(horizontalOffset(), verticalOffset()), viewport); }
+
+ void _q_currentCharFormatChanged(const QTextCharFormat &format);
+
+ void updateDefaultTextOption();
+
+ // re-implemented by QTextBrowser, called by QTextDocument::loadResource
+ virtual QUrl resolveUrl(const QUrl &url) const
+ { return url; }
+
+ QWidgetTextControl *control;
+
+ QTextEdit::AutoFormatting autoFormatting;
+ bool tabChangesFocus;
+
+ QBasicTimer autoScrollTimer;
+ QPoint autoScrollDragPos;
+
+ QTextEdit::LineWrapMode lineWrap;
+ int lineWrapColumnOrWidth;
+ QTextOption::WrapMode wordWrap;
+
+ uint ignoreAutomaticScrollbarAdjustment : 1;
+ uint preferRichText : 1;
+ uint showCursorOnInitialShow : 1;
+ uint inDrag : 1;
+ uint clickCausedFocus : 1;
+
+ // Qt3 COMPAT only, for setText
+ Qt::TextFormat textFormat;
+
+ QString anchorToScrollToWhenVisible;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ QBasicTimer deleteAllTimer;
+#endif
+};
+#endif // QT_NO_TEXTEDIT
+
+
+QT_END_NAMESPACE
+
+#endif // QTEXTEDIT_P_H
diff --git a/src/widgets/widgets/qtoolbar.cpp b/src/widgets/widgets/qtoolbar.cpp
new file mode 100644
index 0000000000..7527baa518
--- /dev/null
+++ b/src/widgets/widgets/qtoolbar.cpp
@@ -0,0 +1,1349 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtoolbar.h"
+
+#ifndef QT_NO_TOOLBAR
+
+#include <qapplication.h>
+#include <qcombobox.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qmainwindow.h>
+#include <qmenu.h>
+#include <qmenubar.h>
+#include <qrubberband.h>
+#include <qsignalmapper.h>
+#include <qstylepainter.h>
+#include <qtoolbutton.h>
+#include <qwidgetaction.h>
+#include <qtimer.h>
+#include <private/qwidgetaction_p.h>
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#include <private/qmainwindowlayout_p.h>
+
+#include "qtoolbar_p.h"
+#include "qtoolbarseparator_p.h"
+#include "qtoolbarlayout_p.h"
+
+#include "qdebug.h"
+
+#define POPUP_TIMER_INTERVAL 500
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_WS_MAC
+static void qt_mac_updateToolBarButtonHint(QWidget *parentWidget)
+{
+ if (!(parentWidget->windowFlags() & Qt::CustomizeWindowHint))
+ parentWidget->setWindowFlags(parentWidget->windowFlags() | Qt::MacWindowToolBarButtonHint);
+}
+#endif
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+/******************************************************************************
+** QToolBarPrivate
+*/
+
+void QToolBarPrivate::init()
+{
+ Q_Q(QToolBar);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
+ q->setBackgroundRole(QPalette::Button);
+ q->setAttribute(Qt::WA_Hover);
+ q->setAttribute(Qt::WA_X11NetWmWindowTypeToolBar);
+
+ QStyle *style = q->style();
+ int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, 0, q);
+ iconSize = QSize(e, e);
+
+ layout = new QToolBarLayout(q);
+ layout->updateMarginAndSpacing();
+
+#ifdef Q_WS_MAC
+ if (q->parentWidget() && q->parentWidget()->isWindow()) {
+ // Make sure that the window has the "toolbar" button.
+ QWidget *parentWidget = q->parentWidget();
+ qt_mac_updateToolBarButtonHint(parentWidget);
+ reinterpret_cast<QToolBar *>(parentWidget)->d_func()->createWinId(); // Please let me create your winId...
+ extern OSWindowRef qt_mac_window_for(const QWidget *); // qwidget_mac.cpp
+ macWindowToolbarShow(q->parentWidget(), true);
+ }
+#endif
+
+ toggleViewAction = new QAction(q);
+ toggleViewAction->setCheckable(true);
+ q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, 0, q ));
+ QObject::connect(toggleViewAction, SIGNAL(triggered(bool)), q, SLOT(_q_toggleView(bool)));
+}
+
+void QToolBarPrivate::_q_toggleView(bool b)
+{
+ Q_Q(QToolBar);
+ if (b == q->isHidden()) {
+ if (b)
+ q->show();
+ else
+ q->close();
+ }
+}
+
+void QToolBarPrivate::_q_updateIconSize(const QSize &sz)
+{
+ Q_Q(QToolBar);
+ if (!explicitIconSize) {
+ // iconSize not explicitly set
+ q->setIconSize(sz);
+ explicitIconSize = false;
+ }
+}
+
+void QToolBarPrivate::_q_updateToolButtonStyle(Qt::ToolButtonStyle style)
+{
+ Q_Q(QToolBar);
+ if (!explicitToolButtonStyle) {
+ q->setToolButtonStyle(style);
+ explicitToolButtonStyle = false;
+ }
+}
+
+void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug)
+{
+ Q_Q(QToolBar);
+ Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
+
+ flags |= Qt::FramelessWindowHint;
+
+ if (unplug) {
+ flags |= Qt::X11BypassWindowManagerHint;
+#ifdef Q_WS_MAC
+ flags |= Qt::WindowStaysOnTopHint;
+#endif
+ }
+
+ q->setWindowFlags(flags);
+}
+
+void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
+{
+ Q_Q(QToolBar);
+ bool visible = !q->isHidden();
+ bool wasFloating = q->isFloating(); // ...is also currently using popup menus
+
+ q->hide();
+
+ updateWindowFlags(floating, unplug);
+
+ if (floating != wasFloating)
+ layout->checkUsePopupMenu();
+
+ if (!rect.isNull())
+ q->setGeometry(rect);
+
+ if (visible)
+ q->show();
+
+ if (floating != wasFloating)
+ emit q->topLevelChanged(floating);
+}
+
+void QToolBarPrivate::initDrag(const QPoint &pos)
+{
+ Q_Q(QToolBar);
+
+ if (state != 0)
+ return;
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parent);
+ Q_ASSERT(win != 0);
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+ Q_ASSERT(layout != 0);
+ if (layout->pluggingWidget != 0) // the main window is animating a docking operation
+ return;
+
+ state = new DragState;
+ state->pressPos = pos;
+ state->dragging = false;
+ state->moving = false;
+ state->widgetItem = 0;
+
+ if (q->isRightToLeft())
+ state->pressPos = QPoint(q->width() - state->pressPos.x(), state->pressPos.y());
+}
+
+void QToolBarPrivate::startDrag(bool moving)
+{
+ Q_Q(QToolBar);
+
+ Q_ASSERT(state != 0);
+
+ if ((moving && state->moving) || state->dragging)
+ return;
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parent);
+ Q_ASSERT(win != 0);
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+ Q_ASSERT(layout != 0);
+
+ if (!moving) {
+ state->widgetItem = layout->unplug(q);
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ if (q->isWindow()) {
+ setWindowState(true, true); //set it to floating
+ }
+#endif
+ Q_ASSERT(state->widgetItem != 0);
+ }
+ state->dragging = !moving;
+ state->moving = moving;
+}
+
+void QToolBarPrivate::endDrag()
+{
+ Q_Q(QToolBar);
+ Q_ASSERT(state != 0);
+
+ q->releaseMouse();
+
+ if (state->dragging) {
+ QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
+ Q_ASSERT(layout != 0);
+
+ if (!layout->plug(state->widgetItem)) {
+ if (q->isFloatable()) {
+ layout->restore();
+#if defined(Q_WS_X11) || defined(Q_WS_MAC)
+ setWindowState(true); // gets rid of the X11BypassWindowManager window flag
+ // and activates the resizer
+#endif
+ q->activateWindow();
+ } else {
+ layout->revert(state->widgetItem);
+ }
+ }
+ }
+
+ delete state;
+ state = 0;
+}
+
+bool QToolBarPrivate::mousePressEvent(QMouseEvent *event)
+{
+ Q_Q(QToolBar);
+ QStyleOptionToolBar opt;
+ q->initStyleOption(&opt);
+ if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->pos()) == false) {
+#ifdef Q_WS_MAC
+ // When using the unified toolbar on Mac OS X the user can can click and
+ // drag between toolbar contents to move the window. Make this work by
+ // implementing the standard mouse-dragging code and then call
+ // window->move() in mouseMoveEvent below.
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent)) {
+ if (mainWindow->toolBarArea(q) == Qt::TopToolBarArea
+ && mainWindow->unifiedTitleAndToolBarOnMac()
+ && q->childAt(event->pos()) == 0) {
+ macWindowDragging = true;
+ macWindowDragPressPosition = event->pos();
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+
+ if (event->button() != Qt::LeftButton)
+ return true;
+
+ if (!layout->movable())
+ return true;
+
+ initDrag(event->pos());
+ return true;
+}
+
+bool QToolBarPrivate::mouseReleaseEvent(QMouseEvent*)
+{
+ if (state != 0) {
+ endDrag();
+ return true;
+ } else {
+#ifdef Q_WS_MAC
+ if (!macWindowDragging)
+ return false;
+ macWindowDragging = false;
+ macWindowDragPressPosition = QPoint();
+ return true;
+#endif
+ return false;
+ }
+}
+
+bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_Q(QToolBar);
+
+ if (!state) {
+#ifdef Q_WS_MAC
+ if (!macWindowDragging)
+ return false;
+ QWidget *w = q->window();
+ const QPoint delta = event->pos() - macWindowDragPressPosition;
+ w->move(w->pos() + delta);
+ return true;
+#endif
+ return false;
+ }
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parent);
+ if (win == 0)
+ return true;
+
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+ Q_ASSERT(layout != 0);
+
+ if (layout->pluggingWidget == 0
+ && (event->pos() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) {
+ const bool wasDragging = state->dragging;
+ const bool moving = !q->isWindow() && (orientation == Qt::Vertical ?
+ event->x() >= 0 && event->x() < q->width() :
+ event->y() >= 0 && event->y() < q->height());
+
+ startDrag(moving);
+ if (!moving && !wasDragging) {
+#ifdef Q_WS_WIN
+ grabMouseWhileInWindow();
+#else
+ q->grabMouse();
+#endif
+ }
+ }
+
+ if (state->dragging) {
+ QPoint pos = event->globalPos();
+ // if we are right-to-left, we move so as to keep the right edge the same distance
+ // from the mouse
+ if (q->isLeftToRight())
+ pos -= state->pressPos;
+ else
+ pos += QPoint(state->pressPos.x() - q->width(), -state->pressPos.y());
+
+ q->move(pos);
+ layout->hover(state->widgetItem, event->globalPos());
+ } else if (state->moving) {
+
+ const QPoint rtl(q->width() - state->pressPos.x(), state->pressPos.y()); //for RTL
+ const QPoint globalPressPos = q->mapToGlobal(q->isRightToLeft() ? rtl : state->pressPos);
+ int pos = 0;
+
+ QPoint delta = event->globalPos() - globalPressPos;
+ if (orientation == Qt::Vertical) {
+ pos = q->y() + delta.y();
+ } else {
+ if (q->isRightToLeft()) {
+ pos = win->width() - q->width() - q->x() - delta.x();
+ } else {
+ pos = q->x() + delta.x();
+ }
+ }
+
+ layout->moveToolBar(q, pos);
+ }
+ return true;
+}
+
+void QToolBarPrivate::unplug(const QRect &_r)
+{
+ Q_Q(QToolBar);
+ QRect r = _r;
+ r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
+ setWindowState(true, true, r);
+ layout->setExpanded(false);
+}
+
+void QToolBarPrivate::plug(const QRect &r)
+{
+ setWindowState(false, false, r);
+}
+
+/******************************************************************************
+** QToolBar
+*/
+
+/*!
+ \class QToolBar
+
+ \brief The QToolBar class provides a movable panel that contains a
+ set of controls.
+
+ \ingroup mainwindow-classes
+
+
+ Toolbar buttons are added by adding \e actions, using addAction()
+ or insertAction(). Groups of buttons can be separated using
+ addSeparator() or insertSeparator(). If a toolbar button is not
+ appropriate, a widget can be inserted instead using addWidget() or
+ insertWidget(); examples of suitable widgets are QSpinBox,
+ QDoubleSpinBox, and QComboBox. When a toolbar button is pressed it
+ emits the actionTriggered() signal.
+
+ A toolbar can be fixed in place in a particular area (e.g. at the
+ top of the window), or it can be movable (isMovable()) between
+ toolbar areas; see allowedAreas() and isAreaAllowed().
+
+ When a toolbar is resized in such a way that it is too small to
+ show all the items it contains, an extension button will appear as
+ the last item in the toolbar. Pressing the extension button will
+ pop up a menu containing the items that does not currently fit in
+ the toolbar.
+
+ When a QToolBar is not a child of a QMainWindow, it looses the ability
+ to populate the extension pop up with widgets added to the toolbar using
+ addWidget(). Please use widget actions created by inheriting QWidgetAction
+ and implementing QWidgetAction::createWidget() instead.
+
+ \sa QToolButton, QMenu, QAction, {Application Example}
+*/
+
+/*!
+ \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
+
+ Returns true if this toolbar is dockable in the given \a area;
+ otherwise returns false.
+*/
+
+/*!
+ \fn void QToolBar::addAction(QAction *action)
+ \overload
+
+ Appends the action \a action to the toolbar's list of actions.
+
+ \sa QMenu::addAction(), QWidget::addAction()
+*/
+
+/*!
+ \fn void QToolBar::actionTriggered(QAction *action)
+
+ This signal is emitted when an action in this toolbar is triggered.
+ This happens when the action's tool button is pressed, or when the
+ action is triggered in some other way outside the tool bar. The parameter
+ holds the triggered \a action.
+*/
+
+/*!
+ \fn void QToolBar::allowedAreasChanged(Qt::ToolBarAreas allowedAreas)
+
+ This signal is emitted when the collection of allowed areas for the
+ toolbar is changed. The new areas in which the toolbar can be positioned
+ are specified by \a allowedAreas.
+
+ \sa allowedAreas
+*/
+
+/*!
+ \fn void QToolBar::iconSizeChanged(const QSize &iconSize)
+
+ This signal is emitted when the icon size is changed. The \a
+ iconSize parameter holds the toolbar's new icon size.
+
+ \sa iconSize QMainWindow::iconSize
+*/
+
+/*!
+ \fn void QToolBar::movableChanged(bool movable)
+
+ This signal is emitted when the toolbar becomes movable or fixed.
+ If the toolbar can be moved, \a movable is true; otherwise it is
+ false.
+
+ \sa movable
+*/
+
+/*!
+ \fn void QToolBar::orientationChanged(Qt::Orientation orientation)
+
+ This signal is emitted when the orientation of the toolbar changes.
+ The new orientation is specified by the \a orientation given.
+
+ \sa orientation
+*/
+
+/*!
+ \fn void QToolBar::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
+
+ This signal is emitted when the tool button style is changed. The
+ \a toolButtonStyle parameter holds the toolbar's new tool button
+ style.
+
+ \sa toolButtonStyle QMainWindow::toolButtonStyle
+*/
+
+/*!
+ \since 4.6
+
+ \fn void QToolBar::topLevelChanged(bool topLevel)
+
+ This signal is emitted when the \l floating property changes.
+ The \a topLevel parameter is true if the toolbar is now floating;
+ otherwise it is false.
+
+ \sa isWindow()
+*/
+
+
+/*!
+ \fn void QToolBar::visibilityChanged(bool visible)
+ \since 4.7
+
+ This signal is emitted when the toolbar becomes \a visible (or
+ invisible). This happens when the widget is hidden or shown.
+*/
+
+/*!
+ Constructs a QToolBar with the given \a parent.
+*/
+QToolBar::QToolBar(QWidget *parent)
+ : QWidget(*new QToolBarPrivate, parent, 0)
+{
+ Q_D(QToolBar);
+ d->init();
+}
+
+/*!
+ Constructs a QToolBar with the given \a parent.
+
+ The given window \a title identifies the toolbar and is shown in
+ the context menu provided by QMainWindow.
+
+ \sa setWindowTitle()
+*/
+QToolBar::QToolBar(const QString &title, QWidget *parent)
+ : QWidget(*new QToolBarPrivate, parent, 0)
+{
+ Q_D(QToolBar);
+ d->init();
+ setWindowTitle(title);
+}
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+ Constructs a QToolBar with the given \a parent and \a name.
+*/
+QToolBar::QToolBar(QWidget *parent, const char *name)
+ : QWidget(*new QToolBarPrivate, parent, 0)
+{
+ Q_D(QToolBar);
+ d->init();
+ setObjectName(QString::fromAscii(name));
+}
+#endif
+
+/*!
+ Destroys the toolbar.
+*/
+QToolBar::~QToolBar()
+{
+ // Remove the toolbar button if there is nothing left.
+ QMainWindow *mainwindow = qobject_cast<QMainWindow *>(parentWidget());
+ if (mainwindow) {
+#ifdef Q_WS_MAC
+ QMainWindowLayout *mainwin_layout = qt_mainwindow_layout(mainwindow);
+ if (mainwin_layout && mainwin_layout->layoutState.toolBarAreaLayout.isEmpty()
+ && mainwindow->testAttribute(Qt::WA_WState_Created))
+ macWindowToolbarShow(mainwindow, false);
+#endif
+ }
+}
+
+/*! \property QToolBar::movable
+ \brief whether the user can move the toolbar within the toolbar area,
+ or between toolbar areas
+
+ By default, this property is true.
+
+ This property only makes sense if the toolbar is in a
+ QMainWindow.
+
+ \sa allowedAreas
+*/
+
+void QToolBar::setMovable(bool movable)
+{
+ Q_D(QToolBar);
+ if (!movable == !d->movable)
+ return;
+ d->movable = movable;
+ d->layout->invalidate();
+ emit movableChanged(d->movable);
+}
+
+bool QToolBar::isMovable() const
+{
+ Q_D(const QToolBar);
+ return d->movable;
+}
+
+/*!
+ \property QToolBar::floatable
+ \brief whether the toolbar can be dragged and dropped as an independent window.
+
+ The default is true.
+*/
+bool QToolBar::isFloatable() const
+{
+ Q_D(const QToolBar);
+ return d->floatable;
+}
+
+void QToolBar::setFloatable(bool floatable)
+{
+ Q_D(QToolBar);
+ d->floatable = floatable;
+}
+
+/*!
+ \property QToolBar::floating
+ \brief whether the toolbar is an independent window.
+
+ By default, this property is true.
+
+ \sa QWidget::isWindow()
+*/
+bool QToolBar::isFloating() const
+{
+ return isWindow();
+}
+
+/*!
+ \property QToolBar::allowedAreas
+ \brief areas where the toolbar may be placed
+
+ The default is Qt::AllToolBarAreas.
+
+ This property only makes sense if the toolbar is in a
+ QMainWindow.
+
+ \sa movable
+*/
+
+void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas)
+{
+ Q_D(QToolBar);
+ areas &= Qt::ToolBarArea_Mask;
+ if (areas == d->allowedAreas)
+ return;
+ d->allowedAreas = areas;
+ emit allowedAreasChanged(d->allowedAreas);
+}
+
+Qt::ToolBarAreas QToolBar::allowedAreas() const
+{
+ Q_D(const QToolBar);
+#ifdef Q_WS_MAC
+ if (QMainWindow *window = qobject_cast<QMainWindow *>(parentWidget())) {
+ if (window->unifiedTitleAndToolBarOnMac()) // Don't allow drags to the top (for now).
+ return (d->allowedAreas & ~Qt::TopToolBarArea);
+ }
+#endif
+ return d->allowedAreas;
+}
+
+/*! \property QToolBar::orientation
+ \brief orientation of the toolbar
+
+ The default is Qt::Horizontal.
+
+ This function should not be used when the toolbar is managed
+ by QMainWindow. You can use QMainWindow::addToolBar() or
+ QMainWindow::insertToolBar() if you wish to move a toolbar (that
+ is already added to a main window) to another Qt::ToolBarArea.
+*/
+
+void QToolBar::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QToolBar);
+ if (orientation == d->orientation)
+ return;
+
+ d->orientation = orientation;
+
+ if (orientation == Qt::Vertical)
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
+ else
+ setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
+
+ d->layout->invalidate();
+ d->layout->activate();
+
+ emit orientationChanged(d->orientation);
+}
+
+Qt::Orientation QToolBar::orientation() const
+{ Q_D(const QToolBar); return d->orientation; }
+
+/*!
+ \property QToolBar::iconSize
+ \brief size of icons in the toolbar.
+
+ The default size is determined by the application's style and is
+ derived from the QStyle::PM_ToolBarIconSize pixel metric. It is
+ the maximum size an icon can have. Icons of smaller size will not
+ be scaled up.
+*/
+
+QSize QToolBar::iconSize() const
+{ Q_D(const QToolBar); return d->iconSize; }
+
+void QToolBar::setIconSize(const QSize &iconSize)
+{
+ Q_D(QToolBar);
+ QSize sz = iconSize;
+ if (!sz.isValid()) {
+ QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget());
+ if (mw && mw->layout()) {
+ QLayout *layout = mw->layout();
+ int i = 0;
+ QLayoutItem *item = 0;
+ do {
+ item = layout->itemAt(i++);
+ if (item && (item->widget() == this))
+ sz = mw->iconSize();
+ } while (!sz.isValid() && item != 0);
+ }
+ }
+ if (!sz.isValid()) {
+ const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this);
+ sz = QSize(metric, metric);
+ }
+ if (d->iconSize != sz) {
+ d->iconSize = sz;
+ setMinimumSize(0, 0);
+ emit iconSizeChanged(d->iconSize);
+ }
+ d->explicitIconSize = iconSize.isValid();
+
+ d->layout->invalidate();
+}
+
+/*!
+ \property QToolBar::toolButtonStyle
+ \brief the style of toolbar buttons
+
+ This property defines the style of all tool buttons that are added
+ as \l{QAction}s. Note that if you add a QToolButton with the
+ addWidget() method, it will not get this button style.
+
+ The default is Qt::ToolButtonIconOnly.
+*/
+
+Qt::ToolButtonStyle QToolBar::toolButtonStyle() const
+{ Q_D(const QToolBar); return d->toolButtonStyle; }
+
+void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
+{
+ Q_D(QToolBar);
+ d->explicitToolButtonStyle = true;
+ if (d->toolButtonStyle == toolButtonStyle)
+ return;
+ d->toolButtonStyle = toolButtonStyle;
+ setMinimumSize(0, 0);
+ emit toolButtonStyleChanged(d->toolButtonStyle);
+}
+
+/*!
+ Removes all actions from the toolbar.
+
+ \sa removeAction()
+*/
+void QToolBar::clear()
+{
+ QList<QAction *> actions = this->actions();
+ for(int i = 0; i < actions.size(); i++)
+ removeAction(actions.at(i));
+}
+
+/*!
+ \overload
+
+ Creates a new action with the given \a text. This action is added to
+ the end of the toolbar.
+*/
+QAction *QToolBar::addAction(const QString &text)
+{
+ QAction *action = new QAction(text, this);
+ addAction(action);
+ return action;
+}
+
+/*!
+ \overload
+
+ Creates a new action with the given \a icon and \a text. This
+ action is added to the end of the toolbar.
+*/
+QAction *QToolBar::addAction(const QIcon &icon, const QString &text)
+{
+ QAction *action = new QAction(icon, text, this);
+ addAction(action);
+ return action;
+}
+
+/*!
+ \overload
+
+ Creates a new action with the given \a text. This action is added to
+ the end of the toolbar. The action's \link QAction::triggered()
+ triggered()\endlink signal is connected to \a member in \a
+ receiver.
+*/
+QAction *QToolBar::addAction(const QString &text,
+ const QObject *receiver, const char* member)
+{
+ QAction *action = new QAction(text, this);
+ QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
+ addAction(action);
+ return action;
+}
+
+/*!
+ \overload
+
+ Creates a new action with the icon \a icon and text \a text. This
+ action is added to the end of the toolbar. The action's \link
+ QAction::triggered() triggered()\endlink signal is connected to \a
+ member in \a receiver.
+*/
+QAction *QToolBar::addAction(const QIcon &icon, const QString &text,
+ const QObject *receiver, const char* member)
+{
+ QAction *action = new QAction(icon, text, this);
+ QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
+ addAction(action);
+ return action;
+}
+
+/*!
+ Adds a separator to the end of the toolbar.
+
+ \sa insertSeparator()
+*/
+QAction *QToolBar::addSeparator()
+{
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ addAction(action);
+ return action;
+}
+
+/*!
+ Inserts a separator into the toolbar in front of the toolbar
+ item associated with the \a before action.
+
+ \sa addSeparator()
+*/
+QAction *QToolBar::insertSeparator(QAction *before)
+{
+ QAction *action = new QAction(this);
+ action->setSeparator(true);
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ Adds the given \a widget to the toolbar as the toolbar's last
+ item.
+
+ The toolbar takes ownership of \a widget.
+
+ If you add a QToolButton with this method, the tools bar's
+ Qt::ToolButtonStyle will not be respected.
+
+ \note You should use QAction::setVisible() to change the
+ visibility of the widget. Using QWidget::setVisible(),
+ QWidget::show() and QWidget::hide() does not work.
+
+ \sa insertWidget()
+*/
+QAction *QToolBar::addWidget(QWidget *widget)
+{
+ QWidgetAction *action = new QWidgetAction(this);
+ action->setDefaultWidget(widget);
+ action->d_func()->autoCreated = true;
+ addAction(action);
+ return action;
+}
+
+/*!
+ Inserts the given \a widget in front of the toolbar item
+ associated with the \a before action.
+
+ Note: You should use QAction::setVisible() to change the
+ visibility of the widget. Using QWidget::setVisible(),
+ QWidget::show() and QWidget::hide() does not work.
+
+ \sa addWidget()
+*/
+QAction *QToolBar::insertWidget(QAction *before, QWidget *widget)
+{
+ QWidgetAction *action = new QWidgetAction(this);
+ action->setDefaultWidget(widget);
+ action->d_func()->autoCreated = true;
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ \internal
+
+ Returns the geometry of the toolbar item associated with the given
+ \a action, or an invalid QRect if no matching item is found.
+*/
+QRect QToolBar::actionGeometry(QAction *action) const
+{
+ Q_D(const QToolBar);
+
+ int index = d->layout->indexOf(action);
+ if (index == -1)
+ return QRect();
+ return d->layout->itemAt(index)->widget()->geometry();
+}
+
+/*!
+ Returns the action at point \a p. This function returns zero if no
+ action was found.
+
+ \sa QWidget::childAt()
+*/
+QAction *QToolBar::actionAt(const QPoint &p) const
+{
+ Q_D(const QToolBar);
+ QWidget *widget = childAt(p);
+ int index = d->layout->indexOf(widget);
+ if (index == -1)
+ return 0;
+ QLayoutItem *item = d->layout->itemAt(index);
+ return static_cast<QToolBarItem*>(item)->action;
+}
+
+/*! \fn QAction *QToolBar::actionAt(int x, int y) const
+ \overload
+
+ Returns the action at the point \a x, \a y. This function returns
+ zero if no action was found.
+*/
+
+/*! \reimp */
+void QToolBar::actionEvent(QActionEvent *event)
+{
+ Q_D(QToolBar);
+ QAction *action = event->action();
+ QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action);
+
+ switch (event->type()) {
+ case QEvent::ActionAdded: {
+ Q_ASSERT_X(widgetAction == 0 || d->layout->indexOf(widgetAction) == -1,
+ "QToolBar", "widgets cannot be inserted multiple times");
+
+ // reparent the action to this toolbar if it has been created
+ // using the addAction(text) etc. convenience functions, to
+ // preserve Qt 4.1.x behavior. The widget is already
+ // reparented to us due to the createWidget call inside
+ // createItem()
+ if (widgetAction != 0 && widgetAction->d_func()->autoCreated)
+ widgetAction->setParent(this);
+
+ int index = d->layout->count();
+ if (event->before()) {
+ index = d->layout->indexOf(event->before());
+ Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error");
+ }
+ d->layout->insertAction(index, action);
+ break;
+ }
+
+ case QEvent::ActionChanged:
+ d->layout->invalidate();
+ break;
+
+ case QEvent::ActionRemoved: {
+ int index = d->layout->indexOf(action);
+ if (index != -1) {
+ delete d->layout->takeAt(index);
+ }
+ break;
+ }
+
+ default:
+ Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error");
+ }
+}
+
+/*! \reimp */
+void QToolBar::changeEvent(QEvent *event)
+{
+ Q_D(QToolBar);
+ switch (event->type()) {
+ case QEvent::WindowTitleChange:
+ d->toggleViewAction->setText(windowTitle());
+ break;
+ case QEvent::StyleChange:
+ d->layout->invalidate();
+ if (!d->explicitIconSize)
+ setIconSize(QSize());
+ d->layout->updateMarginAndSpacing();
+ break;
+ case QEvent::LayoutDirectionChange:
+ d->layout->invalidate();
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(event);
+}
+
+/*! \reimp */
+void QToolBar::paintEvent(QPaintEvent *)
+{
+ Q_D(QToolBar);
+
+ QPainter p(this);
+ QStyle *style = this->style();
+ QStyleOptionToolBar opt;
+ initStyleOption(&opt);
+
+ if (d->layout->expanded || d->layout->animating || isWindow()) {
+ //if the toolbar is expended, we need to fill the background with the window color
+ //because some styles may expects that.
+ p.fillRect(opt.rect, palette().background());
+ style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
+ style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this);
+ } else {
+ style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
+ }
+
+ opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this);
+ if (opt.rect.isValid())
+ style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
+}
+
+/*
+ Checks if an expanded toolbar has to wait for this popup to close before
+ the toolbar collapses. This is true if
+ 1) the popup has the toolbar in its parent chain,
+ 2) the popup is a menu whose menuAction is somewhere in the toolbar.
+*/
+static bool waitForPopup(QToolBar *tb, QWidget *popup)
+{
+ if (popup == 0 || popup->isHidden())
+ return false;
+
+ QWidget *w = popup;
+ while (w != 0) {
+ if (w == tb)
+ return true;
+ w = w->parentWidget();
+ }
+
+ QMenu *menu = qobject_cast<QMenu*>(popup);
+ if (menu == 0)
+ return false;
+
+ QAction *action = menu->menuAction();
+ QList<QWidget*> widgets = action->associatedWidgets();
+ for (int i = 0; i < widgets.count(); ++i) {
+ if (waitForPopup(tb, widgets.at(i)))
+ return true;
+ }
+
+ return false;
+}
+
+#if defined(Q_WS_MAC)
+static bool toolbarInUnifiedToolBar(QToolBar *toolbar)
+{
+ const QMainWindow *mainWindow = qobject_cast<const QMainWindow *>(toolbar->parentWidget());
+ return mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()
+ && mainWindow->toolBarArea(toolbar) == Qt::TopToolBarArea;
+}
+#endif
+
+/*! \reimp */
+bool QToolBar::event(QEvent *event)
+{
+ Q_D(QToolBar);
+
+ switch (event->type()) {
+ case QEvent::Timer:
+ if (d->waitForPopupTimer.timerId() == static_cast<QTimerEvent*>(event)->timerId()) {
+ QWidget *w = QApplication::activePopupWidget();
+ if (!waitForPopup(this, w)) {
+ d->waitForPopupTimer.stop();
+ if (!this->underMouse())
+ d->layout->setExpanded(false);
+ }
+ }
+ break;
+ case QEvent::Hide:
+ if (!isHidden())
+ break;
+ // fallthrough intended
+ case QEvent::Show:
+ d->toggleViewAction->setChecked(event->type() == QEvent::Show);
+ emit visibilityChanged(event->type() == QEvent::Show);
+#if defined(Q_WS_MAC)
+ if (toolbarInUnifiedToolBar(this)) {
+ // I can static_cast because I did the qobject_cast in the if above, therefore
+ // we must have a QMainWindowLayout here.
+ QMainWindowLayout *mwLayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(parentWidget()));
+ mwLayout->fixSizeInUnifiedToolbar(this);
+ mwLayout->syncUnifiedToolbarVisibility();
+ }
+# if !defined(QT_MAC_USE_COCOA)
+ // Fall through
+ case QEvent::LayoutRequest: {
+ // There's currently no way to invalidate the size and let
+ // HIToolbar know about it. This forces a re-check.
+ int earlyResult = -1;
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget())) {
+ bool needUpdate = true;
+ if (event->type() == QEvent::LayoutRequest) {
+ QSize oldSizeHint = sizeHint();
+ earlyResult = QWidget::event(event) ? 1 : 0;
+ needUpdate = oldSizeHint != sizeHint();
+ }
+
+ if (needUpdate) {
+ OSWindowRef windowRef = qt_mac_window_for(mainWindow);
+ if (toolbarInUnifiedToolBar(this)
+ && macWindowToolbarIsVisible(windowRef)) {
+ DisableScreenUpdates();
+ macWindowToolbarShow(this, false);
+ macWindowToolbarShow(this, true);
+ EnableScreenUpdates();
+ }
+ }
+
+ if (earlyResult != -1)
+ return earlyResult;
+ }
+ }
+# endif // !QT_MAC_USE_COCOA
+#endif // Q_WS_MAC
+ break;
+ case QEvent::ParentChange:
+ d->layout->checkUsePopupMenu();
+#if defined(Q_WS_MAC)
+ if (parentWidget() && parentWidget()->isWindow())
+ qt_mac_updateToolBarButtonHint(parentWidget());
+#endif
+ break;
+
+ case QEvent::MouseButtonPress: {
+ if (d->mousePressEvent(static_cast<QMouseEvent*>(event)))
+ return true;
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ if (d->mouseReleaseEvent(static_cast<QMouseEvent*>(event)))
+ return true;
+ break;
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ // there's nothing special to do here and we don't want to update the whole widget
+ return true;
+ case QEvent::HoverMove: {
+#ifndef QT_NO_CURSOR
+ QHoverEvent *e = static_cast<QHoverEvent*>(event);
+ QStyleOptionToolBar opt;
+ initStyleOption(&opt);
+ if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos()))
+ setCursor(Qt::SizeAllCursor);
+ else
+ unsetCursor();
+#endif
+ break;
+ }
+ case QEvent::MouseMove:
+ if (d->mouseMoveEvent(static_cast<QMouseEvent*>(event)))
+ return true;
+ break;
+#ifdef Q_WS_WINCE
+ case QEvent::ContextMenu:
+ {
+ QContextMenuEvent* contextMenuEvent = static_cast<QContextMenuEvent*>(event);
+ QWidget* child = childAt(contextMenuEvent->pos());
+ QAbstractButton* button = qobject_cast<QAbstractButton*>(child);
+ if (button)
+ button->setDown(false);
+ }
+ break;
+#endif
+ case QEvent::Leave:
+ if (d->state != 0 && d->state->dragging) {
+#ifdef Q_OS_WIN
+ // This is a workaround for loosing the mouse on Vista.
+ QPoint pos = QCursor::pos();
+ QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ d->mouseMoveEvent(&fake);
+#endif
+ } else {
+ if (!d->layout->expanded)
+ break;
+
+ QWidget *w = QApplication::activePopupWidget();
+ if (waitForPopup(this, w)) {
+ d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this);
+ break;
+ }
+
+ d->waitForPopupTimer.stop();
+ d->layout->setExpanded(false);
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+/*!
+ Returns a checkable action that can be used to show or hide this
+ toolbar.
+
+ The action's text is set to the toolbar's window title.
+
+ \sa QAction::text QWidget::windowTitle
+*/
+QAction *QToolBar::toggleViewAction() const
+{ Q_D(const QToolBar); return d->toggleViewAction; }
+
+/*!
+ \fn void QToolBar::setLabel(const QString &label)
+
+ Use setWindowTitle() instead.
+*/
+
+/*!
+ \fn QString QToolBar::label() const
+
+ Use windowTitle() instead.
+*/
+
+/*!
+ \since 4.2
+
+ Returns the widget associated with the specified \a action.
+
+ \sa addWidget()
+*/
+QWidget *QToolBar::widgetForAction(QAction *action) const
+{
+ Q_D(const QToolBar);
+
+ int index = d->layout->indexOf(action);
+ if (index == -1)
+ return 0;
+
+ return d->layout->itemAt(index)->widget();
+}
+
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+/*!
+ \internal
+*/
+void QToolBar::initStyleOption(QStyleOptionToolBar *option) const
+{
+ Q_D(const QToolBar);
+
+ if (!option)
+ return;
+
+ option->initFrom(this);
+ if (orientation() == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+ option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this);
+ option->features = d->layout->movable()
+ ? QStyleOptionToolBar::Movable
+ : QStyleOptionToolBar::None;
+ // if the tool bar is not in a QMainWindow, this will make the painting right
+ option->toolBarArea = Qt::NoToolBarArea;
+
+ // Add more styleoptions if the toolbar has been added to a mainwindow.
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+
+ if (!mainWindow)
+ return;
+
+ QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT_X(layout != 0, "QToolBar::initStyleOption()",
+ "QMainWindow->layout() != QMainWindowLayout");
+
+ layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this));
+}
+
+/*!
+ \reimp
+*/
+void QToolBar::childEvent(QChildEvent *event) // ### remove me in 5.0
+{
+ QWidget::childEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QToolBar::resizeEvent(QResizeEvent *event) // ### remove me in 5.0
+{
+ QWidget::resizeEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtoolbar.cpp"
+
+#endif // QT_NO_TOOLBAR
diff --git a/src/widgets/widgets/qtoolbar.h b/src/widgets/widgets/qtoolbar.h
new file mode 100644
index 0000000000..98c44f059a
--- /dev/null
+++ b/src/widgets/widgets/qtoolbar.h
@@ -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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICTOOLBAR_H
+#define QDYNAMICTOOLBAR_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TOOLBAR
+
+class QToolBarPrivate;
+
+class QAction;
+class QIcon;
+class QMainWindow;
+class QStyleOptionToolBar;
+
+class Q_WIDGETS_EXPORT QToolBar : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool movable READ isMovable WRITE setMovable
+ DESIGNABLE (qobject_cast<QMainWindow *>(parentWidget()) != 0)
+ NOTIFY movableChanged)
+ Q_PROPERTY(Qt::ToolBarAreas allowedAreas READ allowedAreas WRITE setAllowedAreas
+ DESIGNABLE (qobject_cast<QMainWindow *>(parentWidget()) != 0)
+ NOTIFY allowedAreasChanged)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation
+ DESIGNABLE (qobject_cast<QMainWindow *>(parentWidget()) == 0)
+ NOTIFY orientationChanged)
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
+ Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle
+ NOTIFY toolButtonStyleChanged)
+ Q_PROPERTY(bool floating READ isFloating)
+ Q_PROPERTY(bool floatable READ isFloatable WRITE setFloatable)
+
+public:
+ explicit QToolBar(const QString &title, QWidget *parent = 0);
+ explicit QToolBar(QWidget *parent = 0);
+ ~QToolBar();
+
+ void setMovable(bool movable);
+ bool isMovable() const;
+
+ void setAllowedAreas(Qt::ToolBarAreas areas);
+ Qt::ToolBarAreas allowedAreas() const;
+
+ inline bool isAreaAllowed(Qt::ToolBarArea area) const
+ { return (allowedAreas() & area) == area; }
+
+ void setOrientation(Qt::Orientation orientation);
+ Qt::Orientation orientation() const;
+
+ void clear();
+
+#ifdef Q_NO_USING_KEYWORD
+ inline void addAction(QAction *action)
+ { QWidget::addAction(action); }
+#else
+ using QWidget::addAction;
+#endif
+
+ QAction *addAction(const QString &text);
+ QAction *addAction(const QIcon &icon, const QString &text);
+ QAction *addAction(const QString &text, const QObject *receiver, const char* member);
+ QAction *addAction(const QIcon &icon, const QString &text,
+ const QObject *receiver, const char* member);
+
+ QAction *addSeparator();
+ QAction *insertSeparator(QAction *before);
+
+ QAction *addWidget(QWidget *widget);
+ QAction *insertWidget(QAction *before, QWidget *widget);
+
+ QRect actionGeometry(QAction *action) const;
+ QAction *actionAt(const QPoint &p) const;
+ inline QAction *actionAt(int x, int y) const;
+
+ QAction *toggleViewAction() const;
+
+ QSize iconSize() const;
+ Qt::ToolButtonStyle toolButtonStyle() const;
+
+ QWidget *widgetForAction(QAction *action) const;
+
+ bool isFloatable() const;
+ void setFloatable(bool floatable);
+ bool isFloating() const;
+
+public Q_SLOTS:
+ void setIconSize(const QSize &iconSize);
+ void setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle);
+
+Q_SIGNALS:
+ void actionTriggered(QAction *action);
+ void movableChanged(bool movable);
+ void allowedAreasChanged(Qt::ToolBarAreas allowedAreas);
+ void orientationChanged(Qt::Orientation orientation);
+ void iconSizeChanged(const QSize &iconSize);
+ void toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle);
+ void topLevelChanged(bool topLevel);
+ void visibilityChanged(bool visible);
+
+protected:
+ void actionEvent(QActionEvent *event);
+ void changeEvent(QEvent *event);
+ void childEvent(QChildEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ bool event(QEvent *event);
+ void initStyleOption(QStyleOptionToolBar *option) const;
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QToolBar(QWidget *parent, const char *name);
+ inline QT3_SUPPORT void setLabel(const QString &label)
+ { setWindowTitle(label); }
+ inline QT3_SUPPORT QString label() const
+ { return windowTitle(); }
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QToolBar)
+ Q_DISABLE_COPY(QToolBar)
+ Q_PRIVATE_SLOT(d_func(), void _q_toggleView(bool))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateIconSize(const QSize &))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateToolButtonStyle(Qt::ToolButtonStyle))
+
+ friend class QMainWindow;
+ friend class QMainWindowLayout;
+ friend class QToolBarLayout;
+ friend class QToolBarAreaLayout;
+};
+
+inline QAction *QToolBar::actionAt(int ax, int ay) const
+{ return actionAt(QPoint(ax, ay)); }
+
+#endif // QT_NO_TOOLBAR
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDYNAMICTOOLBAR_H
diff --git a/src/widgets/widgets/qtoolbar_p.h b/src/widgets/widgets/qtoolbar_p.h
new file mode 100644
index 0000000000..70f1b6dca1
--- /dev/null
+++ b/src/widgets/widgets/qtoolbar_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICTOOLBAR_P_H
+#define QDYNAMICTOOLBAR_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 "qtoolbar.h"
+#include "QtWidgets/qaction.h"
+#include "private/qwidget_p.h"
+#include <QtCore/qbasictimer.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TOOLBAR
+
+class QToolBarLayout;
+class QTimer;
+
+class QToolBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QToolBar)
+
+public:
+ inline QToolBarPrivate()
+ : explicitIconSize(false), explicitToolButtonStyle(false), movable(true), floatable(true),
+ allowedAreas(Qt::AllToolBarAreas), orientation(Qt::Horizontal),
+ toolButtonStyle(Qt::ToolButtonIconOnly),
+ layout(0), state(0)
+#ifdef Q_WS_MAC
+ , macWindowDragging(false)
+#endif
+ { }
+
+ void init();
+ void actionTriggered();
+ void _q_toggleView(bool b);
+ void _q_updateIconSize(const QSize &sz);
+ void _q_updateToolButtonStyle(Qt::ToolButtonStyle style);
+
+ bool explicitIconSize;
+ bool explicitToolButtonStyle;
+ bool movable;
+ bool floatable;
+ Qt::ToolBarAreas allowedAreas;
+ Qt::Orientation orientation;
+ Qt::ToolButtonStyle toolButtonStyle;
+ QSize iconSize;
+
+ QAction *toggleViewAction;
+
+ QToolBarLayout *layout;
+
+ struct DragState {
+ QPoint pressPos;
+ bool dragging;
+ bool moving;
+ QLayoutItem *widgetItem;
+ };
+ DragState *state;
+
+#ifdef Q_WS_MAC
+ bool macWindowDragging;
+ QPoint macWindowDragPressPosition;
+#endif
+
+ bool mousePressEvent(QMouseEvent *e);
+ bool mouseReleaseEvent(QMouseEvent *e);
+ bool mouseMoveEvent(QMouseEvent *e);
+
+ void updateWindowFlags(bool floating, bool unplug = false);
+ void setWindowState(bool floating, bool unplug = false, const QRect &rect = QRect());
+ void initDrag(const QPoint &pos);
+ void startDrag(bool moving = false);
+ void endDrag();
+
+ void unplug(const QRect &r);
+ void plug(const QRect &r);
+
+ QBasicTimer waitForPopupTimer;
+};
+
+#endif // QT_NO_TOOLBAR
+
+QT_END_NAMESPACE
+
+#endif // QDYNAMICTOOLBAR_P_H
diff --git a/src/widgets/widgets/qtoolbararealayout.cpp b/src/widgets/widgets/qtoolbararealayout.cpp
new file mode 100644
index 0000000000..fbd5ef2cd7
--- /dev/null
+++ b/src/widgets/widgets/qtoolbararealayout.cpp
@@ -0,0 +1,1391 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWidgetItem>
+#include <QToolBar>
+#include <QStyleOption>
+#include <QApplication>
+#include <qdebug.h>
+
+#include "qtoolbararealayout_p.h"
+#include "qmainwindowlayout_p.h"
+#include "qwidgetanimator_p.h"
+#include "qtoolbarlayout_p.h"
+#include "qtoolbar_p.h"
+
+/******************************************************************************
+** QToolBarAreaLayoutItem
+*/
+
+#ifndef QT_NO_TOOLBAR
+
+QT_BEGIN_NAMESPACE
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow);
+
+QSize QToolBarAreaLayoutItem::minimumSize() const
+{
+ if (skip())
+ return QSize(0, 0);
+ return qSmartMinSize(static_cast<QWidgetItem*>(widgetItem));
+}
+
+QSize QToolBarAreaLayoutItem::sizeHint() const
+{
+ if (skip())
+ return QSize(0, 0);
+
+ return realSizeHint();
+}
+
+//returns the real size hint not taking into account the visibility of the widget
+QSize QToolBarAreaLayoutItem::realSizeHint() const
+{
+ QWidget *wid = widgetItem->widget();
+ QSize s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
+ if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
+ s.setWidth(0);
+ if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
+ s.setHeight(0);
+ s = s.boundedTo(wid->maximumSize())
+ .expandedTo(wid->minimumSize());
+ return s;
+}
+
+bool QToolBarAreaLayoutItem::skip() const
+{
+ if (gap)
+ return false;
+ return widgetItem == 0 || widgetItem->isEmpty();
+}
+
+/******************************************************************************
+** QToolBarAreaLayoutLine
+*/
+
+QToolBarAreaLayoutLine::QToolBarAreaLayoutLine(Qt::Orientation orientation)
+ : o(orientation)
+{
+}
+
+QSize QToolBarAreaLayoutLine::sizeHint() const
+{
+ int a = 0, b = 0;
+ for (int i = 0; i < toolBarItems.count(); ++i) {
+ const QToolBarAreaLayoutItem &item = toolBarItems.at(i);
+ if (item.skip())
+ continue;
+
+ QSize sh = item.sizeHint();
+ a += item.preferredSize > 0 ? item.preferredSize : pick(o, sh);
+ b = qMax(b, perp(o, sh));
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+ return result;
+}
+
+QSize QToolBarAreaLayoutLine::minimumSize() const
+{
+ int a = 0, b = 0;
+ for (int i = 0; i < toolBarItems.count(); ++i) {
+ const QToolBarAreaLayoutItem &item = toolBarItems[i];
+ if (item.skip())
+ continue;
+
+ QSize ms = item.minimumSize();
+ a += pick(o, ms);
+ b = qMax(b, perp(o, ms));
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+ return result;
+}
+
+void QToolBarAreaLayoutLine::fitLayout()
+{
+ int last = -1;
+ int min = pick(o, minimumSize());
+ int space = pick(o, rect.size());
+ int extra = qMax(0, space - min);
+
+ for (int i = 0; i < toolBarItems.count(); ++i) {
+ QToolBarAreaLayoutItem &item = toolBarItems[i];
+ if (item.skip())
+ continue;
+
+ if (QToolBarLayout *tblayout = qobject_cast<QToolBarLayout*>(item.widgetItem->widget()->layout()))
+ tblayout->checkUsePopupMenu();
+
+ const int itemMin = pick(o, item.minimumSize());
+ //preferredSize is the default if it is set, otherwise, we take the sizehint
+ item.size = item.preferredSize > 0 ? item.preferredSize : pick(o, item.sizeHint());
+
+ //the extraspace is the space above the item minimum sizehint
+ const int extraSpace = qMin(item.size - itemMin, extra);
+ item.size = itemMin + extraSpace; //that is the real size
+
+ extra -= extraSpace;
+
+ last = i;
+ }
+
+ // calculate the positions from the sizes
+ int pos = 0;
+ for (int i = 0; i < toolBarItems.count(); ++i) {
+ QToolBarAreaLayoutItem &item = toolBarItems[i];
+ if (item.skip())
+ continue;
+
+ item.pos = pos;
+ if (i == last) // stretch the last item to the end of the line
+ item.size = qMax(0, pick(o, rect.size()) - item.pos);
+ pos += item.size;
+ }
+}
+
+bool QToolBarAreaLayoutLine::skip() const
+{
+ for (int i = 0; i < toolBarItems.count(); ++i) {
+ if (!toolBarItems.at(i).skip())
+ return false;
+ }
+ return true;
+}
+
+/******************************************************************************
+** QToolBarAreaLayoutInfo
+*/
+
+QToolBarAreaLayoutInfo::QToolBarAreaLayoutInfo(QInternal::DockPosition pos)
+ : dockPos(pos), dirty(false)
+{
+ switch (pos) {
+ case QInternal::LeftDock:
+ case QInternal::RightDock:
+ o = Qt::Vertical;
+ break;
+ case QInternal::TopDock:
+ case QInternal::BottomDock:
+ o = Qt::Horizontal;
+ break;
+ default:
+ o = Qt::Horizontal;
+ break;
+ }
+}
+
+QSize QToolBarAreaLayoutInfo::sizeHint() const
+{
+ int a = 0, b = 0;
+ for (int i = 0; i < lines.count(); ++i) {
+ const QToolBarAreaLayoutLine &l = lines.at(i);
+ if (l.skip())
+ continue;
+
+ QSize hint = l.sizeHint();
+ a = qMax(a, pick(o, hint));
+ b += perp(o, hint);
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+ return result;
+}
+
+QSize QToolBarAreaLayoutInfo::minimumSize() const
+{
+ int a = 0, b = 0;
+ for (int i = 0; i < lines.count(); ++i) {
+ const QToolBarAreaLayoutLine &l = lines.at(i);
+ if (l.skip())
+ continue;
+
+ QSize m = l.minimumSize();
+ a = qMax(a, pick(o, m));
+ b += perp(o, m);
+ }
+
+ QSize result;
+ rpick(o, result) = a;
+ rperp(o, result) = b;
+
+ return result;
+}
+
+void QToolBarAreaLayoutInfo::fitLayout()
+{
+ dirty = false;
+
+ int b = 0;
+
+ bool reverse = dockPos == QInternal::RightDock || dockPos == QInternal::BottomDock;
+
+ int i = reverse ? lines.count() - 1 : 0;
+ for (;;) {
+ if ((reverse && i < 0) || (!reverse && i == lines.count()))
+ break;
+
+ QToolBarAreaLayoutLine &l = lines[i];
+ if (!l.skip()) {
+ if (o == Qt::Horizontal) {
+ l.rect.setLeft(rect.left());
+ l.rect.setRight(rect.right());
+ l.rect.setTop(b + rect.top());
+ b += l.sizeHint().height();
+ l.rect.setBottom(b - 1 + rect.top());
+ } else {
+ l.rect.setTop(rect.top());
+ l.rect.setBottom(rect.bottom());
+ l.rect.setLeft(b + rect.left());
+ b += l.sizeHint().width();
+ l.rect.setRight(b - 1 + rect.left());
+ }
+
+ l.fitLayout();
+ }
+
+ i += reverse ? -1 : 1;
+ }
+}
+
+QLayoutItem *QToolBarAreaLayoutInfo::insertToolBar(QToolBar *before, QToolBar *toolBar)
+{
+ toolBar->setOrientation(o);
+ QLayoutItem *item = new QWidgetItemV2(toolBar);
+ insertItem(before, item);
+ return item;
+}
+
+void QToolBarAreaLayoutInfo::insertItem(QToolBar *before, QLayoutItem *item)
+{
+ if (before == 0) {
+ if (lines.isEmpty())
+ lines.append(QToolBarAreaLayoutLine(o));
+ lines.last().toolBarItems.append(item);
+ return;
+ }
+
+ for (int j = 0; j < lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == before) {
+ line.toolBarItems.insert(k, item);
+ return;
+ }
+ }
+ }
+}
+
+void QToolBarAreaLayoutInfo::removeToolBar(QToolBar *toolBar)
+{
+ for (int j = 0; j < lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ QToolBarAreaLayoutItem &item = line.toolBarItems[k];
+ if (item.widgetItem->widget() == toolBar) {
+ delete item.widgetItem;
+ item.widgetItem = 0;
+ line.toolBarItems.removeAt(k);
+
+ if (line.toolBarItems.isEmpty() && j < lines.count() - 1)
+ lines.removeAt(j);
+
+ return;
+ }
+ }
+ }
+}
+
+void QToolBarAreaLayoutInfo::insertToolBarBreak(QToolBar *before)
+{
+ if (before == 0) {
+ if (!lines.isEmpty() && lines.last().toolBarItems.isEmpty())
+ return;
+ lines.append(QToolBarAreaLayoutLine(o));
+ return;
+ }
+
+ for (int j = 0; j < lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == before) {
+ if (k == 0)
+ return;
+
+ QToolBarAreaLayoutLine newLine(o);
+ newLine.toolBarItems = line.toolBarItems.mid(k);
+ line.toolBarItems = line.toolBarItems.mid(0, k);
+ lines.insert(j + 1, newLine);
+
+ return;
+ }
+ }
+ }
+}
+
+void QToolBarAreaLayoutInfo::removeToolBarBreak(QToolBar *before)
+{
+ for (int j = 0; j < lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == before) {
+ if (k != 0)
+ return;
+ if (j == 0)
+ return;
+
+ lines[j - 1].toolBarItems += lines[j].toolBarItems;
+ lines.removeAt(j);
+
+ return;
+ }
+ }
+ }
+}
+
+void QToolBarAreaLayoutInfo::moveToolBar(QToolBar *toolbar, int pos)
+{
+ if (dirty)
+ fitLayout();
+
+ dirty = true;
+
+ if (o == Qt::Vertical)
+ pos -= rect.top();
+
+ //here we actually update the preferredSize for the line containing the toolbar so that we move it
+ for (int j = 0; j < lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = lines[j];
+
+ int previousIndex = -1;
+ int minPos = 0;
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ QToolBarAreaLayoutItem &current = line.toolBarItems[k];
+ if (current.widgetItem->widget() == toolbar) {
+ int newPos = current.pos;
+
+ if (previousIndex >= 0) {
+ QToolBarAreaLayoutItem &previous = line.toolBarItems[previousIndex];
+ if (pos < current.pos) {
+ newPos = qMax(pos, minPos);
+ } else {
+ //we check the max value for the position (until everything at the right is "compressed")
+ int maxPos = pick(o, rect.size());
+ for(int l = k; l < line.toolBarItems.count(); ++l) {
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(l);
+ if (!item.skip()) {
+ maxPos -= pick(o, item.minimumSize());
+ }
+ }
+ newPos = qMin(pos, maxPos);
+ }
+
+ //extra is the number of pixels to add to the previous toolbar
+ int extra = newPos - current.pos;
+
+ //we check if the previous is near its size hint
+ //in which case we try to stick to it
+ const int diff = pick(o, previous.sizeHint()) - (previous.size + extra);
+ if (qAbs(diff) < QApplication::startDragDistance()) {
+ //we stick to the default place and size
+ extra += diff;
+ }
+
+ //update for the current item
+ current.extendSize(line.o, -extra);
+
+ if (extra >= 0) {
+ previous.extendSize(line.o, extra);
+ } else {
+ //we need to push the toolbars on the left starting with previous
+ extra = -extra; // we just need to know the number of pixels
+ ///at this point we need to get extra pixels from the toolbars at the left
+ for(int l = previousIndex; l >=0; --l) {
+ QToolBarAreaLayoutItem &item = line.toolBarItems[l];
+ if (!item.skip()) {
+ const int minPreferredSize = pick(o, item.minimumSize());
+ const int margin = item.size - minPreferredSize;
+ if (margin < extra) {
+ item.resize(line.o, minPreferredSize);
+ extra -= margin;
+ } else {
+ item.extendSize(line.o, -extra);
+ extra = 0;
+ }
+ }
+ }
+ Q_ASSERT(extra == 0);
+ }
+ } else {
+ //the item is the first one, it should be at position 0
+ }
+
+ return;
+
+ } else if (!current.skip()) {
+ previousIndex = k;
+ minPos += pick(o, current.minimumSize());
+ }
+ }
+ }
+}
+
+
+QList<int> QToolBarAreaLayoutInfo::gapIndex(const QPoint &pos, int *minDistance) const
+{
+ int p = pick(o, pos);
+
+ if (rect.contains(pos)) {
+ for (int j = 0; j < lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = lines.at(j);
+ if (line.skip())
+ continue;
+ if (!line.rect.contains(pos))
+ continue;
+
+ int k = 0;
+ for (; k < line.toolBarItems.count(); ++k) {
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
+ if (item.skip())
+ continue;
+
+ int size = qMin(item.size, pick(o, item.sizeHint()));
+
+ if (p > item.pos + size)
+ continue;
+ if (p > item.pos + size/2)
+ ++k;
+ break;
+ }
+
+ QList<int> result;
+ result << j << k;
+ *minDistance = 0; //we found a perfect match
+ return result;
+ }
+ } else {
+ const int dist = distance(pos);
+ //it will only return a path if the minDistance is higher than the current distance
+ if (dist >= 0 && *minDistance > dist) {
+ *minDistance = dist;
+
+ QList<int> result;
+ result << lines.count() << 0;
+ return result;
+ }
+ }
+
+ return QList<int>();
+}
+
+bool QToolBarAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *item)
+{
+ Q_ASSERT(path.count() == 2);
+ int j = path.first();
+ if (j == lines.count())
+ lines.append(QToolBarAreaLayoutLine(o));
+
+ QToolBarAreaLayoutLine &line = lines[j];
+ const int k = path.at(1);
+
+ QToolBarAreaLayoutItem gap_item;
+ gap_item.gap = true;
+ gap_item.widgetItem = item;
+
+ //update the previous item's preferred size
+ for(int p = k - 1 ; p >= 0; --p) {
+ QToolBarAreaLayoutItem &previous = line.toolBarItems[p];
+ if (!previous.skip()) {
+ //we found the previous one
+ int previousSizeHint = pick(line.o, previous.sizeHint());
+ int previousExtraSpace = previous.size - previousSizeHint;
+
+ if (previousExtraSpace > 0) {
+ //in this case we reset the space
+ previous.preferredSize = -1;
+ previous.size = previousSizeHint;
+
+ gap_item.resize(o, previousExtraSpace);
+ }
+
+ break;
+ }
+ }
+
+ line.toolBarItems.insert(k, gap_item);
+ return true;
+
+}
+
+void QToolBarAreaLayoutInfo::clear()
+{
+ lines.clear();
+ rect = QRect();
+}
+
+QRect QToolBarAreaLayoutInfo::itemRect(const QList<int> &path) const
+{
+ Q_ASSERT(path.count() == 2);
+ int j = path.at(0);
+ int k = path.at(1);
+
+ const QToolBarAreaLayoutLine &line = lines.at(j);
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
+
+ QRect result = line.rect;
+
+ if (o == Qt::Horizontal) {
+ result.setLeft(item.pos + line.rect.left());
+ result.setWidth(item.size);
+ } else {
+ result.setTop(item.pos + line.rect.top());
+ result.setHeight(item.size);
+ }
+
+ return result;
+}
+
+int QToolBarAreaLayoutInfo::distance(const QPoint &pos) const
+{
+ switch (dockPos) {
+ case QInternal::LeftDock:
+ if (pos.y() < rect.bottom())
+ return pos.x() - rect.right();
+ case QInternal::RightDock:
+ if (pos.y() < rect.bottom())
+ return rect.left() - pos.x();
+ case QInternal::TopDock:
+ if (pos.x() < rect.right())
+ return pos.y() - rect.bottom();
+ case QInternal::BottomDock:
+ if (pos.x() < rect.right())
+ return rect.top() - pos.y();
+ default:
+ break;
+ }
+ return -1;
+}
+
+/******************************************************************************
+** QToolBarAreaLayout
+*/
+
+QToolBarAreaLayout::QToolBarAreaLayout(const QMainWindow *win) : mainWindow(win), visible(true)
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QInternal::DockPosition pos = static_cast<QInternal::DockPosition>(i);
+ docks[i] = QToolBarAreaLayoutInfo(pos);
+ }
+}
+
+QRect QToolBarAreaLayout::fitLayout()
+{
+ if (!visible)
+ return rect;
+
+ QSize left_hint = docks[QInternal::LeftDock].sizeHint();
+ QSize right_hint = docks[QInternal::RightDock].sizeHint();
+ QSize top_hint = docks[QInternal::TopDock].sizeHint();
+ QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
+
+ QRect center = rect.adjusted(left_hint.width(), top_hint.height(),
+ -right_hint.width(), -bottom_hint.height());
+
+ docks[QInternal::TopDock].rect = QRect(rect.left(), rect.top(),
+ rect.width(), top_hint.height());
+ docks[QInternal::LeftDock].rect = QRect(rect.left(), center.top(),
+ left_hint.width(), center.height());
+ docks[QInternal::RightDock].rect = QRect(center.right() + 1, center.top(),
+ right_hint.width(), center.height());
+ docks[QInternal::BottomDock].rect = QRect(rect.left(), center.bottom() + 1,
+ rect.width(), bottom_hint.height());
+
+ if (!mainWindow->unifiedTitleAndToolBarOnMac()) {
+ docks[QInternal::TopDock].fitLayout();
+ }
+ docks[QInternal::LeftDock].fitLayout();
+ docks[QInternal::RightDock].fitLayout();
+ docks[QInternal::BottomDock].fitLayout();
+
+ return center;
+}
+
+QSize QToolBarAreaLayout::minimumSize(const QSize &centerMin) const
+{
+ if (!visible)
+ return centerMin;
+
+ QSize result = centerMin;
+
+ QSize left_min = docks[QInternal::LeftDock].minimumSize();
+ QSize right_min = docks[QInternal::RightDock].minimumSize();
+ QSize top_min = docks[QInternal::TopDock].minimumSize();
+ QSize bottom_min = docks[QInternal::BottomDock].minimumSize();
+
+ result.setWidth(qMax(top_min.width(), result.width()));
+ result.setWidth(qMax(bottom_min.width(), result.width()));
+ result.setHeight(qMax(left_min.height(), result.height()));
+ result.setHeight(qMax(right_min.height(), result.height()));
+
+ result.rwidth() += left_min.width() + right_min.width();
+ result.rheight() += top_min.height() + bottom_min.height();
+
+ return result;
+}
+
+QSize QToolBarAreaLayout::sizeHint(const QSize &centerHint) const
+{
+ if (!visible)
+ return centerHint;
+
+ QSize result = centerHint;
+
+ QSize left_hint = docks[QInternal::LeftDock].sizeHint();
+ QSize right_hint = docks[QInternal::RightDock].sizeHint();
+ QSize top_hint = docks[QInternal::TopDock].sizeHint();
+ QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
+
+ result.setWidth(qMax(top_hint.width(), result.width()));
+ result.setWidth(qMax(bottom_hint.width(), result.width()));
+ result.setHeight(qMax(left_hint.height(), result.height()));
+ result.setHeight(qMax(right_hint.height(), result.height()));
+
+ result.rwidth() += left_hint.width() + right_hint.width();
+ result.rheight() += top_hint.height() + bottom_hint.height();
+
+ return result;
+}
+
+QRect QToolBarAreaLayout::rectHint(const QRect &r) const
+{
+ int coef = visible ? 1 : -1;
+
+ QRect result = r;
+
+ QSize left_hint = docks[QInternal::LeftDock].sizeHint();
+ QSize right_hint = docks[QInternal::RightDock].sizeHint();
+ QSize top_hint = docks[QInternal::TopDock].sizeHint();
+ QSize bottom_hint = docks[QInternal::BottomDock].sizeHint();
+
+ result.adjust(-left_hint.width()*coef, -top_hint.height()*coef,
+ right_hint.width()*coef, bottom_hint.height()*coef);
+
+ return result;
+}
+
+QLayoutItem *QToolBarAreaLayout::itemAt(int *x, int index) const
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if ((*x)++ == index)
+ return line.toolBarItems.at(k).widgetItem;
+ }
+ }
+ }
+
+ return 0;
+}
+
+QLayoutItem *QToolBarAreaLayout::takeAt(int *x, int index)
+{
+ Q_ASSERT(x != 0);
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = dock.lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if ((*x)++ == index) {
+ QLayoutItem *result = line.toolBarItems.takeAt(k).widgetItem;
+ if (line.toolBarItems.isEmpty())
+ dock.lines.removeAt(j);
+ return result;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void QToolBarAreaLayout::deleteAllLayoutItems()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = dock.lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ QToolBarAreaLayoutItem &item = line.toolBarItems[k];
+ if (!item.gap)
+ delete item.widgetItem;
+ item.widgetItem = 0;
+ }
+ }
+ }
+}
+
+QInternal::DockPosition QToolBarAreaLayout::findToolBar(QToolBar *toolBar) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
+ return static_cast<QInternal::DockPosition>(i);
+ }
+ }
+ }
+
+ return QInternal::DockCount;
+}
+
+QLayoutItem *QToolBarAreaLayout::insertToolBar(QToolBar *before, QToolBar *toolBar)
+{
+ QInternal::DockPosition pos = findToolBar(before);
+ if (pos == QInternal::DockCount)
+ return 0;
+
+ return docks[pos].insertToolBar(before, toolBar);
+}
+
+void QToolBarAreaLayout::removeToolBar(QToolBar *toolBar)
+{
+ QInternal::DockPosition pos = findToolBar(toolBar);
+ if (pos == QInternal::DockCount)
+ return;
+ docks[pos].removeToolBar(toolBar);
+}
+
+QLayoutItem *QToolBarAreaLayout::addToolBar(QInternal::DockPosition pos, QToolBar *toolBar)
+{
+ return docks[pos].insertToolBar(0, toolBar);
+}
+
+void QToolBarAreaLayout::insertToolBarBreak(QToolBar *before)
+{
+ QInternal::DockPosition pos = findToolBar(before);
+ if (pos == QInternal::DockCount)
+ return;
+ docks[pos].insertToolBarBreak(before);
+}
+
+void QToolBarAreaLayout::removeToolBarBreak(QToolBar *before)
+{
+ QInternal::DockPosition pos = findToolBar(before);
+ if (pos == QInternal::DockCount)
+ return;
+ docks[pos].removeToolBarBreak(before);
+}
+
+void QToolBarAreaLayout::addToolBarBreak(QInternal::DockPosition pos)
+{
+ docks[pos].insertToolBarBreak(0);
+}
+
+void QToolBarAreaLayout::moveToolBar(QToolBar *toolbar, int p)
+{
+ QInternal::DockPosition pos = findToolBar(toolbar);
+ if (pos == QInternal::DockCount)
+ return;
+ docks[pos].moveToolBar(toolbar, p);
+}
+
+
+void QToolBarAreaLayout::insertItem(QInternal::DockPosition pos, QLayoutItem *item)
+{
+ if (docks[pos].lines.isEmpty())
+ docks[pos].lines.append(QToolBarAreaLayoutLine(docks[pos].o));
+ docks[pos].lines.last().toolBarItems.append(item);
+}
+
+void QToolBarAreaLayout::insertItem(QToolBar *before, QLayoutItem *item)
+{
+ QInternal::DockPosition pos = findToolBar(before);
+ if (pos == QInternal::DockCount)
+ return;
+
+ docks[pos].insertItem(before, item);
+}
+
+void QToolBarAreaLayout::apply(bool animate)
+{
+ QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT(layout != 0);
+
+ Qt::LayoutDirection dir = mainWindow->layoutDirection();
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+ if (line.skip())
+ continue;
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
+ if (item.skip() || item.gap)
+ continue;
+
+ QRect geo;
+ if (visible) {
+ if (line.o == Qt::Horizontal) {
+ geo.setTop(line.rect.top());
+ geo.setBottom(line.rect.bottom());
+ geo.setLeft(line.rect.left() + item.pos);
+ geo.setRight(line.rect.left() + item.pos + item.size - 1);
+ } else {
+ geo.setLeft(line.rect.left());
+ geo.setRight(line.rect.right());
+ geo.setTop(line.rect.top() + item.pos);
+ geo.setBottom(line.rect.top() + item.pos + item.size - 1);
+ }
+ }
+
+ QWidget *widget = item.widgetItem->widget();
+ if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
+ QToolBarLayout *tbl = qobject_cast<QToolBarLayout*>(toolBar->layout());
+ if (tbl->expanded) {
+ QPoint tr = geo.topRight();
+ QSize size = tbl->expandedSize(geo.size());
+ geo.setSize(size);
+ geo.moveTopRight(tr);
+ if (geo.bottom() > rect.bottom())
+ geo.moveBottom(rect.bottom());
+ if (geo.right() > rect.right())
+ geo.moveRight(rect.right());
+ if (geo.left() < 0)
+ geo.moveLeft(0);
+ if (geo.top() < 0)
+ geo.moveTop(0);
+ }
+ }
+
+ if (visible && dock.o == Qt::Horizontal)
+ geo = QStyle::visualRect(dir, line.rect, geo);
+
+ layout->widgetAnimator.animate(widget, geo, animate);
+ }
+ }
+ }
+}
+
+bool QToolBarAreaLayout::toolBarBreak(QToolBar *toolBar) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == toolBar)
+ return j > 0 && k == 0;
+ }
+ }
+ }
+
+ return false;
+}
+
+void QToolBarAreaLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ if (line.toolBarItems.at(k).widgetItem->widget() == toolBar) {
+ if (line.toolBarItems.count() == 1)
+ option->positionWithinLine = QStyleOptionToolBar::OnlyOne;
+ else if (k == 0)
+ option->positionWithinLine = QStyleOptionToolBar::Beginning;
+ else if (k == line.toolBarItems.count() - 1)
+ option->positionWithinLine = QStyleOptionToolBar::End;
+ else
+ option->positionWithinLine = QStyleOptionToolBar::Middle;
+
+ if (dock.lines.count() == 1)
+ option->positionOfLine = QStyleOptionToolBar::OnlyOne;
+ else if (j == 0)
+ option->positionOfLine = QStyleOptionToolBar::Beginning;
+ else if (j == dock.lines.count() - 1)
+ option->positionOfLine = QStyleOptionToolBar::End;
+ else
+ option->positionOfLine = QStyleOptionToolBar::Middle;
+
+ return;
+ }
+ }
+ }
+ }
+}
+
+QList<int> QToolBarAreaLayout::indexOf(QWidget *toolBar) const
+{
+ QList<int> result;
+
+ bool found = false;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
+ if (!item.gap && item.widgetItem->widget() == toolBar) {
+ found = true;
+ result.prepend(k);
+ break;
+ }
+ }
+
+ if (found) {
+ result.prepend(j);
+ break;
+ }
+ }
+
+ if (found) {
+ result.prepend(i);
+ break;
+ }
+ }
+
+ return result;
+}
+
+//this functions returns the path to the possible gapindex for the position pos
+QList<int> QToolBarAreaLayout::gapIndex(const QPoint &pos) const
+{
+ Qt::LayoutDirection dir = mainWindow->layoutDirection();
+ int minDistance = 80; // when a dock area is empty, how "wide" is it?
+ QList<int> ret; //return value
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QPoint p = pos;
+ if (docks[i].o == Qt::Horizontal)
+ p = QStyle::visualPos(dir, docks[i].rect, p);
+ QList<int> result = docks[i].gapIndex(p, &minDistance);
+ if (!result.isEmpty()) {
+ result.prepend(i);
+ ret = result;
+ }
+ }
+
+ return ret;
+}
+
+QList<int> QToolBarAreaLayout::currentGapIndex() const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); k++) {
+ if (line.toolBarItems[k].gap) {
+ QList<int> result;
+ result << i << j << k;
+ return result;
+ }
+ }
+ }
+ }
+ return QList<int>();
+}
+
+bool QToolBarAreaLayout::insertGap(const QList<int> &path, QLayoutItem *item)
+{
+ Q_ASSERT(path.count() == 3);
+ const int i = path.first();
+ Q_ASSERT(i >= 0 && i < QInternal::DockCount);
+ return docks[i].insertGap(path.mid(1), item);
+}
+
+void QToolBarAreaLayout::remove(const QList<int> &path)
+{
+ Q_ASSERT(path.count() == 3);
+ docks[path.at(0)].lines[path.at(1)].toolBarItems.removeAt(path.at(2));
+}
+
+void QToolBarAreaLayout::remove(QLayoutItem *item)
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ QToolBarAreaLayoutLine &line = dock.lines[j];
+
+ for (int k = 0; k < line.toolBarItems.count(); k++) {
+ if (line.toolBarItems[k].widgetItem == item) {
+ line.toolBarItems.removeAt(k);
+ if (line.toolBarItems.isEmpty())
+ dock.lines.removeAt(j);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void QToolBarAreaLayout::clear()
+{
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ docks[i].clear();
+ rect = QRect();
+}
+
+QToolBarAreaLayoutItem &QToolBarAreaLayout::item(const QList<int> &path)
+{
+ Q_ASSERT(path.count() == 3);
+
+ Q_ASSERT(path.at(0) >= 0 && path.at(0) < QInternal::DockCount);
+ QToolBarAreaLayoutInfo &info = docks[path.at(0)];
+ Q_ASSERT(path.at(1) >= 0 && path.at(1) < info.lines.count());
+ QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
+ Q_ASSERT(path.at(2) >= 0 && path.at(2) < line.toolBarItems.count());
+ return line.toolBarItems[path.at(2)];
+}
+
+QRect QToolBarAreaLayout::itemRect(const QList<int> &path) const
+{
+ const int i = path.first();
+
+ QRect r = docks[i].itemRect(path.mid(1));
+ if (docks[i].o == Qt::Horizontal)
+ r = QStyle::visualRect(mainWindow->layoutDirection(),
+ docks[i].rect, r);
+ return r;
+}
+
+QLayoutItem *QToolBarAreaLayout::plug(const QList<int> &path)
+{
+ QToolBarAreaLayoutItem &item = this->item(path);
+ Q_ASSERT(item.gap);
+ Q_ASSERT(item.widgetItem != 0);
+ item.gap = false;
+ return item.widgetItem;
+}
+
+QLayoutItem *QToolBarAreaLayout::unplug(const QList<int> &path, QToolBarAreaLayout *other)
+{
+ //other needs to be update as well
+ Q_ASSERT(path.count() == 3);
+ QToolBarAreaLayoutItem &item = this->item(path);
+
+ //update the leading space here
+ QToolBarAreaLayoutInfo &info = docks[path.at(0)];
+ QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
+ if (item.size != pick(line.o, item.realSizeHint())) {
+ //the item doesn't have its default size
+ //so we'll give this to the next item
+ int newExtraSpace = 0;
+ //let's iterate over the siblings of the current item that pare placed before it
+ //we need to find just the one before
+ for (int i = path.at(2) - 1; i >= 0; --i) {
+ QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
+ if (!previous.skip()) {
+ //we need to check if it has a previous element and a next one
+ //the previous will get its size changed
+ for (int j = path.at(2) + 1; j < line.toolBarItems.count(); ++j) {
+ const QToolBarAreaLayoutItem &next = line.toolBarItems.at(j);
+ if (!next.skip()) {
+ newExtraSpace = next.pos - previous.pos - pick(line.o, previous.sizeHint());
+ previous.resize(line.o, next.pos - previous.pos);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (other) {
+ QToolBarAreaLayoutInfo &info = other->docks[path.at(0)];
+ QToolBarAreaLayoutLine &line = info.lines[path.at(1)];
+ for (int i = path.at(2) - 1; i >= 0; --i) {
+ QToolBarAreaLayoutItem &previous = line.toolBarItems[i];
+ if (!previous.skip()) {
+ previous.resize(line.o, pick(line.o, previous.sizeHint()) + newExtraSpace);
+ break;
+ }
+ }
+
+ }
+ }
+
+ Q_ASSERT(!item.gap);
+ item.gap = true;
+ return item.widgetItem;
+}
+
+static QRect unpackRect(uint geom0, uint geom1, bool *floating)
+{
+ *floating = geom0 & 1;
+ if (!*floating)
+ return QRect();
+
+ geom0 >>= 1;
+
+ int x = (int)(geom0 & 0x0000ffff) - 0x7FFF;
+ int y = (int)(geom1 & 0x0000ffff) - 0x7FFF;
+
+ geom0 >>= 16;
+ geom1 >>= 16;
+
+ int w = geom0 & 0x0000ffff;
+ int h = geom1 & 0x0000ffff;
+
+ return QRect(x, y, w, h);
+}
+
+static void packRect(uint *geom0, uint *geom1, const QRect &rect, bool floating)
+{
+ *geom0 = 0;
+ *geom1 = 0;
+
+ if (!floating)
+ return;
+
+ // The 0x7FFF is half of 0xFFFF. We add it so we can handle negative coordinates on
+ // dual monitors. It's subtracted when unpacking.
+
+ *geom0 |= qMax(0, rect.width()) & 0x0000ffff;
+ *geom1 |= qMax(0, rect.height()) & 0x0000ffff;
+
+ *geom0 <<= 16;
+ *geom1 <<= 16;
+
+ *geom0 |= qMax(0, rect.x() + 0x7FFF) & 0x0000ffff;
+ *geom1 |= qMax(0, rect.y() + 0x7FFF) & 0x0000ffff;
+
+ // yeah, we chop one bit off the width, but it still has a range up to 32512
+
+ *geom0 <<= 1;
+ *geom0 |= 1;
+}
+
+
+void QToolBarAreaLayout::saveState(QDataStream &stream) const
+{
+ // save toolbar state
+ stream << (uchar) ToolBarStateMarkerEx;
+
+ int lineCount = 0;
+ for (int i = 0; i < QInternal::DockCount; ++i)
+ lineCount += docks[i].lines.count();
+
+ stream << lineCount;
+
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const QToolBarAreaLayoutInfo &dock = docks[i];
+
+ for (int j = 0; j < dock.lines.count(); ++j) {
+ const QToolBarAreaLayoutLine &line = dock.lines.at(j);
+
+ stream << i << line.toolBarItems.count();
+
+ for (int k = 0; k < line.toolBarItems.count(); ++k) {
+ const QToolBarAreaLayoutItem &item = line.toolBarItems.at(k);
+ QWidget *widget = const_cast<QLayoutItem*>(item.widgetItem)->widget();
+ QString objectName = widget->objectName();
+ if (objectName.isEmpty()) {
+ qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar %p '%s'",
+ widget, widget->windowTitle().toLocal8Bit().constData());
+ }
+ stream << objectName;
+ // we store information as:
+ // 1st bit: 1 if shown
+ // 2nd bit: 1 if orientation is vertical (default is horizontal)
+ uchar shownOrientation = (uchar)!widget->isHidden();
+ if (QToolBar * tb= qobject_cast<QToolBar*>(widget)) {
+ if (tb->orientation() == Qt::Vertical)
+ shownOrientation |= 2;
+ }
+ stream << shownOrientation;
+ stream << item.pos;
+ //we store the preferred size. If the use rdidn't resize the toolbars it will be -1
+ stream << item.preferredSize;
+
+ uint geom0, geom1;
+ packRect(&geom0, &geom1, widget->geometry(), widget->isWindow());
+ stream << geom0 << geom1;
+ }
+ }
+ }
+}
+
+static inline int getInt(QDataStream &stream, Qt::Orientation o, bool pre43)
+{
+ if (pre43) {
+ QPoint p;
+ stream >> p;
+ return pick(o, p);
+ } else {
+ int x;
+ stream >> x;
+ return x;
+ }
+}
+
+
+bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList<QToolBar*> &_toolBars, uchar tmarker, bool pre43, bool testing)
+{
+ QList<QToolBar*> toolBars = _toolBars;
+ int lines;
+ stream >> lines;
+ if (!testing)
+ testing = mainWindow->unifiedTitleAndToolBarOnMac();
+
+ for (int j = 0; j < lines; ++j) {
+ int pos;
+ stream >> pos;
+ if (pos < 0 || pos >= QInternal::DockCount)
+ return false;
+ int cnt;
+ stream >> cnt;
+
+ QToolBarAreaLayoutInfo &dock = docks[pos];
+ const bool applyingLayout = !testing && !(pos == QInternal::TopDock && mainWindow->unifiedTitleAndToolBarOnMac());
+ QToolBarAreaLayoutLine line(dock.o);
+
+ for (int k = 0; k < cnt; ++k) {
+ QToolBarAreaLayoutItem item;
+
+ QString objectName;
+ stream >> objectName;
+ uchar shown;
+ stream >> shown;
+ item.pos = getInt(stream, dock.o, pre43);
+ item.size = getInt(stream, dock.o, pre43);
+
+ /*
+ 4.3.0 added floating toolbars, but failed to add the ability to restore them.
+ We need to store there geometry (four ints). We cannot change the format in a
+ patch release (4.3.1) by adding ToolBarStateMarkerEx2 to signal extra data. So
+ for now we'll pack it in the two legacy ints we no longer used in Qt4.3.0.
+ In 4.4, we should add ToolBarStateMarkerEx2 and fix this properly.
+ */
+
+ QRect rect;
+ bool floating = false;
+ uint geom0, geom1;
+ geom0 = getInt(stream, dock.o, pre43);
+ if (tmarker == ToolBarStateMarkerEx) {
+ geom1 = getInt(stream, dock.o, pre43);
+ rect = unpackRect(geom0, geom1, &floating);
+ }
+
+ QToolBar *toolBar = 0;
+ for (int x = 0; x < toolBars.count(); ++x) {
+ if (toolBars.at(x)->objectName() == objectName) {
+ toolBar = toolBars.takeAt(x);
+ break;
+ }
+ }
+ if (toolBar == 0) {
+ continue;
+ }
+
+ if (applyingLayout) {
+ item.widgetItem = new QWidgetItemV2(toolBar);
+ toolBar->setOrientation(floating ? ((shown & 2) ? Qt::Vertical : Qt::Horizontal) : dock.o);
+ toolBar->setVisible(shown & 1);
+ toolBar->d_func()->setWindowState(floating, true, rect);
+
+ item.preferredSize = item.size;
+ line.toolBarItems.append(item);
+ }
+ }
+
+ if (applyingLayout) {
+ dock.lines.append(line);
+ }
+ }
+
+
+ return stream.status() == QDataStream::Ok;
+}
+
+bool QToolBarAreaLayout::isEmpty() const
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ if (!docks[i].lines.isEmpty())
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TOOLBAR
diff --git a/src/widgets/widgets/qtoolbararealayout_p.h b/src/widgets/widgets/qtoolbararealayout_p.h
new file mode 100644
index 0000000000..940901df96
--- /dev/null
+++ b/src/widgets/widgets/qtoolbararealayout_p.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTOOLBARAREALAYOUT_P_H
+#define QTOOLBARAREALAYOUT_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 <QList>
+#include <QSize>
+#include <QRect>
+
+QT_BEGIN_NAMESPACE
+
+static inline int pick(Qt::Orientation o, const QPoint &pos)
+{ return o == Qt::Horizontal ? pos.x() : pos.y(); }
+
+static inline int pick(Qt::Orientation o, const QSize &size)
+{ return o == Qt::Horizontal ? size.width() : size.height(); }
+
+static inline int &rpick(Qt::Orientation o, QPoint &pos)
+{ return o == Qt::Horizontal ? pos.rx() : pos.ry(); }
+
+static inline int &rpick(Qt::Orientation o, QSize &size)
+{ return o == Qt::Horizontal ? size.rwidth() : size.rheight(); }
+
+static inline QSizePolicy::Policy pick(Qt::Orientation o, const QSizePolicy &policy)
+{ return o == Qt::Horizontal ? policy.horizontalPolicy() : policy.verticalPolicy(); }
+
+static inline int perp(Qt::Orientation o, const QPoint &pos)
+{ return o == Qt::Vertical ? pos.x() : pos.y(); }
+
+static inline int perp(Qt::Orientation o, const QSize &size)
+{ return o == Qt::Vertical ? size.width() : size.height(); }
+
+static inline int &rperp(Qt::Orientation o, QPoint &pos)
+{ return o == Qt::Vertical ? pos.rx() : pos.ry(); }
+
+static inline int &rperp(Qt::Orientation o, QSize &size)
+{ return o == Qt::Vertical ? size.rwidth() : size.rheight(); }
+
+#ifndef QT_NO_TOOLBAR
+
+class QToolBar;
+class QLayoutItem;
+class QMainWindow;
+class QStyleOptionToolBar;
+
+class QToolBarAreaLayoutItem
+{
+public:
+ QToolBarAreaLayoutItem(QLayoutItem *item = 0)
+ : widgetItem(item), pos(0), size(-1), preferredSize(-1), gap(false) {}
+
+ bool skip() const;
+ QSize minimumSize() const;
+ QSize sizeHint() const;
+ QSize realSizeHint() const;
+
+ void resize(Qt::Orientation o, int newSize)
+ {
+ newSize = qMax(pick(o, minimumSize()), newSize);
+ int sizeh = pick(o, sizeHint());
+ if (newSize == sizeh) {
+ preferredSize = -1;
+ size = sizeh;
+ } else {
+ preferredSize = newSize;
+ }
+ }
+
+ void extendSize(Qt::Orientation o, int extent)
+ {
+ int newSize = qMax(pick(o, minimumSize()), (preferredSize > 0 ? preferredSize : pick(o, sizeHint())) + extent);
+ int sizeh = pick(o, sizeHint());
+ if (newSize == sizeh) {
+ preferredSize = -1;
+ size = sizeh;
+ } else {
+ preferredSize = newSize;
+ }
+ }
+
+ QLayoutItem *widgetItem;
+ int pos;
+ int size;
+ int preferredSize;
+ bool gap;
+};
+
+class QToolBarAreaLayoutLine
+{
+public:
+ QToolBarAreaLayoutLine(Qt::Orientation orientation);
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+
+ void fitLayout();
+ bool skip() const;
+
+ QRect rect;
+ Qt::Orientation o;
+
+ QList<QToolBarAreaLayoutItem> toolBarItems;
+};
+
+class QToolBarAreaLayoutInfo
+{
+public:
+ QToolBarAreaLayoutInfo(QInternal::DockPosition pos = QInternal::TopDock);
+
+ QList<QToolBarAreaLayoutLine> lines;
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+
+ void fitLayout();
+
+ QLayoutItem *insertToolBar(QToolBar *before, QToolBar *toolBar);
+ void insertItem(QToolBar *before, QLayoutItem *item);
+ void removeToolBar(QToolBar *toolBar);
+ void insertToolBarBreak(QToolBar *before);
+ void removeToolBarBreak(QToolBar *before);
+ void moveToolBar(QToolBar *toolbar, int pos);
+
+ QList<int> gapIndex(const QPoint &pos, int *maxDistance) const;
+ bool insertGap(const QList<int> &path, QLayoutItem *item);
+ void clear();
+ QRect itemRect(const QList<int> &path) const;
+ int distance(const QPoint &pos) const;
+
+ QRect rect;
+ Qt::Orientation o;
+ QInternal::DockPosition dockPos;
+ bool dirty;
+};
+
+class QToolBarAreaLayout
+{
+public:
+ enum { // sentinel values used to validate state data
+ ToolBarStateMarker = 0xfe,
+ ToolBarStateMarkerEx = 0xfc
+ };
+
+ QRect rect;
+ const QMainWindow *mainWindow;
+ QToolBarAreaLayoutInfo docks[4];
+ bool visible;
+
+ QToolBarAreaLayout(const QMainWindow *win);
+
+ QRect fitLayout();
+
+ QSize minimumSize(const QSize &centerMin) const;
+ QRect rectHint(const QRect &r) const;
+ QSize sizeHint(const QSize &center) const;
+ void apply(bool animate);
+
+ QLayoutItem *itemAt(int *x, int index) const;
+ QLayoutItem *takeAt(int *x, int index);
+ void deleteAllLayoutItems();
+
+ QLayoutItem *insertToolBar(QToolBar *before, QToolBar *toolBar);
+ void removeToolBar(QToolBar *toolBar);
+ QLayoutItem *addToolBar(QInternal::DockPosition pos, QToolBar *toolBar);
+ void insertToolBarBreak(QToolBar *before);
+ void removeToolBarBreak(QToolBar *before);
+ void addToolBarBreak(QInternal::DockPosition pos);
+ void moveToolBar(QToolBar *toolbar, int pos);
+
+ void insertItem(QInternal::DockPosition pos, QLayoutItem *item);
+ void insertItem(QToolBar *before, QLayoutItem *item);
+
+ QInternal::DockPosition findToolBar(QToolBar *toolBar) const;
+ bool toolBarBreak(QToolBar *toolBar) const;
+
+ void getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar *toolBar) const;
+
+ QList<int> indexOf(QWidget *toolBar) const;
+ QList<int> gapIndex(const QPoint &pos) const;
+ QList<int> currentGapIndex() const;
+ bool insertGap(const QList<int> &path, QLayoutItem *item);
+ void remove(const QList<int> &path);
+ void remove(QLayoutItem *item);
+ void clear();
+ QToolBarAreaLayoutItem &item(const QList<int> &path);
+ QRect itemRect(const QList<int> &path) const;
+ QLayoutItem *plug(const QList<int> &path);
+ QLayoutItem *unplug(const QList<int> &path, QToolBarAreaLayout *other);
+
+ void saveState(QDataStream &stream) const;
+ bool restoreState(QDataStream &stream, const QList<QToolBar*> &toolBars, uchar tmarker, bool pre43, bool testing = false);
+ bool isEmpty() const;
+};
+
+
+QT_END_NAMESPACE
+#endif // QT_NO_TOOLBAR
+#endif // QTOOLBARAREALAYOUT_P_H
diff --git a/src/widgets/widgets/qtoolbarextension.cpp b/src/widgets/widgets/qtoolbarextension.cpp
new file mode 100644
index 0000000000..c522b416f2
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarextension.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtoolbarextension_p.h"
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qstylepainter.h>
+#include <qstyleoption.h>
+
+#ifndef QT_NO_TOOLBUTTON
+
+QT_BEGIN_NAMESPACE
+
+QToolBarExtension::QToolBarExtension(QWidget *parent)
+ : QToolButton(parent)
+{
+ setObjectName(QLatin1String("qt_toolbar_ext_button"));
+ setAutoRaise(true);
+ setOrientation(Qt::Horizontal);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setCheckable(true);
+}
+
+void QToolBarExtension::setOrientation(Qt::Orientation o)
+{
+ QStyleOption opt;
+ opt.init(this);
+ if (o == Qt::Horizontal) {
+ setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, &opt));
+ } else {
+ setIcon(style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton, &opt));
+ }
+}
+
+void QToolBarExtension::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ // We do not need to draw both extension arrows
+ opt.features &= ~QStyleOptionToolButton::HasMenu;
+ p.drawComplexControl(QStyle::CC_ToolButton, opt);
+}
+
+
+QSize QToolBarExtension::sizeHint() const
+{
+ int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent);
+ return QSize(ext, ext);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TOOLBUTTON
diff --git a/src/widgets/widgets/qtoolbarextension_p.h b/src/widgets/widgets/qtoolbarextension_p.h
new file mode 100644
index 0000000000..d7f28bf0f3
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarextension_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICTOOLBAREXTENSION_P_H
+#define QDYNAMICTOOLBAREXTENSION_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 "QtWidgets/qtoolbutton.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TOOLBUTTON
+
+class Q_AUTOTEST_EXPORT QToolBarExtension : public QToolButton
+{
+ Q_OBJECT
+ Qt::Orientation orientation;
+
+public:
+ explicit QToolBarExtension(QWidget *parent);
+ void paintEvent(QPaintEvent *);
+ QSize sizeHint() const;
+
+public Q_SLOTS:
+ void setOrientation(Qt::Orientation o);
+};
+
+#endif // QT_NO_TOOLBUTTON
+
+QT_END_NAMESPACE
+
+#endif // QDYNAMICTOOLBAREXTENSION_P_H
diff --git a/src/widgets/widgets/qtoolbarlayout.cpp b/src/widgets/widgets/qtoolbarlayout.cpp
new file mode 100644
index 0000000000..971fddaafd
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarlayout.cpp
@@ -0,0 +1,742 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qaction.h>
+#include <qwidgetaction.h>
+#include <qtoolbar.h>
+#include <qstyleoption.h>
+#include <qtoolbutton.h>
+#include <qmenu.h>
+#include <qdebug.h>
+#include <qmath.h>
+
+#include "qmainwindowlayout_p.h"
+#include "qtoolbarextension_p.h"
+#include "qtoolbarlayout_p.h"
+#include "qtoolbarseparator_p.h"
+
+#ifndef QT_NO_TOOLBAR
+
+QT_BEGIN_NAMESPACE
+
+// qmainwindow.cpp
+extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
+
+/******************************************************************************
+** QToolBarItem
+*/
+
+QToolBarItem::QToolBarItem(QWidget *widget)
+ : QWidgetItem(widget), action(0), customWidget(false)
+{
+}
+
+bool QToolBarItem::isEmpty() const
+{
+ return action == 0 || !action->isVisible();
+}
+
+/******************************************************************************
+** QToolBarLayout
+*/
+
+QToolBarLayout::QToolBarLayout(QWidget *parent)
+ : QLayout(parent), expanded(false), animating(false), dirty(true),
+ expanding(false), empty(true), expandFlag(false), popupMenu(0)
+{
+ QToolBar *tb = qobject_cast<QToolBar*>(parent);
+ if (!tb)
+ return;
+
+ extension = new QToolBarExtension(tb);
+ extension->setFocusPolicy(Qt::NoFocus);
+ extension->hide();
+ QObject::connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
+ extension, SLOT(setOrientation(Qt::Orientation)));
+
+ setUsePopupMenu(qobject_cast<QMainWindow*>(tb->parentWidget()) == 0);
+}
+
+QToolBarLayout::~QToolBarLayout()
+{
+ while (!items.isEmpty()) {
+ QToolBarItem *item = items.takeFirst();
+ if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action)) {
+ if (item->customWidget)
+ widgetAction->releaseWidget(item->widget());
+ }
+ delete item;
+ }
+}
+
+void QToolBarLayout::updateMarginAndSpacing()
+{
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return;
+ QStyle *style = tb->style();
+ QStyleOptionToolBar opt;
+ tb->initStyleOption(&opt);
+ setMargin(style->pixelMetric(QStyle::PM_ToolBarItemMargin, &opt, tb)
+ + style->pixelMetric(QStyle::PM_ToolBarFrameWidth, &opt, tb));
+ setSpacing(style->pixelMetric(QStyle::PM_ToolBarItemSpacing, &opt, tb));
+}
+
+bool QToolBarLayout::hasExpandFlag() const
+{
+ return expandFlag;
+}
+
+void QToolBarLayout::setUsePopupMenu(bool set)
+{
+ if (!dirty && ((popupMenu == 0) == set))
+ invalidate();
+ if (!set) {
+ QObject::connect(extension, SIGNAL(clicked(bool)),
+ this, SLOT(setExpanded(bool)), Qt::UniqueConnection);
+ extension->setPopupMode(QToolButton::DelayedPopup);
+ extension->setMenu(0);
+ delete popupMenu;
+ popupMenu = 0;
+ } else {
+ QObject::disconnect(extension, SIGNAL(clicked(bool)),
+ this, SLOT(setExpanded(bool)));
+ extension->setPopupMode(QToolButton::InstantPopup);
+ if (!popupMenu) {
+ popupMenu = new QMenu(extension);
+ }
+ extension->setMenu(popupMenu);
+ }
+}
+
+void QToolBarLayout::checkUsePopupMenu()
+{
+ QToolBar *tb = static_cast<QToolBar *>(parent());
+ QMainWindow *mw = qobject_cast<QMainWindow *>(tb->parent());
+ Qt::Orientation o = tb->orientation();
+ setUsePopupMenu(!mw || tb->isFloating() || perp(o, expandedSize(mw->size())) >= perp(o, mw->size()));
+}
+
+void QToolBarLayout::addItem(QLayoutItem*)
+{
+ qWarning() << "QToolBarLayout::addItem(): please use addAction() instead";
+ return;
+}
+
+QLayoutItem *QToolBarLayout::itemAt(int index) const
+{
+ if (index < 0 || index >= items.count())
+ return 0;
+ return items.at(index);
+}
+
+QLayoutItem *QToolBarLayout::takeAt(int index)
+{
+ if (index < 0 || index >= items.count())
+ return 0;
+ QToolBarItem *item = items.takeAt(index);
+
+ if (popupMenu)
+ popupMenu->removeAction(item->action);
+
+ QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(item->action);
+ if (widgetAction != 0 && item->customWidget) {
+ widgetAction->releaseWidget(item->widget());
+ } else {
+ // destroy the QToolButton/QToolBarSeparator
+ item->widget()->hide();
+ item->widget()->deleteLater();
+ }
+
+ invalidate();
+ return item;
+}
+
+void QToolBarLayout::insertAction(int index, QAction *action)
+{
+ index = qMax(0, index);
+ index = qMin(items.count(), index);
+
+ QToolBarItem *item = createItem(action);
+ if (item) {
+ items.insert(index, item);
+ invalidate();
+ }
+}
+
+int QToolBarLayout::indexOf(QAction *action) const
+{
+ for (int i = 0; i < items.count(); ++i) {
+ if (items.at(i)->action == action)
+ return i;
+ }
+ return -1;
+}
+
+int QToolBarLayout::count() const
+{
+ return items.count();
+}
+
+bool QToolBarLayout::isEmpty() const
+{
+ if (dirty)
+ updateGeomArray();
+ return empty;
+}
+
+void QToolBarLayout::invalidate()
+{
+ dirty = true;
+ QLayout::invalidate();
+}
+
+Qt::Orientations QToolBarLayout::expandingDirections() const
+{
+ if (dirty)
+ updateGeomArray();
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return Qt::Orientations(0);
+ Qt::Orientation o = tb->orientation();
+ return expanding ? Qt::Orientations(o) : Qt::Orientations(0);
+}
+
+bool QToolBarLayout::movable() const
+{
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return false;
+ QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
+ return tb->isMovable() && win != 0;
+}
+
+void QToolBarLayout::updateGeomArray() const
+{
+ if (!dirty)
+ return;
+
+ QToolBarLayout *that = const_cast<QToolBarLayout*>(this);
+
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return;
+ QStyle *style = tb->style();
+ QStyleOptionToolBar opt;
+ tb->initStyleOption(&opt);
+ const int handleExtent = movable()
+ ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
+ const int margin = this->margin();
+ const int spacing = this->spacing();
+ const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
+ Qt::Orientation o = tb->orientation();
+
+ that->minSize = QSize(0, 0);
+ that->hint = QSize(0, 0);
+ rperp(o, that->minSize) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
+ rperp(o, that->hint) = style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb);
+
+ that->expanding = false;
+ that->empty = false;
+
+ QVector<QLayoutStruct> a(items.count() + 1); // + 1 for the stretch
+
+ int count = 0;
+ for (int i = 0; i < items.count(); ++i) {
+ QToolBarItem *item = items.at(i);
+
+ QSize max = item->maximumSize();
+ QSize min = item->minimumSize();
+ QSize hint = item->sizeHint();
+ Qt::Orientations exp = item->expandingDirections();
+ bool empty = item->isEmpty();
+
+ that->expanding = expanding || exp & o;
+
+
+ if (item->widget()) {
+ if ((item->widget()->sizePolicy().horizontalPolicy() & QSizePolicy::ExpandFlag)) {
+ that->expandFlag = true;
+ }
+ }
+
+ if (!empty) {
+ if (count == 0) // the minimum size only displays one widget
+ rpick(o, that->minSize) += pick(o, min);
+ int s = perp(o, minSize);
+ rperp(o, that->minSize) = qMax(s, perp(o, min));
+
+ //we only add spacing before item (ie never before the first one)
+ rpick(o, that->hint) += (count == 0 ? 0 : spacing) + pick(o, hint);
+ s = perp(o, that->hint);
+ rperp(o, that->hint) = qMax(s, perp(o, hint));
+ ++count;
+ }
+
+ a[i].sizeHint = pick(o, hint);
+ a[i].maximumSize = pick(o, max);
+ a[i].minimumSize = pick(o, min);
+ a[i].expansive = exp & o;
+ if (o == Qt::Horizontal)
+ a[i].stretch = item->widget()->sizePolicy().horizontalStretch();
+ else
+ a[i].stretch = item->widget()->sizePolicy().verticalStretch();
+ a[i].empty = empty;
+ }
+
+ that->geomArray = a;
+ that->empty = count == 0;
+
+ rpick(o, that->minSize) += handleExtent;
+ that->minSize += QSize(2*margin, 2*margin);
+ if (items.count() > 1)
+ rpick(o, that->minSize) += spacing + extensionExtent;
+
+ rpick(o, that->hint) += handleExtent;
+ that->hint += QSize(2*margin, 2*margin);
+ that->dirty = false;
+#ifdef Q_WS_MAC
+ if (QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget()->parentWidget())) {
+ if (mw->unifiedTitleAndToolBarOnMac()
+ && mw->toolBarArea(static_cast<QToolBar *>(parentWidget())) == Qt::TopToolBarArea) {
+ if (expandFlag) {
+ tb->setMaximumSize(0xFFFFFF, 0xFFFFFF);
+ } else {
+ tb->setMaximumSize(hint);
+ }
+ }
+ }
+#endif
+
+ that->dirty = false;
+}
+
+static bool defaultWidgetAction(QToolBarItem *item)
+{
+ QWidgetAction *a = qobject_cast<QWidgetAction*>(item->action);
+ return a != 0 && a->defaultWidget() == item->widget();
+}
+
+void QToolBarLayout::setGeometry(const QRect &rect)
+{
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return;
+ QStyle *style = tb->style();
+ QStyleOptionToolBar opt;
+ tb->initStyleOption(&opt);
+ const int margin = this->margin();
+ const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
+ Qt::Orientation o = tb->orientation();
+
+ QLayout::setGeometry(rect);
+
+ bool ranOutOfSpace = false;
+ if (!animating)
+ ranOutOfSpace = layoutActions(rect.size());
+
+ if (expanded || animating || ranOutOfSpace) {
+ Qt::ToolBarArea area = Qt::TopToolBarArea;
+ if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget()))
+ area = win->toolBarArea(tb);
+ QSize hint = sizeHint();
+
+ QPoint pos;
+ rpick(o, pos) = pick(o, rect.bottomRight()) - margin - extensionExtent + 2;
+ if (area == Qt::LeftToolBarArea || area == Qt::TopToolBarArea)
+ rperp(o, pos) = perp(o, rect.topLeft()) + margin;
+ else
+ rperp(o, pos) = perp(o, rect.bottomRight()) - margin - (perp(o, hint) - 2*margin) + 1;
+ QSize size;
+ rpick(o, size) = extensionExtent;
+ rperp(o, size) = perp(o, hint) - 2*margin;
+ QRect r(pos, size);
+
+ if (o == Qt::Horizontal)
+ r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
+
+ extension->setGeometry(r);
+
+ if (extension->isHidden())
+ extension->show();
+ } else {
+ if (!extension->isHidden())
+ extension->hide();
+ }
+#ifdef Q_WS_MAC
+ // Nothing to do for Carbon... probably
+# ifdef QT_MAC_USE_COCOA
+ if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget())) {
+ Qt::ToolBarArea area = win->toolBarArea(tb);
+ if (win->unifiedTitleAndToolBarOnMac() && area == Qt::TopToolBarArea) {
+ qt_mainwindow_layout(win)->fixSizeInUnifiedToolbar(tb);
+ }
+ }
+# endif
+#endif
+
+}
+
+bool QToolBarLayout::layoutActions(const QSize &size)
+{
+ if (dirty)
+ updateGeomArray();
+
+ QRect rect(0, 0, size.width(), size.height());
+
+ QList<QWidget*> showWidgets, hideWidgets;
+
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return false;
+ QStyle *style = tb->style();
+ QStyleOptionToolBar opt;
+ tb->initStyleOption(&opt);
+ const int handleExtent = movable()
+ ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
+ const int margin = this->margin();
+ const int spacing = this->spacing();
+ const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
+ Qt::Orientation o = tb->orientation();
+ bool extensionMenuContainsOnlyWidgetActions = true;
+
+ int space = pick(o, rect.size()) - 2*margin - handleExtent;
+ if (space <= 0)
+ return false; // nothing to do.
+
+ if(popupMenu)
+ popupMenu->clear();
+
+ bool ranOutOfSpace = false;
+ int rows = 0;
+ int rowPos = perp(o, rect.topLeft()) + margin;
+ int i = 0;
+ while (i < items.count()) {
+ QVector<QLayoutStruct> a = geomArray;
+
+ int start = i;
+ int size = 0;
+ int prev = -1;
+ int rowHeight = 0;
+ int count = 0;
+ int maximumSize = 0;
+ bool expansiveRow = false;
+ for (; i < items.count(); ++i) {
+ if (a[i].empty)
+ continue;
+
+ int newSize = size + (count == 0 ? 0 : spacing) + a[i].minimumSize;
+ if (prev != -1 && newSize > space) {
+ if (rows == 0)
+ ranOutOfSpace = true;
+ // do we have to move the previous item to the next line to make space for
+ // the extension button?
+ if (count > 1 && size + spacing + extensionExtent > space)
+ i = prev;
+ break;
+ }
+
+ if (expanded)
+ rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
+ expansiveRow = expansiveRow || a[i].expansive;
+ size = newSize;
+ maximumSize += spacing + (a[i].expansive ? a[i].maximumSize : a[i].smartSizeHint());
+ prev = i;
+ ++count;
+ }
+
+ // stretch at the end
+ a[i].sizeHint = 0;
+ a[i].maximumSize = QWIDGETSIZE_MAX;
+ a[i].minimumSize = 0;
+ a[i].expansive = true;
+ a[i].stretch = 0;
+ a[i].empty = true;
+
+ if (expansiveRow && maximumSize < space) {
+ expansiveRow = false;
+ a[i].maximumSize = space - maximumSize;
+ }
+
+ qGeomCalc(a, start, i - start + (expansiveRow ? 0 : 1), 0,
+ space - (ranOutOfSpace ? (extensionExtent + spacing) : 0),
+ spacing);
+
+ for (int j = start; j < i; ++j) {
+ QToolBarItem *item = items.at(j);
+
+ if (a[j].empty) {
+ if (!item->widget()->isHidden())
+ hideWidgets << item->widget();
+ continue;
+ }
+
+ QPoint pos;
+ rpick(o, pos) = margin + handleExtent + a[j].pos;
+ rperp(o, pos) = rowPos;
+ QSize size;
+ rpick(o, size) = a[j].size;
+ if (expanded)
+ rperp(o, size) = rowHeight;
+ else
+ rperp(o, size) = perp(o, rect.size()) - 2*margin;
+ QRect r(pos, size);
+
+ if (o == Qt::Horizontal)
+ r = QStyle::visualRect(parentWidget()->layoutDirection(), rect, r);
+
+ item->setGeometry(r);
+
+ if (item->widget()->isHidden())
+ showWidgets << item->widget();
+ }
+
+ if (!expanded) {
+ for (int j = i; j < items.count(); ++j) {
+ QToolBarItem *item = items.at(j);
+ if (!item->widget()->isHidden())
+ hideWidgets << item->widget();
+ if (popupMenu) {
+ if (!defaultWidgetAction(item)) {
+ popupMenu->addAction(item->action);
+ extensionMenuContainsOnlyWidgetActions = false;
+ }
+ }
+ }
+ break;
+ }
+
+ rowPos += rowHeight + spacing;
+ ++rows;
+ }
+
+ // if we are using a popup menu, not the expadning toolbar effect, we cannot move custom
+ // widgets into the menu. If only custom widget actions are chopped off, the popup menu
+ // is empty. So we show the little extension button to show something is chopped off,
+ // but we make it disabled.
+ extension->setEnabled(popupMenu == 0 || !extensionMenuContainsOnlyWidgetActions);
+
+ // we have to do the show/hide here, because it triggers more calls to setGeometry :(
+ for (int i = 0; i < showWidgets.count(); ++i)
+ showWidgets.at(i)->show();
+ for (int i = 0; i < hideWidgets.count(); ++i)
+ hideWidgets.at(i)->hide();
+
+ return ranOutOfSpace;
+}
+
+QSize QToolBarLayout::expandedSize(const QSize &size) const
+{
+ if (dirty)
+ updateGeomArray();
+
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return QSize(0, 0);
+ QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget());
+ Qt::Orientation o = tb->orientation();
+ QStyle *style = tb->style();
+ QStyleOptionToolBar opt;
+ tb->initStyleOption(&opt);
+ const int handleExtent = movable()
+ ? style->pixelMetric(QStyle::PM_ToolBarHandleExtent, &opt, tb) : 0;
+ const int margin = this->margin();
+ const int spacing = this->spacing();
+ const int extensionExtent = style->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, tb);
+
+ int total_w = 0;
+ int count = 0;
+ for (int x = 0; x < items.count(); ++x) {
+ if (!geomArray[x].empty) {
+ total_w += (count == 0 ? 0 : spacing) + geomArray[x].minimumSize;
+ ++count;
+ }
+ }
+ if (count == 0)
+ return QSize(0, 0);
+
+ int min_w = pick(o, size);
+ int rows = (int)qSqrt(qreal(count));
+ if (rows == 1)
+ ++rows; // we want to expand to at least two rows
+ int space = total_w/rows + spacing + extensionExtent;
+ space = qMax(space, min_w - 2*margin - handleExtent);
+ if (win != 0)
+ space = qMin(space, pick(o, win->size()) - 2*margin - handleExtent);
+
+ int w = 0;
+ int h = 0;
+ int i = 0;
+ while (i < items.count()) {
+ int count = 0;
+ int size = 0;
+ int prev = -1;
+ int rowHeight = 0;
+ for (; i < items.count(); ++i) {
+ if (geomArray[i].empty)
+ continue;
+
+ int newSize = size + (count == 0 ? 0 : spacing) + geomArray[i].minimumSize;
+ rowHeight = qMax(rowHeight, perp(o, items.at(i)->sizeHint()));
+ if (prev != -1 && newSize > space) {
+ if (count > 1 && size + spacing + extensionExtent > space) {
+ size -= spacing + geomArray[prev].minimumSize;
+ i = prev;
+ }
+ break;
+ }
+
+ size = newSize;
+ prev = i;
+ ++count;
+ }
+
+ w = qMax(size, w);
+ h += rowHeight + spacing;
+ }
+
+ w += 2*margin + handleExtent + spacing + extensionExtent;
+ w = qMax(w, min_w);
+ if (win != 0)
+ w = qMin(w, pick(o, win->size()));
+ h += 2*margin - spacing; //there is no spacing before the first row
+
+ QSize result;
+ rpick(o, result) = w;
+ rperp(o, result) = h;
+ return result;
+}
+
+void QToolBarLayout::setExpanded(bool exp)
+{
+ QWidget *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return;
+ if (exp == expanded && !tb->isWindow())
+ return;
+
+ expanded = exp;
+ extension->setChecked(expanded);
+
+ if (QMainWindow *win = qobject_cast<QMainWindow*>(tb->parentWidget())) {
+#ifdef QT_NO_DOCKWIDGET
+ animating = false;
+#else
+ animating = !tb->isWindow() && win->isAnimated();
+#endif
+ QMainWindowLayout *layout = qt_mainwindow_layout(win);
+ if (expanded) {
+ tb->raise();
+ } else {
+ QList<int> path = layout->layoutState.indexOf(tb);
+ if (!path.isEmpty()) {
+ QRect rect = layout->layoutState.itemRect(path);
+ layoutActions(rect.size());
+ }
+ }
+ layout->layoutState.toolBarAreaLayout.apply(animating);
+ }
+}
+
+QSize QToolBarLayout::minimumSize() const
+{
+ if (dirty)
+ updateGeomArray();
+ return minSize;
+}
+
+QSize QToolBarLayout::sizeHint() const
+{
+ if (dirty)
+ updateGeomArray();
+ return hint;
+}
+
+QToolBarItem *QToolBarLayout::createItem(QAction *action)
+{
+ bool customWidget = false;
+ bool standardButtonWidget = false;
+ QWidget *widget = 0;
+ QToolBar *tb = qobject_cast<QToolBar*>(parentWidget());
+ if (!tb)
+ return (QToolBarItem *)0;
+
+ if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action)) {
+ widget = widgetAction->requestWidget(tb);
+ if (widget != 0) {
+ widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ customWidget = true;
+ }
+ } else if (action->isSeparator()) {
+ QToolBarSeparator *sep = new QToolBarSeparator(tb);
+ connect(tb, SIGNAL(orientationChanged(Qt::Orientation)),
+ sep, SLOT(setOrientation(Qt::Orientation)));
+ widget = sep;
+ }
+
+ if (!widget) {
+ QToolButton *button = new QToolButton(tb);
+ button->setAutoRaise(true);
+ button->setFocusPolicy(Qt::NoFocus);
+ button->setIconSize(tb->iconSize());
+ button->setToolButtonStyle(tb->toolButtonStyle());
+ QObject::connect(tb, SIGNAL(iconSizeChanged(QSize)),
+ button, SLOT(setIconSize(QSize)));
+ QObject::connect(tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
+ button, SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));
+ button->setDefaultAction(action);
+ QObject::connect(button, SIGNAL(triggered(QAction*)), tb, SIGNAL(actionTriggered(QAction*)));
+ widget = button;
+ standardButtonWidget = true;
+ }
+
+ widget->hide();
+ QToolBarItem *result = new QToolBarItem(widget);
+ if (standardButtonWidget)
+ result->setAlignment(Qt::AlignJustify);
+ result->customWidget = customWidget;
+ result->action = action;
+ return result;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TOOLBAR
diff --git a/src/widgets/widgets/qtoolbarlayout_p.h b/src/widgets/widgets/qtoolbarlayout_p.h
new file mode 100644
index 0000000000..4e4a8eab84
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarlayout_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTOOLBARLAYOUT_P_H
+#define QTOOLBARLAYOUT_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 <QtWidgets/qlayout.h>
+#include <private/qlayoutengine_p.h>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TOOLBAR
+
+class QAction;
+class QToolBarExtension;
+class QMenu;
+
+class QToolBarItem : public QWidgetItem
+{
+public:
+ QToolBarItem(QWidget *widget);
+ bool isEmpty() const;
+
+ QAction *action;
+ bool customWidget;
+};
+
+class QToolBarLayout : public QLayout
+{
+ Q_OBJECT
+
+public:
+ QToolBarLayout(QWidget *parent = 0);
+ ~QToolBarLayout();
+
+ void addItem(QLayoutItem *item);
+ QLayoutItem *itemAt(int index) const;
+ QLayoutItem *takeAt(int index);
+ int count() const;
+
+ bool isEmpty() const;
+ void invalidate();
+ Qt::Orientations expandingDirections() const;
+
+ void setGeometry(const QRect &r);
+ QSize minimumSize() const;
+ QSize sizeHint() const;
+
+ void insertAction(int index, QAction *action);
+ int indexOf(QAction *action) const;
+ int indexOf(QWidget *widget) const { return QLayout::indexOf(widget); }
+
+ bool layoutActions(const QSize &size);
+ QSize expandedSize(const QSize &size) const;
+ bool expanded, animating;
+
+ void setUsePopupMenu(bool set); // Yeah, there's no getter, but it's internal.
+ void checkUsePopupMenu();
+
+ bool movable() const;
+ void updateMarginAndSpacing();
+ bool hasExpandFlag() const;
+
+public Q_SLOTS:
+ void setExpanded(bool b);
+
+private:
+ QList<QToolBarItem*> items;
+ QSize hint, minSize;
+ bool dirty, expanding, empty, expandFlag;
+ QVector<QLayoutStruct> geomArray;
+ QRect handRect;
+ QToolBarExtension *extension;
+
+ void updateGeomArray() const;
+ QToolBarItem *createItem(QAction *action);
+ QMenu *popupMenu;
+};
+
+#endif // QT_NO_TOOLBAR
+
+QT_END_NAMESPACE
+
+#endif // QTOOLBARLAYOUT_P_H
diff --git a/src/widgets/widgets/qtoolbarseparator.cpp b/src/widgets/widgets/qtoolbarseparator.cpp
new file mode 100644
index 0000000000..bd0ed9854f
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarseparator.cpp
@@ -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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtoolbarseparator_p.h"
+
+#ifndef QT_NO_TOOLBAR
+
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qtoolbar.h>
+#include <qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+void QToolBarSeparator::initStyleOption(QStyleOption *option) const
+{
+ option->initFrom(this);
+ if (orientation() == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+}
+
+QToolBarSeparator::QToolBarSeparator(QToolBar *parent)
+ : QWidget(parent), orient(parent->orientation())
+{ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); }
+
+void QToolBarSeparator::setOrientation(Qt::Orientation orientation)
+{
+ orient = orientation;
+ update();
+}
+
+Qt::Orientation QToolBarSeparator::orientation() const
+{ return orient; }
+
+QSize QToolBarSeparator::sizeHint() const
+{
+ QStyleOption opt;
+ initStyleOption(&opt);
+ const int extent = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, &opt, parentWidget());
+ return QSize(extent, extent);
+}
+
+void QToolBarSeparator::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ initStyleOption(&opt);
+ style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_TOOLBAR
diff --git a/src/widgets/widgets/qtoolbarseparator_p.h b/src/widgets/widgets/qtoolbarseparator_p.h
new file mode 100644
index 0000000000..0f1eb05abc
--- /dev/null
+++ b/src/widgets/widgets/qtoolbarseparator_p.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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICTOOLBARSEPARATOR_P_H
+#define QDYNAMICTOOLBARSEPARATOR_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 "QtWidgets/qwidget.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_TOOLBAR
+
+class QStyleOption;
+class QToolBar;
+
+class QToolBarSeparator : public QWidget
+{
+ Q_OBJECT
+ Qt::Orientation orient;
+
+public:
+ explicit QToolBarSeparator(QToolBar *parent);
+
+ Qt::Orientation orientation() const;
+
+ QSize sizeHint() const;
+
+ void paintEvent(QPaintEvent *);
+ void initStyleOption(QStyleOption *option) const;
+
+public Q_SLOTS:
+ void setOrientation(Qt::Orientation orientation);
+};
+
+#endif // QT_NO_TOOLBAR
+
+QT_END_NAMESPACE
+
+#endif // QDYNAMICTOOLBARSEPARATOR_P_H
diff --git a/src/widgets/widgets/qtoolbox.cpp b/src/widgets/widgets/qtoolbox.cpp
new file mode 100644
index 0000000000..711bf8c89c
--- /dev/null
+++ b/src/widgets/widgets/qtoolbox.cpp
@@ -0,0 +1,822 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtoolbox.h"
+
+#ifndef QT_NO_TOOLBOX
+
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qlayout.h>
+#include <qlist.h>
+#include <qpainter.h>
+#include <qscrollarea.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qtooltip.h>
+#include <qabstractbutton.h>
+
+#include "qframe_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QToolBoxButton : public QAbstractButton
+{
+ Q_OBJECT
+public:
+ QToolBoxButton(QWidget *parent)
+ : QAbstractButton(parent), selected(false), indexInPage(-1)
+ {
+ setBackgroundRole(QPalette::Window);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ setFocusPolicy(Qt::NoFocus);
+ }
+
+ inline void setSelected(bool b) { selected = b; update(); }
+ inline void setIndex(int newIndex) { indexInPage = newIndex; }
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+protected:
+ void initStyleOption(QStyleOptionToolBox *opt) const;
+ void paintEvent(QPaintEvent *);
+
+private:
+ bool selected;
+ int indexInPage;
+};
+
+
+class QToolBoxPrivate : public QFramePrivate
+{
+ Q_DECLARE_PUBLIC(QToolBox)
+public:
+ struct Page
+ {
+ QToolBoxButton *button;
+ QScrollArea *sv;
+ QWidget *widget;
+
+ inline void setText(const QString &text) { button->setText(text); }
+ inline void setIcon(const QIcon &is) { button->setIcon(is); }
+#ifndef QT_NO_TOOLTIP
+ inline void setToolTip(const QString &tip) { button->setToolTip(tip); }
+ inline QString toolTip() const { return button->toolTip(); }
+#endif
+ inline QString text() const { return button->text(); }
+ inline QIcon icon() const { return button->icon(); }
+
+ inline bool operator==(const Page& other) const
+ {
+ return widget == other.widget;
+ }
+ };
+ typedef QList<Page> PageList;
+
+ inline QToolBoxPrivate()
+ : currentPage(0)
+ {
+ }
+ void _q_buttonClicked();
+ void _q_widgetDestroyed(QObject*);
+
+ Page *page(QWidget *widget) const;
+ const Page *page(int index) const;
+ Page *page(int index);
+
+ void updateTabs();
+ void relayout();
+
+ PageList pageList;
+ QVBoxLayout *layout;
+ Page *currentPage;
+};
+
+QToolBoxPrivate::Page *QToolBoxPrivate::page(QWidget *widget) const
+{
+ if (!widget)
+ return 0;
+
+ for (PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i)
+ if ((*i).widget == widget)
+ return (Page*) &(*i);
+ return 0;
+}
+
+QToolBoxPrivate::Page *QToolBoxPrivate::page(int index)
+{
+ if (index >= 0 && index < pageList.size())
+ return &pageList[index];
+ return 0;
+}
+
+const QToolBoxPrivate::Page *QToolBoxPrivate::page(int index) const
+{
+ if (index >= 0 && index < pageList.size())
+ return &pageList.at(index);
+ return 0;
+}
+
+void QToolBoxPrivate::updateTabs()
+{
+ QToolBoxButton *lastButton = currentPage ? currentPage->button : 0;
+ bool after = false;
+ int index = 0;
+ for (index = 0; index < pageList.count(); ++index) {
+ const Page &page = pageList.at(index);
+ QToolBoxButton *tB = page.button;
+ // update indexes, since the updates are delayed, the indexes will be correct
+ // when we actually paint.
+ tB->setIndex(index);
+ QWidget *tW = page.widget;
+ if (after) {
+ QPalette p = tB->palette();
+ p.setColor(tB->backgroundRole(), tW->palette().color(tW->backgroundRole()));
+ tB->setPalette(p);
+ tB->update();
+ } else if (tB->backgroundRole() != QPalette::Window) {
+ tB->setBackgroundRole(QPalette::Window);
+ tB->update();
+ }
+ after = tB == lastButton;
+ }
+}
+
+QSize QToolBoxButton::sizeHint() const
+{
+ QSize iconSize(8, 8);
+ if (!icon().isNull()) {
+ int icone = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, parentWidget() /* QToolBox */);
+ iconSize += QSize(icone + 2, icone);
+ }
+ QSize textSize = fontMetrics().size(Qt::TextShowMnemonic, text()) + QSize(0, 8);
+
+ QSize total(iconSize.width() + textSize.width(), qMax(iconSize.height(), textSize.height()));
+ return total.expandedTo(QApplication::globalStrut());
+}
+
+QSize QToolBoxButton::minimumSizeHint() const
+{
+ if (icon().isNull())
+ return QSize();
+ int icone = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, parentWidget() /* QToolBox */);
+ return QSize(icone + 8, icone + 8);
+}
+
+void QToolBoxButton::initStyleOption(QStyleOptionToolBox *option) const
+{
+ if (!option)
+ return;
+ option->initFrom(this);
+ if (selected)
+ option->state |= QStyle::State_Selected;
+ if (isDown())
+ option->state |= QStyle::State_Sunken;
+ option->text = text();
+ option->icon = icon();
+
+ if (QStyleOptionToolBoxV2 *optionV2 = qstyleoption_cast<QStyleOptionToolBoxV2 *>(option)) {
+ QToolBox *toolBox = static_cast<QToolBox *>(parentWidget()); // I know I'm in a tool box.
+ int widgetCount = toolBox->count();
+ int currIndex = toolBox->currentIndex();
+ if (widgetCount == 1) {
+ optionV2->position = QStyleOptionToolBoxV2::OnlyOneTab;
+ } else if (indexInPage == 0) {
+ optionV2->position = QStyleOptionToolBoxV2::Beginning;
+ } else if (indexInPage == widgetCount - 1) {
+ optionV2->position = QStyleOptionToolBoxV2::End;
+ } else {
+ optionV2->position = QStyleOptionToolBoxV2::Middle;
+ }
+ if (currIndex == indexInPage - 1) {
+ optionV2->selectedPosition = QStyleOptionToolBoxV2::PreviousIsSelected;
+ } else if (currIndex == indexInPage + 1) {
+ optionV2->selectedPosition = QStyleOptionToolBoxV2::NextIsSelected;
+ } else {
+ optionV2->selectedPosition = QStyleOptionToolBoxV2::NotAdjacent;
+ }
+ }
+}
+
+void QToolBoxButton::paintEvent(QPaintEvent *)
+{
+ QPainter paint(this);
+ QString text = QAbstractButton::text();
+ QPainter *p = &paint;
+ QStyleOptionToolBoxV2 opt;
+ initStyleOption(&opt);
+ style()->drawControl(QStyle::CE_ToolBoxTab, &opt, p, parentWidget());
+}
+
+/*!
+ \class QToolBox
+
+ \brief The QToolBox class provides a column of tabbed widget items.
+
+
+ \ingroup basicwidgets
+
+ A toolbox is a widget that displays a column of tabs one above the
+ other, with the current item displayed below the current tab.
+ Every tab has an index position within the column of tabs. A tab's
+ item is a QWidget.
+
+ Each item has an itemText(), an optional itemIcon(), an optional
+ itemToolTip(), and a widget(). The item's attributes can be
+ changed with setItemText(), setItemIcon(), and
+ setItemToolTip(). Each item can be enabled or disabled
+ individually with setItemEnabled().
+
+ Items are added using addItem(), or inserted at particular
+ positions using insertItem(). The total number of items is given
+ by count(). Items can be deleted with delete, or removed from the
+ toolbox with removeItem(). Combining removeItem() and insertItem()
+ allows you to move items to different positions.
+
+ The index of the current item widget is returned by currentIndex(),
+ and set with setCurrentIndex(). The index of a particular item can
+ be found using indexOf(), and the item at a given index is returned
+ by item().
+
+ The currentChanged() signal is emitted when the current item is
+ changed.
+
+ \sa QTabWidget
+*/
+
+/*!
+ \fn void QToolBox::currentChanged(int index)
+
+ This signal is emitted when the current item is changed. The new
+ current item's index is passed in \a index, or -1 if there is no
+ current item.
+*/
+
+#ifdef QT3_SUPPORT
+/*!
+ Constructs a toolbox called \a name with parent \a parent and flags \a f.
+*/
+QToolBox::QToolBox(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QFrame(*new QToolBoxPrivate, parent, f)
+{
+ Q_D(QToolBox);
+ setObjectName(QString::fromAscii(name));
+ d->layout = new QVBoxLayout(this);
+ d->layout->setMargin(0);
+ setBackgroundRole(QPalette::Button);
+}
+#endif
+
+/*!
+ Constructs a new toolbox with the given \a parent and the flags, \a f.
+*/
+QToolBox::QToolBox(QWidget *parent, Qt::WindowFlags f)
+ : QFrame(*new QToolBoxPrivate, parent, f)
+{
+ Q_D(QToolBox);
+ d->layout = new QVBoxLayout(this);
+ d->layout->setMargin(0);
+ setBackgroundRole(QPalette::Button);
+}
+
+/*!
+ Destroys the toolbox.
+*/
+
+QToolBox::~QToolBox()
+{
+}
+
+/*!
+ \fn int QToolBox::addItem(QWidget *w, const QString &text)
+ \overload
+
+ Adds the widget \a w in a new tab at bottom of the toolbox. The
+ new tab's text is set to \a text. Returns the new tab's index.
+*/
+
+/*!
+ \fn int QToolBox::addItem(QWidget *widget, const QIcon &iconSet,const QString &text)
+ Adds the \a widget in a new tab at bottom of the toolbox. The
+ new tab's text is set to \a text, and the \a iconSet is
+ displayed to the left of the \a text. Returns the new tab's index.
+*/
+
+/*!
+ \fn int QToolBox::insertItem(int index, QWidget *widget, const QString &text)
+ \overload
+
+ Inserts the \a widget at position \a index, or at the bottom
+ of the toolbox if \a index is out of range. The new item's text is
+ set to \a text. Returns the new item's index.
+*/
+
+/*!
+ Inserts the \a widget at position \a index, or at the bottom
+ of the toolbox if \a index is out of range. The new item's text
+ is set to \a text, and the \a icon is displayed to the left of
+ the \a text. Returns the new item's index.
+*/
+
+int QToolBox::insertItem(int index, QWidget *widget, const QIcon &icon, const QString &text)
+{
+ if (!widget)
+ return -1;
+
+ Q_D(QToolBox);
+ connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_q_widgetDestroyed(QObject*)));
+
+ QToolBoxPrivate::Page c;
+ c.widget = widget;
+ c.button = new QToolBoxButton(this);
+ c.button->setObjectName(QLatin1String("qt_toolbox_toolboxbutton"));
+ connect(c.button, SIGNAL(clicked()), this, SLOT(_q_buttonClicked()));
+
+ c.sv = new QScrollArea(this);
+ c.sv->setWidget(widget);
+ c.sv->setWidgetResizable(true);
+ c.sv->hide();
+ c.sv->setFrameStyle(QFrame::NoFrame);
+
+ c.setText(text);
+ c.setIcon(icon);
+
+ if (index < 0 || index >= (int)d->pageList.count()) {
+ index = d->pageList.count();
+ d->pageList.append(c);
+ d->layout->addWidget(c.button);
+ d->layout->addWidget(c.sv);
+ if (index == 0)
+ setCurrentIndex(index);
+ } else {
+ d->pageList.insert(index, c);
+ d->relayout();
+ if (d->currentPage) {
+ QWidget *current = d->currentPage->widget;
+ int oldindex = indexOf(current);
+ if (index <= oldindex) {
+ d->currentPage = 0; // trigger change
+ setCurrentIndex(oldindex);
+ }
+ }
+ }
+
+ c.button->show();
+
+ d->updateTabs();
+ itemInserted(index);
+ return index;
+}
+
+void QToolBoxPrivate::_q_buttonClicked()
+{
+ Q_Q(QToolBox);
+ QToolBoxButton *tb = qobject_cast<QToolBoxButton*>(q->sender());
+ QWidget* item = 0;
+ for (QToolBoxPrivate::PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i)
+ if ((*i).button == tb) {
+ item = (*i).widget;
+ break;
+ }
+
+ q->setCurrentIndex(q->indexOf(item));
+}
+
+/*!
+ \property QToolBox::count
+ \brief The number of items contained in the toolbox.
+
+ By default, this property has a value of 0.
+*/
+
+int QToolBox::count() const
+{
+ Q_D(const QToolBox);
+ return d->pageList.count();
+}
+
+void QToolBox::setCurrentIndex(int index)
+{
+ Q_D(QToolBox);
+ QToolBoxPrivate::Page *c = d->page(index);
+ if (!c || d->currentPage == c)
+ return;
+
+ c->button->setSelected(true);
+ if (d->currentPage) {
+ d->currentPage->sv->hide();
+ d->currentPage->button->setSelected(false);
+ }
+ d->currentPage = c;
+ d->currentPage->sv->show();
+ d->updateTabs();
+ emit currentChanged(index);
+}
+
+void QToolBoxPrivate::relayout()
+{
+ Q_Q(QToolBox);
+ delete layout;
+ layout = new QVBoxLayout(q);
+ layout->setMargin(0);
+ for (QToolBoxPrivate::PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i) {
+ layout->addWidget((*i).button);
+ layout->addWidget((*i).sv);
+ }
+}
+
+void QToolBoxPrivate::_q_widgetDestroyed(QObject *object)
+{
+ Q_Q(QToolBox);
+ // no verification - vtbl corrupted already
+ QWidget *p = (QWidget*)object;
+
+ QToolBoxPrivate::Page *c = page(p);
+ if (!p || !c)
+ return;
+
+ layout->removeWidget(c->sv);
+ layout->removeWidget(c->button);
+ c->sv->deleteLater(); // page might still be a child of sv
+ delete c->button;
+
+ bool removeCurrent = c == currentPage;
+ pageList.removeAll(*c);
+
+ if (!pageList.count()) {
+ currentPage = 0;
+ emit q->currentChanged(-1);
+ } else if (removeCurrent) {
+ currentPage = 0;
+ q->setCurrentIndex(0);
+ }
+}
+
+/*!
+ Removes the item at position \a index from the toolbox. Note that
+ the widget is \e not deleted.
+*/
+
+void QToolBox::removeItem(int index)
+{
+ Q_D(QToolBox);
+ if (QWidget *w = widget(index)) {
+ disconnect(w, SIGNAL(destroyed(QObject*)), this, SLOT(_q_widgetDestroyed(QObject*)));
+ w->setParent(this);
+ // destroy internal data
+ d->_q_widgetDestroyed(w);
+ itemRemoved(index);
+ }
+}
+
+
+/*!
+ \property QToolBox::currentIndex
+ \brief the index of the current item
+
+ By default, for an empty toolbox, this property has a value of -1.
+
+ \sa indexOf(), widget()
+*/
+
+
+int QToolBox::currentIndex() const
+{
+ Q_D(const QToolBox);
+ return d->currentPage ? indexOf(d->currentPage->widget) : -1;
+}
+
+/*!
+ Returns a pointer to the current widget, or 0 if there is no such item.
+
+ \sa currentIndex(), setCurrentWidget()
+*/
+
+QWidget * QToolBox::currentWidget() const
+{
+ Q_D(const QToolBox);
+ return d->currentPage ? d->currentPage->widget : 0;
+}
+
+/*!
+ Makes\a widget the current widget. The \a widget must be an item in this tool box.
+
+ \sa addItem(), setCurrentIndex(), currentWidget()
+ */
+void QToolBox::setCurrentWidget(QWidget *widget)
+{
+ int i = indexOf(widget);
+ if (i >= 0)
+ setCurrentIndex(i);
+ else
+ qWarning("QToolBox::setCurrentWidget: widget not contained in tool box");
+}
+
+/*!
+ Returns the widget at position \a index, or 0 if there is no such
+ item.
+*/
+
+QWidget *QToolBox::widget(int index) const
+{
+ Q_D(const QToolBox);
+ if (index < 0 || index >= (int) d->pageList.size())
+ return 0;
+ return d->pageList.at(index).widget;
+}
+
+/*!
+ Returns the index of \a widget, or -1 if the item does not
+ exist.
+*/
+
+int QToolBox::indexOf(QWidget *widget) const
+{
+ Q_D(const QToolBox);
+ QToolBoxPrivate::Page *c = (widget ? d->page(widget) : 0);
+ return c ? d->pageList.indexOf(*c) : -1;
+}
+
+/*!
+ If \a enabled is true then the item at position \a index is enabled; otherwise
+ the item at position \a index is disabled.
+*/
+
+void QToolBox::setItemEnabled(int index, bool enabled)
+{
+ Q_D(QToolBox);
+ QToolBoxPrivate::Page *c = d->page(index);
+ if (!c)
+ return;
+
+ c->button->setEnabled(enabled);
+ if (!enabled && c == d->currentPage) {
+ int curIndexUp = index;
+ int curIndexDown = curIndexUp;
+ const int count = d->pageList.count();
+ while (curIndexUp > 0 || curIndexDown < count-1) {
+ if (curIndexDown < count-1) {
+ if (d->page(++curIndexDown)->button->isEnabled()) {
+ index = curIndexDown;
+ break;
+ }
+ }
+ if (curIndexUp > 0) {
+ if (d->page(--curIndexUp)->button->isEnabled()) {
+ index = curIndexUp;
+ break;
+ }
+ }
+ }
+ setCurrentIndex(index);
+ }
+}
+
+
+/*!
+ Sets the text of the item at position \a index to \a text.
+
+ If the provided text contains an ampersand character ('&'), a
+ mnemonic is automatically created for it. The character that
+ follows the '&' will be used as the shortcut key. Any previous
+ mnemonic will be overwritten, or cleared if no mnemonic is defined
+ by the text. See the \l {QShortcut#mnemonic}{QShortcut}
+ documentation for details (to display an actual ampersand, use
+ '&&').
+*/
+
+void QToolBox::setItemText(int index, const QString &text)
+{
+ Q_D(QToolBox);
+ QToolBoxPrivate::Page *c = d->page(index);
+ if (c)
+ c->setText(text);
+}
+
+/*!
+ Sets the icon of the item at position \a index to \a icon.
+*/
+
+void QToolBox::setItemIcon(int index, const QIcon &icon)
+{
+ Q_D(QToolBox);
+ QToolBoxPrivate::Page *c = d->page(index);
+ if (c)
+ c->setIcon(icon);
+}
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Sets the tooltip of the item at position \a index to \a toolTip.
+*/
+
+void QToolBox::setItemToolTip(int index, const QString &toolTip)
+{
+ Q_D(QToolBox);
+ QToolBoxPrivate::Page *c = d->page(index);
+ if (c)
+ c->setToolTip(toolTip);
+}
+#endif // QT_NO_TOOLTIP
+
+/*!
+ Returns true if the item at position \a index is enabled; otherwise returns false.
+*/
+
+bool QToolBox::isItemEnabled(int index) const
+{
+ Q_D(const QToolBox);
+ const QToolBoxPrivate::Page *c = d->page(index);
+ return c && c->button->isEnabled();
+}
+
+/*!
+ Returns the text of the item at position \a index, or an empty string if
+ \a index is out of range.
+*/
+
+QString QToolBox::itemText(int index) const
+{
+ Q_D(const QToolBox);
+ const QToolBoxPrivate::Page *c = d->page(index);
+ return (c ? c->text() : QString());
+}
+
+/*!
+ Returns the icon of the item at position \a index, or a null
+ icon if \a index is out of range.
+*/
+
+QIcon QToolBox::itemIcon(int index) const
+{
+ Q_D(const QToolBox);
+ const QToolBoxPrivate::Page *c = d->page(index);
+ return (c ? c->icon() : QIcon());
+}
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Returns the tooltip of the item at position \a index, or an
+ empty string if \a index is out of range.
+*/
+
+QString QToolBox::itemToolTip(int index) const
+{
+ Q_D(const QToolBox);
+ const QToolBoxPrivate::Page *c = d->page(index);
+ return (c ? c->toolTip() : QString());
+}
+#endif // QT_NO_TOOLTIP
+
+/*! \reimp */
+void QToolBox::showEvent(QShowEvent *e)
+{
+ QWidget::showEvent(e);
+}
+
+/*! \reimp */
+void QToolBox::changeEvent(QEvent *ev)
+{
+ Q_D(QToolBox);
+ if(ev->type() == QEvent::StyleChange)
+ d->updateTabs();
+ QFrame::changeEvent(ev);
+}
+
+/*!
+ This virtual handler is called after a new item was added or
+ inserted at position \a index.
+
+ \sa itemRemoved()
+ */
+void QToolBox::itemInserted(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ This virtual handler is called after an item was removed from
+ position \a index.
+
+ \sa itemInserted()
+ */
+void QToolBox::itemRemoved(int index)
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ \fn void QToolBox::setItemLabel(int index, const QString &text)
+
+ Use setItemText() instead.
+*/
+
+/*!
+ \fn QString QToolBox::itemLabel(int index) const
+
+ Use itemText() instead.
+*/
+
+/*!
+ \fn QWidget *QToolBox::currentItem() const
+
+ Use widget(currentIndex()) instead.
+*/
+
+/*!
+ \fn void QToolBox::setCurrentItem(QWidget *widget)
+
+ Use setCurrentIndex(indexOf(widget)) instead.
+*/
+
+/*!
+ \fn void QToolBox::setItemIconSet(int index, const QIcon &icon)
+
+ Use setItemIcon() instead.
+*/
+
+/*!
+ \fn QIcon QToolBox::itemIconSet(int index) const
+
+ Use itemIcon() instead.
+*/
+
+/*!
+ \fn int QToolBox::removeItem(QWidget *widget)
+
+ Use toolbox->removeItem(toolbox->indexOf(widget)) instead.
+*/
+
+/*!
+ \fn QWidget *QToolBox::item(int index) const
+
+ Use widget() instead.
+*/
+
+/*!
+ \fn void QToolBox::setMargin(int margin)
+ Sets the width of the margin around the contents of the widget to \a margin.
+
+ Use QWidget::setContentsMargins() instead.
+ \sa margin(), QWidget::setContentsMargins()
+*/
+
+/*!
+ \fn int QToolBox::margin() const
+ Returns the width of the margin around the contents of the widget.
+
+ Use QWidget::getContentsMargins() instead.
+ \sa setMargin(), QWidget::getContentsMargins()
+*/
+
+/*! \reimp */
+bool QToolBox::event(QEvent *e)
+{
+ return QFrame::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtoolbox.cpp"
+#include "qtoolbox.moc"
+
+#endif //QT_NO_TOOLBOX
diff --git a/src/widgets/widgets/qtoolbox.h b/src/widgets/widgets/qtoolbox.h
new file mode 100644
index 0000000000..b08d37e424
--- /dev/null
+++ b/src/widgets/widgets/qtoolbox.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTOOLBOX_H
+#define QTOOLBOX_H
+
+#include <QtWidgets/qframe.h>
+#include <QtWidgets/qicon.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TOOLBOX
+
+class QToolBoxPrivate;
+
+class Q_WIDGETS_EXPORT QToolBox : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged)
+ Q_PROPERTY(int count READ count)
+
+public:
+ explicit QToolBox(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ ~QToolBox();
+
+ int addItem(QWidget *widget, const QString &text);
+ int addItem(QWidget *widget, const QIcon &icon, const QString &text);
+ int insertItem(int index, QWidget *widget, const QString &text);
+ int insertItem(int index, QWidget *widget, const QIcon &icon, const QString &text);
+
+ void removeItem(int index);
+
+ void setItemEnabled(int index, bool enabled);
+ bool isItemEnabled(int index) const;
+
+ void setItemText(int index, const QString &text);
+ QString itemText(int index) const;
+
+ void setItemIcon(int index, const QIcon &icon);
+ QIcon itemIcon(int index) const;
+
+#ifndef QT_NO_TOOLTIP
+ void setItemToolTip(int index, const QString &toolTip);
+ QString itemToolTip(int index) const;
+#endif
+
+ int currentIndex() const;
+ QWidget *currentWidget() const;
+ QWidget *widget(int index) const;
+ int indexOf(QWidget *widget) const;
+ int count() const;
+
+public Q_SLOTS:
+ void setCurrentIndex(int index);
+ void setCurrentWidget(QWidget *widget);
+
+Q_SIGNALS:
+ void currentChanged(int index);
+
+protected:
+ bool event(QEvent *e);
+ virtual void itemInserted(int index);
+ virtual void itemRemoved(int index);
+ void showEvent(QShowEvent *e);
+ void changeEvent(QEvent *);
+
+#ifdef QT3_SUPPORT
+public:
+ QT3_SUPPORT_CONSTRUCTOR QToolBox(QWidget *parent, const char *name, Qt::WindowFlags f = 0);
+ inline QT3_SUPPORT void setItemLabel(int index, const QString &text) { setItemText(index, text); }
+ inline QT3_SUPPORT QString itemLabel(int index) const { return itemText(index); }
+ inline QT3_SUPPORT QWidget *currentItem() const { return widget(currentIndex()); }
+ inline QT3_SUPPORT void setCurrentItem(QWidget *item) { setCurrentIndex(indexOf(item)); }
+ inline QT3_SUPPORT void setItemIconSet(int index, const QIcon &icon) { setItemIcon(index, icon); }
+ inline QT3_SUPPORT QIcon itemIconSet(int index) const { return itemIcon(index); }
+ inline QT3_SUPPORT int removeItem(QWidget *item)
+ { int i = indexOf(item); removeItem(i); return i; }
+ inline QT3_SUPPORT QWidget *item(int index) const { return widget(index); }
+ QT3_SUPPORT void setMargin(int margin) { setContentsMargins(margin, margin, margin, margin); }
+ QT3_SUPPORT int margin() const
+ { int margin; int dummy; getContentsMargins(&margin, &dummy, &dummy, &dummy); return margin; }
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QToolBox)
+ Q_DISABLE_COPY(QToolBox)
+ Q_PRIVATE_SLOT(d_func(), void _q_buttonClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_widgetDestroyed(QObject*))
+};
+
+
+inline int QToolBox::addItem(QWidget *item, const QString &text)
+{ return insertItem(-1, item, QIcon(), text); }
+inline int QToolBox::addItem(QWidget *item, const QIcon &iconSet,
+ const QString &text)
+{ return insertItem(-1, item, iconSet, text); }
+inline int QToolBox::insertItem(int index, QWidget *item, const QString &text)
+{ return insertItem(index, item, QIcon(), text); }
+
+#endif // QT_NO_TOOLBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTOOLBOX_H
diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp
new file mode 100644
index 0000000000..f023f8af0f
--- /dev/null
+++ b/src/widgets/widgets/qtoolbutton.cpp
@@ -0,0 +1,1247 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtoolbutton.h"
+#ifndef QT_NO_TOOLBUTTON
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qdrawutil.h>
+#include <qevent.h>
+#include <qicon.h>
+#include <qmenu.h>
+#include <qpainter.h>
+#include <qpointer.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qtooltip.h>
+#include <qmainwindow.h>
+#include <qtoolbar.h>
+#include <qvariant.h>
+#include <qstylepainter.h>
+#include <private/qabstractbutton_p.h>
+#include <private/qaction_p.h>
+#include <private/qmenu_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QToolButtonPrivate : public QAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QToolButton)
+public:
+ void init();
+#ifndef QT_NO_MENU
+ void _q_buttonPressed();
+ void popupTimerDone();
+ void _q_updateButtonDown();
+ void _q_menuTriggered(QAction *);
+#endif
+ bool updateHoverControl(const QPoint &pos);
+ void _q_actionTriggered();
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+ QPointer<QAction> menuAction; //the menu set by the user (setMenu)
+ QBasicTimer popupTimer;
+ int delay;
+ Qt::ArrowType arrowType;
+ Qt::ToolButtonStyle toolButtonStyle;
+ QToolButton::ToolButtonPopupMode popupMode;
+ enum { NoButtonPressed=0, MenuButtonPressed=1, ToolButtonPressed=2 };
+ uint buttonPressed : 2;
+ uint menuButtonDown : 1;
+ uint autoRaise : 1;
+ uint repeat : 1;
+ QAction *defaultAction;
+#ifndef QT_NO_MENU
+ bool hasMenu() const;
+ //workaround for task 177850
+ QList<QAction *> actionsCopy;
+#endif
+#ifdef QT3_SUPPORT
+ bool userDefinedPopupDelay;
+#endif
+};
+
+#ifndef QT_NO_MENU
+bool QToolButtonPrivate::hasMenu() const
+{
+ return ((defaultAction && defaultAction->menu())
+ || (menuAction && menuAction->menu())
+ || actions.size() > (defaultAction ? 1 : 0));
+}
+#endif
+
+/*!
+ \class QToolButton
+ \brief The QToolButton class provides a quick-access button to
+ commands or options, usually used inside a QToolBar.
+
+ \ingroup basicwidgets
+
+
+ A tool button is a special button that provides quick-access to
+ specific commands or options. As opposed to a normal command
+ button, a tool button usually doesn't show a text label, but shows
+ an icon instead.
+
+ Tool buttons are normally created when new QAction instances are
+ created with QToolBar::addAction() or existing actions are added
+ to a toolbar with QToolBar::addAction(). It is also possible to
+ construct tool buttons in the same way as any other widget, and
+ arrange them alongside other widgets in layouts.
+
+ One classic use of a tool button is to select tools; for example,
+ the "pen" tool in a drawing program. This would be implemented
+ by using a QToolButton as a toggle button (see setToggleButton()).
+
+ QToolButton supports auto-raising. In auto-raise mode, the button
+ draws a 3D frame only when the mouse points at it. The feature is
+ automatically turned on when a button is used inside a QToolBar.
+ Change it with setAutoRaise().
+
+ A tool button's icon is set as QIcon. This makes it possible to
+ specify different pixmaps for the disabled and active state. The
+ disabled pixmap is used when the button's functionality is not
+ available. The active pixmap is displayed when the button is
+ auto-raised because the mouse pointer is hovering over it.
+
+ The button's look and dimension is adjustable with
+ setToolButtonStyle() and setIconSize(). When used inside a
+ QToolBar in a QMainWindow, the button automatically adjusts to
+ QMainWindow's settings (see QMainWindow::setToolButtonStyle() and
+ QMainWindow::setIconSize()). Instead of an icon, a tool button can
+ also display an arrow symbol, specified with
+ \l{QToolButton::arrowType} {arrowType}.
+
+ A tool button can offer additional choices in a popup menu. The
+ popup menu can be set using setMenu(). Use setPopupMode() to
+ configure the different modes available for tool buttons with a
+ menu set. The default mode is DelayedPopupMode which is sometimes
+ used with the "Back" button in a web browser. After pressing and
+ holding the button down for a while, a menu pops up showing a list
+ of possible pages to jump to. The default delay is 600 ms; you can
+ adjust it with setPopupDelay().
+
+ \table 100%
+ \row \o \inlineimage assistant-toolbar.png Qt Assistant's toolbar with tool buttons
+ \row \o Qt Assistant's toolbar contains tool buttons that are associated
+ with actions used in other parts of the main window.
+ \endtable
+
+ \sa QPushButton, QToolBar, QMainWindow, QAction,
+ {fowler}{GUI Design Handbook: Push Button}
+*/
+
+/*!
+ \fn void QToolButton::triggered(QAction *action)
+
+ This signal is emitted when the given \a action is triggered.
+
+ The action may also be associated with other parts of the user interface,
+ such as menu items and keyboard shortcuts. Sharing actions in this
+ way helps make the user interface more consistent and is often less work
+ to implement.
+*/
+
+/*!
+ Constructs an empty tool button with parent \a
+ parent.
+*/
+QToolButton::QToolButton(QWidget * parent)
+ : QAbstractButton(*new QToolButtonPrivate, parent)
+{
+ Q_D(QToolButton);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Constructs an empty tool button called \a name, with parent \a
+ parent.
+*/
+
+QToolButton::QToolButton(QWidget * parent, const char *name)
+ : QAbstractButton(*new QToolButtonPrivate, parent)
+{
+ Q_D(QToolButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Constructs a tool button called \a name, that is a child of \a
+ parent.
+
+ The tool button will display the given \a icon, with its text
+ label and tool tip set to \a textLabel and its status bar message
+ set to \a statusTip. It will be connected to the \a slot in
+ object \a receiver.
+*/
+
+QToolButton::QToolButton(const QIcon& icon, const QString &textLabel,
+ const QString& statusTip,
+ QObject * receiver, const char *slot,
+ QWidget * parent, const char *name)
+ : QAbstractButton(*new QToolButtonPrivate, parent)
+{
+ Q_D(QToolButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+ setIcon(icon);
+ setText(textLabel);
+ if (receiver && slot)
+ connect(this, SIGNAL(clicked()), receiver, slot);
+#ifndef QT_NO_TOOLTIP
+ if (!textLabel.isEmpty())
+ setToolTip(textLabel);
+#endif
+#ifndef QT_NO_STATUSTIP
+ if (!statusTip.isEmpty())
+ setStatusTip(statusTip);
+#else
+ Q_UNUSED(statusTip);
+#endif
+}
+
+
+/*!
+ Constructs a tool button as an arrow button. The Qt::ArrowType \a
+ type defines the arrow direction. Possible values are
+ Qt::LeftArrow, Qt::RightArrow, Qt::UpArrow, and Qt::DownArrow.
+
+ An arrow button has auto-repeat turned on by default.
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+*/
+QToolButton::QToolButton(Qt::ArrowType type, QWidget *parent, const char *name)
+ : QAbstractButton(*new QToolButtonPrivate, parent)
+{
+ Q_D(QToolButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+ setAutoRepeat(true);
+ d->arrowType = type;
+}
+
+#endif
+
+
+/* Set-up code common to all the constructors */
+
+void QToolButtonPrivate::init()
+{
+ Q_Q(QToolButton);
+ delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, q);
+#ifdef QT3_SUPPORT
+ userDefinedPopupDelay = false;
+#endif
+ defaultAction = 0;
+#ifndef QT_NO_TOOLBAR
+ if (qobject_cast<QToolBar*>(parent))
+ autoRaise = true;
+ else
+#endif
+ autoRaise = false;
+ arrowType = Qt::NoArrow;
+ menuButtonDown = false;
+ popupMode = QToolButton::DelayedPopup;
+ buttonPressed = QToolButtonPrivate::NoButtonPressed;
+
+ toolButtonStyle = Qt::ToolButtonIconOnly;
+ hoverControl = QStyle::SC_None;
+
+ q->setFocusPolicy(Qt::TabFocus);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed,
+ QSizePolicy::ToolButton));
+
+#ifndef QT_NO_MENU
+ QObject::connect(q, SIGNAL(pressed()), q, SLOT(_q_buttonPressed()));
+#endif
+
+ setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
+
+}
+
+/*!
+ Initialize \a option with the values from this QToolButton. This method
+ is useful for subclasses when they need a QStyleOptionToolButton, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QToolButton::initStyleOption(QStyleOptionToolButton *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QToolButton);
+ option->initFrom(this);
+ bool forceNoText = false;
+ option->iconSize = iconSize(); //default value
+
+#ifndef QT_NO_TOOLBAR
+ if (parentWidget()) {
+ if (QToolBar *toolBar = qobject_cast<QToolBar *>(parentWidget())) {
+ option->iconSize = toolBar->iconSize();
+ }
+#ifdef QT3_SUPPORT
+ else if (parentWidget()->inherits("Q3ToolBar")) {
+ if (!option->iconSize.isValid()) {
+ int iconSize = style()->pixelMetric(QStyle::PM_ToolBarIconSize, option, this);
+ option->iconSize = d->icon.actualSize(QSize(iconSize, iconSize));
+ }
+ forceNoText = d->toolButtonStyle == Qt::ToolButtonIconOnly;
+ }
+#endif
+ }
+#endif // QT_NO_TOOLBAR
+
+ if (!forceNoText)
+ option->text = d->text;
+ option->icon = d->icon;
+ option->arrowType = d->arrowType;
+ if (d->down)
+ option->state |= QStyle::State_Sunken;
+ if (d->checked)
+ option->state |= QStyle::State_On;
+ if (d->autoRaise)
+ option->state |= QStyle::State_AutoRaise;
+ if (!d->checked && !d->down)
+ option->state |= QStyle::State_Raised;
+
+ option->subControls = QStyle::SC_ToolButton;
+ option->activeSubControls = QStyle::SC_None;
+
+ option->features = QStyleOptionToolButton::None;
+ if (d->popupMode == QToolButton::MenuButtonPopup) {
+ option->subControls |= QStyle::SC_ToolButtonMenu;
+ option->features |= QStyleOptionToolButton::MenuButtonPopup;
+ }
+ if (option->state & QStyle::State_MouseOver) {
+ option->activeSubControls = d->hoverControl;
+ }
+ if (d->menuButtonDown) {
+ option->state |= QStyle::State_Sunken;
+ option->activeSubControls |= QStyle::SC_ToolButtonMenu;
+ }
+ if (d->down) {
+ option->state |= QStyle::State_Sunken;
+ option->activeSubControls |= QStyle::SC_ToolButton;
+ }
+
+
+ if (d->arrowType != Qt::NoArrow)
+ option->features |= QStyleOptionToolButton::Arrow;
+ if (d->popupMode == QToolButton::DelayedPopup)
+ option->features |= QStyleOptionToolButton::PopupDelay;
+#ifndef QT_NO_MENU
+ if (d->hasMenu())
+ option->features |= QStyleOptionToolButton::HasMenu;
+#endif
+ if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) {
+ option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option, this));
+ } else
+ option->toolButtonStyle = d->toolButtonStyle;
+
+ if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
+ // If the action is not prioritized, remove the text label to save space
+ if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority)
+ option->toolButtonStyle = Qt::ToolButtonIconOnly;
+ }
+
+ if (d->icon.isNull() && d->arrowType == Qt::NoArrow && !forceNoText) {
+ if (!d->text.isEmpty())
+ option->toolButtonStyle = Qt::ToolButtonTextOnly;
+ else if (option->toolButtonStyle != Qt::ToolButtonTextOnly)
+ option->toolButtonStyle = Qt::ToolButtonIconOnly;
+ }
+
+ option->pos = pos();
+ option->font = font();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QToolButton::~QToolButton()
+{
+}
+
+/*!
+ \reimp
+*/
+QSize QToolButton::sizeHint() const
+{
+ Q_D(const QToolButton);
+ if (d->sizeHint.isValid())
+ return d->sizeHint;
+ ensurePolished();
+
+ int w = 0, h = 0;
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+
+ QFontMetrics fm = fontMetrics();
+ if (opt.toolButtonStyle != Qt::ToolButtonTextOnly) {
+ QSize icon = opt.iconSize;
+ w = icon.width();
+ h = icon.height();
+ }
+
+ if (opt.toolButtonStyle != Qt::ToolButtonIconOnly) {
+ QSize textSize = fm.size(Qt::TextShowMnemonic, text());
+ textSize.setWidth(textSize.width() + fm.width(QLatin1Char(' '))*2);
+ if (opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+ h += 4 + textSize.height();
+ if (textSize.width() > w)
+ w = textSize.width();
+ } else if (opt.toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
+ w += 4 + textSize.width();
+ if (textSize.height() > h)
+ h = textSize.height();
+ } else { // TextOnly
+ w = textSize.width();
+ h = textSize.height();
+ }
+ }
+
+ opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
+ if (d->popupMode == MenuButtonPopup)
+ w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
+
+ d->sizeHint = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this).
+ expandedTo(QApplication::globalStrut());
+ return d->sizeHint;
+}
+
+/*!
+ \reimp
+ */
+QSize QToolButton::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \property QToolButton::toolButtonStyle
+ \brief whether the tool button displays an icon only, text only,
+ or text beside/below the icon.
+
+ The default is Qt::ToolButtonIconOnly.
+
+ To have the style of toolbuttons follow the system settings (as available
+ in GNOME and KDE desktop environments), set this property to Qt::ToolButtonFollowStyle.
+
+ QToolButton automatically connects this slot to the relevant
+ signal in the QMainWindow in which is resides.
+*/
+
+/*!
+ \property QToolButton::arrowType
+ \brief whether the button displays an arrow instead of a normal icon
+
+ This displays an arrow as the icon for the QToolButton.
+
+ By default, this property is set to Qt::NoArrow.
+*/
+
+Qt::ToolButtonStyle QToolButton::toolButtonStyle() const
+{
+ Q_D(const QToolButton);
+ return d->toolButtonStyle;
+}
+
+Qt::ArrowType QToolButton::arrowType() const
+{
+ Q_D(const QToolButton);
+ return d->arrowType;
+}
+
+
+void QToolButton::setToolButtonStyle(Qt::ToolButtonStyle style)
+{
+ Q_D(QToolButton);
+ if (d->toolButtonStyle == style)
+ return;
+
+ d->toolButtonStyle = style;
+ d->sizeHint = QSize();
+ updateGeometry();
+ if (isVisible()) {
+ update();
+ }
+}
+
+void QToolButton::setArrowType(Qt::ArrowType type)
+{
+ Q_D(QToolButton);
+ if (d->arrowType == type)
+ return;
+
+ d->arrowType = type;
+ d->sizeHint = QSize();
+ updateGeometry();
+ if (isVisible()) {
+ update();
+ }
+}
+
+/*!
+ \fn void QToolButton::paintEvent(QPaintEvent *event)
+
+ Paints the button in response to the paint \a event.
+*/
+void QToolButton::paintEvent(QPaintEvent *)
+{
+ QStylePainter p(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ p.drawComplexControl(QStyle::CC_ToolButton, opt);
+}
+
+/*!
+ \reimp
+ */
+void QToolButton::actionEvent(QActionEvent *event)
+{
+ Q_D(QToolButton);
+ QAction *action = event->action();
+ switch (event->type()) {
+ case QEvent::ActionChanged:
+ if (action == d->defaultAction)
+ setDefaultAction(action); // update button state
+ break;
+ case QEvent::ActionAdded:
+ connect(action, SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
+ break;
+ case QEvent::ActionRemoved:
+ if (d->defaultAction == action)
+ d->defaultAction = 0;
+#ifndef QT_NO_MENU
+ if (action == d->menuAction)
+ d->menuAction = 0;
+#endif
+ action->disconnect(this);
+ break;
+ default:
+ ;
+ }
+ QAbstractButton::actionEvent(event);
+}
+
+QStyle::SubControl QToolButtonPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QToolButton);
+ QStyleOptionToolButton opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ToolButton, &opt, pos, q);
+ if (hoverControl == QStyle::SC_None)
+ hoverRect = QRect();
+ else
+ hoverRect = q->style()->subControlRect(QStyle::CC_ToolButton, &opt, hoverControl, q);
+ return hoverControl;
+}
+
+bool QToolButtonPrivate::updateHoverControl(const QPoint &pos)
+{
+ Q_Q(QToolButton);
+ QRect lastHoverRect = hoverRect;
+ QStyle::SubControl lastHoverControl = hoverControl;
+ bool doesHover = q->testAttribute(Qt::WA_Hover);
+ if (lastHoverControl != newHoverControl(pos) && doesHover) {
+ q->update(lastHoverRect);
+ q->update(hoverRect);
+ return true;
+ }
+ return !doesHover;
+}
+
+void QToolButtonPrivate::_q_actionTriggered()
+{
+ Q_Q(QToolButton);
+ if (QAction *action = qobject_cast<QAction *>(q->sender()))
+ emit q->triggered(action);
+}
+
+/*!
+ \reimp
+ */
+void QToolButton::enterEvent(QEvent * e)
+{
+ Q_D(QToolButton);
+ if (d->autoRaise)
+ update();
+ if (d->defaultAction)
+ d->defaultAction->hover();
+ QAbstractButton::enterEvent(e);
+}
+
+
+/*!
+ \reimp
+ */
+void QToolButton::leaveEvent(QEvent * e)
+{
+ Q_D(QToolButton);
+ if (d->autoRaise)
+ update();
+
+ QAbstractButton::leaveEvent(e);
+}
+
+
+/*!
+ \reimp
+ */
+void QToolButton::timerEvent(QTimerEvent *e)
+{
+#ifndef QT_NO_MENU
+ Q_D(QToolButton);
+ if (e->timerId() == d->popupTimer.timerId()) {
+ d->popupTimerDone();
+ return;
+ }
+#endif
+ QAbstractButton::timerEvent(e);
+}
+
+
+/*!
+ \reimp
+*/
+void QToolButton::changeEvent(QEvent *e)
+{
+#ifndef QT_NO_TOOLBAR
+ Q_D(QToolButton);
+ if (e->type() == QEvent::ParentChange) {
+ if (qobject_cast<QToolBar*>(parentWidget()))
+ d->autoRaise = true;
+ } else if (e->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || e->type() == QEvent::MacSizeChange
+#endif
+ ) {
+#ifdef QT3_SUPPORT
+ if (!d->userDefinedPopupDelay)
+#endif
+ d->delay = style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, this);
+ d->setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
+ }
+#endif
+ QAbstractButton::changeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QToolButton::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QToolButton);
+#ifndef QT_NO_MENU
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ if (e->button() == Qt::LeftButton && (d->popupMode == MenuButtonPopup)) {
+ QRect popupr = style()->subControlRect(QStyle::CC_ToolButton, &opt,
+ QStyle::SC_ToolButtonMenu, this);
+ if (popupr.isValid() && popupr.contains(e->pos())) {
+ d->buttonPressed = QToolButtonPrivate::MenuButtonPressed;
+ showMenu();
+ return;
+ }
+ }
+#endif
+ d->buttonPressed = QToolButtonPrivate::ToolButtonPressed;
+ QAbstractButton::mousePressEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QToolButton::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QToolButton);
+ QAbstractButton::mouseReleaseEvent(e);
+ d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
+}
+
+/*!
+ \reimp
+*/
+bool QToolButton::hitButton(const QPoint &pos) const
+{
+ Q_D(const QToolButton);
+ if(QAbstractButton::hitButton(pos))
+ return (d->buttonPressed != QToolButtonPrivate::MenuButtonPressed);
+ return false;
+}
+
+#ifdef QT3_SUPPORT
+
+/*!
+ Use icon() instead.
+*/
+QIcon QToolButton::onIconSet() const
+{
+ return icon();
+}
+
+/*!
+ Use icon() instead.
+*/
+QIcon QToolButton::offIconSet() const
+{
+ return icon();
+}
+
+
+/*!
+ \obsolete
+
+ Use setIcon() instead.
+*/
+void QToolButton::setOnIconSet(const QIcon& set)
+{
+ setIcon(set);
+}
+
+/*!
+ \obsolete
+
+ Use setIcon() instead.
+*/
+void QToolButton::setOffIconSet(const QIcon& set)
+{
+ setIcon(set);
+}
+
+
+/*! \overload
+ \obsolete
+
+ Since Qt 3.0, QIcon contains both the On and Off icons.
+
+ For ease of porting, this function ignores the \a on parameter and
+ sets the \l{QAbstractButton::icon} {icon} property. If you relied on
+ the \a on parameter, you probably want to update your code to use
+ the QIcon On/Off mechanism.
+
+ \sa icon QIcon::State
+*/
+
+void QToolButton::setIconSet(const QIcon & set, bool /* on */)
+{
+ QAbstractButton::setIcon(set);
+}
+
+/*! \overload
+ \obsolete
+
+ Since Qt 3.0, QIcon contains both the On and Off icons.
+
+ For ease of porting, this function ignores the \a on parameter and
+ returns the \l{QAbstractButton::icon} {icon} property. If you relied
+ on the \a on parameter, you probably want to update your code to use
+ the QIcon On/Off mechanism.
+*/
+QIcon QToolButton::iconSet(bool /* on */) const
+{
+ return QAbstractButton::icon();
+}
+
+#endif
+
+#ifndef QT_NO_MENU
+/*!
+ Associates the given \a menu with this tool button.
+
+ The menu will be shown according to the button's \l popupMode.
+
+ Ownership of the menu is not transferred to the tool button.
+
+ \sa menu()
+*/
+void QToolButton::setMenu(QMenu* menu)
+{
+ Q_D(QToolButton);
+
+ if (d->menuAction)
+ removeAction(d->menuAction);
+
+ if (menu) {
+ d->menuAction = menu->menuAction();
+ addAction(d->menuAction);
+ } else {
+ d->menuAction = 0;
+ }
+ update();
+}
+
+/*!
+ Returns the associated menu, or 0 if no menu has been defined.
+
+ \sa setMenu()
+*/
+QMenu* QToolButton::menu() const
+{
+ Q_D(const QToolButton);
+ if (d->menuAction)
+ return d->menuAction->menu();
+ return 0;
+}
+
+/*!
+ Shows (pops up) the associated popup menu. If there is no such
+ menu, this function does nothing. This function does not return
+ until the popup menu has been closed by the user.
+*/
+void QToolButton::showMenu()
+{
+ Q_D(QToolButton);
+ if (!d->hasMenu()) {
+ d->menuButtonDown = false;
+ return; // no menu to show
+ }
+
+ d->menuButtonDown = true;
+ repaint();
+ d->popupTimer.stop();
+ d->popupTimerDone();
+}
+
+void QToolButtonPrivate::_q_buttonPressed()
+{
+ Q_Q(QToolButton);
+ if (!hasMenu())
+ return; // no menu to show
+ if (popupMode == QToolButton::MenuButtonPopup)
+ return;
+ else if (delay > 0 && !popupTimer.isActive() && popupMode == QToolButton::DelayedPopup)
+ popupTimer.start(delay, q);
+ else if (delay == 0 || popupMode == QToolButton::InstantPopup)
+ q->showMenu();
+}
+
+void QToolButtonPrivate::popupTimerDone()
+{
+ Q_Q(QToolButton);
+ popupTimer.stop();
+ if (!menuButtonDown && !down)
+ return;
+
+ menuButtonDown = true;
+ QPointer<QMenu> actualMenu;
+ bool mustDeleteActualMenu = false;
+ if(menuAction) {
+ actualMenu = menuAction->menu();
+ } else if (defaultAction && defaultAction->menu()) {
+ actualMenu = defaultAction->menu();
+ } else {
+ actualMenu = new QMenu(q);
+ mustDeleteActualMenu = true;
+ for(int i = 0; i < actions.size(); i++)
+ actualMenu->addAction(actions.at(i));
+ }
+ repeat = q->autoRepeat();
+ q->setAutoRepeat(false);
+ bool horizontal = true;
+#if !defined(QT_NO_TOOLBAR)
+ QToolBar *tb = qobject_cast<QToolBar*>(parent);
+ if (tb && tb->orientation() == Qt::Vertical)
+ horizontal = false;
+#endif
+ QPoint p;
+ QRect screen = QApplication::desktop()->availableGeometry(q);
+ QSize sh = ((QToolButton*)(QMenu*)actualMenu)->receivers(SIGNAL(aboutToShow()))? QSize() : actualMenu->sizeHint();
+ QRect rect = q->rect();
+ if (horizontal) {
+ if (q->isRightToLeft()) {
+ if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
+ p = q->mapToGlobal(rect.bottomRight());
+ } else {
+ p = q->mapToGlobal(rect.topRight() - QPoint(0, sh.height()));
+ }
+ p.rx() -= sh.width();
+ } else {
+ if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
+ p = q->mapToGlobal(rect.bottomLeft());
+ } else {
+ p = q->mapToGlobal(rect.topLeft() - QPoint(0, sh.height()));
+ }
+ }
+ } else {
+ if (q->isRightToLeft()) {
+ if (q->mapToGlobal(QPoint(rect.left(), 0)).x() - sh.width() <= screen.x()) {
+ p = q->mapToGlobal(rect.topRight());
+ } else {
+ p = q->mapToGlobal(rect.topLeft());
+ p.rx() -= sh.width();
+ }
+ } else {
+ if (q->mapToGlobal(QPoint(rect.right(), 0)).x() + sh.width() <= screen.right()) {
+ p = q->mapToGlobal(rect.topRight());
+ } else {
+ p = q->mapToGlobal(rect.topLeft() - QPoint(sh.width(), 0));
+ }
+ }
+ }
+ p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width()));
+ p.ry() += 1;
+ QPointer<QToolButton> that = q;
+ actualMenu->setNoReplayFor(q);
+ if (!mustDeleteActualMenu) //only if action are not in this widget
+ QObject::connect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
+ QObject::connect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
+ actualMenu->d_func()->causedPopup.widget = q;
+ actualMenu->d_func()->causedPopup.action = defaultAction;
+ actionsCopy = q->actions(); //(the list of action may be modified in slots)
+ actualMenu->exec(p);
+ QObject::disconnect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
+ if (mustDeleteActualMenu)
+ delete actualMenu;
+ else
+ QObject::disconnect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
+
+ if (!that)
+ return;
+
+ actionsCopy.clear();
+
+ if (repeat)
+ q->setAutoRepeat(true);
+}
+
+void QToolButtonPrivate::_q_updateButtonDown()
+{
+ Q_Q(QToolButton);
+ menuButtonDown = false;
+ if (q->isDown())
+ q->setDown(false);
+ else
+ q->repaint();
+}
+
+void QToolButtonPrivate::_q_menuTriggered(QAction *action)
+{
+ Q_Q(QToolButton);
+ if (action && !actionsCopy.contains(action))
+ emit q->triggered(action);
+}
+#endif // QT_NO_MENU
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn void QToolButton::setPopupDelay(int delay)
+
+ Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
+*/
+void QToolButton::setPopupDelay(int delay)
+{
+ Q_D(QToolButton);
+ d->userDefinedPopupDelay = true;
+ d->delay = delay;
+
+ update();
+}
+
+/*!
+ Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
+*/
+int QToolButton::popupDelay() const
+{
+ Q_D(const QToolButton);
+ return d->delay;
+}
+#endif
+
+#ifndef QT_NO_MENU
+/*! \enum QToolButton::ToolButtonPopupMode
+
+ Describes how a menu should be popped up for tool buttons that has
+ a menu set or contains a list of actions.
+
+ \value DelayedPopup After pressing and holding the tool button
+ down for a certain amount of time (the timeout is style dependant,
+ see QStyle::SH_ToolButton_PopupDelay), the menu is displayed. A
+ typical application example is the "back" button in some web
+ browsers's tool bars. If the user clicks it, the browser simply
+ browses back to the previous page. If the user presses and holds
+ the button down for a while, the tool button shows a menu
+ containing the current history list
+
+ \value MenuButtonPopup In this mode the tool button displays a
+ special arrow to indicate that a menu is present. The menu is
+ displayed when the arrow part of the button is pressed.
+
+ \value InstantPopup The menu is displayed, without delay, when
+ the tool button is pressed. In this mode, the button's own action
+ is not triggered.
+*/
+
+/*!
+ \property QToolButton::popupMode
+ \brief describes the way that popup menus are used with tool buttons
+
+ By default, this property is set to \l DelayedPopup.
+*/
+
+void QToolButton::setPopupMode(ToolButtonPopupMode mode)
+{
+ Q_D(QToolButton);
+ d->popupMode = mode;
+}
+
+QToolButton::ToolButtonPopupMode QToolButton::popupMode() const
+{
+ Q_D(const QToolButton);
+ return d->popupMode;
+}
+#endif
+
+/*!
+ \property QToolButton::autoRaise
+ \brief whether auto-raising is enabled or not.
+
+ The default is disabled (i.e. false).
+
+ This property is currently ignored on Mac OS X when using QMacStyle.
+*/
+void QToolButton::setAutoRaise(bool enable)
+{
+ Q_D(QToolButton);
+ d->autoRaise = enable;
+
+ update();
+}
+
+bool QToolButton::autoRaise() const
+{
+ Q_D(const QToolButton);
+ return d->autoRaise;
+}
+
+/*!
+ Sets the default action to \a action.
+
+ If a tool button has a default action, the action defines the
+ button's properties like text, icon, tool tip, etc.
+ */
+void QToolButton::setDefaultAction(QAction *action)
+{
+ Q_D(QToolButton);
+#ifndef QT_NO_MENU
+ bool hadMenu = false;
+ hadMenu = d->hasMenu();
+#endif
+ d->defaultAction = action;
+ if (!action)
+ return;
+ if (!actions().contains(action))
+ addAction(action);
+ setText(action->iconText());
+ setIcon(action->icon());
+#ifndef QT_NO_TOOLTIP
+ setToolTip(action->toolTip());
+#endif
+#ifndef QT_NO_STATUSTIP
+ setStatusTip(action->statusTip());
+#endif
+#ifndef QT_NO_WHATSTHIS
+ setWhatsThis(action->whatsThis());
+#endif
+#ifndef QT_NO_MENU
+ if (action->menu() && !hadMenu) {
+ // new 'default' popup mode defined introduced by tool bar. We
+ // should have changed QToolButton's default instead. Do that
+ // in 4.2.
+ setPopupMode(QToolButton::MenuButtonPopup);
+ }
+#endif
+ setCheckable(action->isCheckable());
+ setChecked(action->isChecked());
+ setEnabled(action->isEnabled());
+ if (action->d_func()->fontSet)
+ setFont(action->font());
+}
+
+
+/*!
+ Returns the default action.
+
+ \sa setDefaultAction()
+ */
+QAction *QToolButton::defaultAction() const
+{
+ Q_D(const QToolButton);
+ return d->defaultAction;
+}
+
+
+
+/*!
+ \reimp
+ */
+void QToolButton::nextCheckState()
+{
+ Q_D(QToolButton);
+ if (!d->defaultAction)
+ QAbstractButton::nextCheckState();
+ else
+ d->defaultAction->trigger();
+}
+
+/*! \reimp */
+bool QToolButton::event(QEvent *event)
+{
+ switch(event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d_func()->updateHoverControl(he->pos());
+ break;
+ default:
+ break;
+ }
+ return QAbstractButton::event(event);
+}
+
+/*! \internal
+ */
+QToolButton::QToolButton(QToolButtonPrivate &dd, QWidget *parent)
+ :QAbstractButton(dd, parent)
+{
+ Q_D(QToolButton);
+ d->init();
+}
+
+/*!
+ \fn void QToolButton::setPixmap(const QPixmap &pixmap)
+
+ Use setIcon(QIcon(pixmap)) instead.
+*/
+
+/*!
+ \fn void QToolButton::setIconSet(const QIcon &icon)
+
+ Use setIcon() instead.
+*/
+
+/*!
+ \fn void QToolButton::setTextLabel(const QString &text, bool tooltip)
+
+ Use setText() and setToolTip() instead.
+*/
+
+/*!
+ \fn QString QToolButton::textLabel() const
+
+ Use text() instead.
+*/
+
+/*!
+ \fn QIcon QToolButton::iconSet() const
+
+ Use icon() instead.
+*/
+
+/*!
+ \fn void QToolButton::openPopup()
+
+ Use showMenu() instead.
+*/
+
+/*!
+ \fn void QToolButton::setPopup(QMenu* popup)
+
+ Use setMenu() instead.
+*/
+
+/*!
+ \fn QMenu* QToolButton::popup() const
+
+ Use menu() instead.
+*/
+
+/*!
+ \fn TextPosition QToolButton::textPosition() const
+
+ Use toolButtonStyle() instead.
+*/
+
+/*!
+ \fn void QToolButton::setTextPosition(QToolButton::TextPosition pos)
+
+ Use setToolButtonStyle() instead.
+*/
+
+/*!
+ \fn bool QToolButton::usesBigPixmap() const
+
+ Use iconSize() instead.
+*/
+
+/*!
+ \fn void QToolButton::setUsesBigPixmap(bool enable)
+
+ Use setIconSize() instead.
+*/
+
+/*!
+ \fn bool QToolButton::usesTextLabel() const
+
+ Use toolButtonStyle() instead.
+*/
+
+/*!
+ \fn void QToolButton::setUsesTextLabel(bool enable)
+
+ Use setToolButtonStyle() instead.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qtoolbutton.cpp"
+
+#endif
diff --git a/src/widgets/widgets/qtoolbutton.h b/src/widgets/widgets/qtoolbutton.h
new file mode 100644
index 0000000000..7d1ff13409
--- /dev/null
+++ b/src/widgets/widgets/qtoolbutton.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTOOLBUTTON_H
+#define QTOOLBUTTON_H
+
+#include <QtWidgets/qabstractbutton.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_TOOLBUTTON
+
+class QToolButtonPrivate;
+class QMenu;
+class QStyleOptionToolButton;
+
+class Q_WIDGETS_EXPORT QToolButton : public QAbstractButton
+{
+ Q_OBJECT
+ Q_ENUMS(Qt::ToolButtonStyle Qt::ArrowType ToolButtonPopupMode)
+#ifndef QT_NO_MENU
+ Q_PROPERTY(ToolButtonPopupMode popupMode READ popupMode WRITE setPopupMode)
+#endif
+ Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle)
+ Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise)
+ Q_PROPERTY(Qt::ArrowType arrowType READ arrowType WRITE setArrowType)
+
+public:
+ enum ToolButtonPopupMode {
+ DelayedPopup,
+ MenuButtonPopup,
+ InstantPopup
+ };
+
+ explicit QToolButton(QWidget * parent=0);
+ ~QToolButton();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ Qt::ToolButtonStyle toolButtonStyle() const;
+
+ Qt::ArrowType arrowType() const;
+ void setArrowType(Qt::ArrowType type);
+
+#ifndef QT_NO_MENU
+ void setMenu(QMenu* menu);
+ QMenu* menu() const;
+
+ void setPopupMode(ToolButtonPopupMode mode);
+ ToolButtonPopupMode popupMode() const;
+#endif
+
+ QAction *defaultAction() const;
+
+ void setAutoRaise(bool enable);
+ bool autoRaise() const;
+
+public Q_SLOTS:
+#ifndef QT_NO_MENU
+ void showMenu();
+#endif
+ void setToolButtonStyle(Qt::ToolButtonStyle style);
+ void setDefaultAction(QAction *);
+
+Q_SIGNALS:
+ void triggered(QAction *);
+
+protected:
+ QToolButton(QToolButtonPrivate &, QWidget* parent);
+ bool event(QEvent *e);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void paintEvent(QPaintEvent *);
+ void actionEvent(QActionEvent *);
+
+ void enterEvent(QEvent *);
+ void leaveEvent(QEvent *);
+ void timerEvent(QTimerEvent *);
+ void changeEvent(QEvent *);
+
+ bool hitButton(const QPoint &pos) const;
+ void nextCheckState();
+ void initStyleOption(QStyleOptionToolButton *option) const;
+
+private:
+ Q_DISABLE_COPY(QToolButton)
+ Q_DECLARE_PRIVATE(QToolButton)
+#ifndef QT_NO_MENU
+ Q_PRIVATE_SLOT(d_func(), void _q_buttonPressed())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateButtonDown())
+ Q_PRIVATE_SLOT(d_func(), void _q_menuTriggered(QAction*))
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered())
+
+#ifdef QT3_SUPPORT
+public:
+ enum TextPosition {
+ BesideIcon,
+ BelowIcon
+ , Right = BesideIcon,
+ Under = BelowIcon
+ };
+
+ QT3_SUPPORT_CONSTRUCTOR QToolButton(QWidget * parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QToolButton(Qt::ArrowType type, QWidget *parent, const char* name);
+ QT3_SUPPORT_CONSTRUCTOR QToolButton( const QIcon& s, const QString &textLabel,
+ const QString& grouptext,
+ QObject * receiver, const char* slot,
+ QWidget * parent, const char* name=0 );
+ inline QT3_SUPPORT void setPixmap(const QPixmap &pixmap) { setIcon(static_cast<QIcon>(pixmap)); }
+ QT3_SUPPORT void setOnIconSet(const QIcon&);
+ QT3_SUPPORT void setOffIconSet(const QIcon&);
+ inline QT3_SUPPORT void setIconSet(const QIcon &icon){setIcon(icon);}
+ QT3_SUPPORT void setIconSet(const QIcon &, bool on);
+ inline QT3_SUPPORT void setTextLabel(const QString &text, bool tooltip = true) {
+ setText(text);
+#ifndef QT_NO_TOOLTIP
+ if (tooltip)
+ setToolTip(text);
+#else
+ Q_UNUSED(tooltip);
+#endif
+ }
+ inline QT3_SUPPORT QString textLabel() const { return text(); }
+ QT3_SUPPORT QIcon onIconSet() const;
+ QT3_SUPPORT QIcon offIconSet() const;
+ QT3_SUPPORT QIcon iconSet(bool on) const;
+ inline QT3_SUPPORT QIcon iconSet() const { return icon(); }
+ inline QT3_SUPPORT void openPopup() { showMenu(); }
+ inline QT3_SUPPORT void setPopup(QMenu* popup) {setMenu(popup); }
+ inline QT3_SUPPORT QMenu* popup() const { return menu(); }
+ inline QT3_SUPPORT bool usesBigPixmap() const { return iconSize().height() > 22; }
+ inline QT3_SUPPORT bool usesTextLabel() const { return toolButtonStyle() != Qt::ToolButtonIconOnly; }
+ inline QT3_SUPPORT TextPosition textPosition() const
+ { return toolButtonStyle() == Qt::ToolButtonTextUnderIcon ? BelowIcon : BesideIcon; }
+ QT3_SUPPORT void setPopupDelay(int delay);
+ QT3_SUPPORT int popupDelay() const;
+
+public Q_SLOTS:
+ QT_MOC_COMPAT void setUsesBigPixmap(bool enable)
+ { setIconSize(enable?QSize(32,32):QSize(22,22)); }
+ QT_MOC_COMPAT void setUsesTextLabel(bool enable)
+ { setToolButtonStyle(enable?Qt::ToolButtonTextUnderIcon : Qt::ToolButtonIconOnly); }
+ QT_MOC_COMPAT void setTextPosition(QToolButton::TextPosition pos)
+ { setToolButtonStyle(pos == BesideIcon ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonTextUnderIcon); }
+
+#endif
+};
+
+#endif // QT_NO_TOOLBUTTON
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTOOLBUTTON_H
diff --git a/src/widgets/widgets/qwidgetanimator.cpp b/src/widgets/widgets/qwidgetanimator.cpp
new file mode 100644
index 0000000000..9df7dfc0eb
--- /dev/null
+++ b/src/widgets/widgets/qwidgetanimator.cpp
@@ -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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qpropertyanimation.h>
+#include <QtWidgets/qwidget.h>
+#include <private/qmainwindowlayout_p.h>
+
+#include "qwidgetanimator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QWidgetAnimator::QWidgetAnimator(QMainWindowLayout *layout) : m_mainWindowLayout(layout)
+{
+}
+
+void QWidgetAnimator::abort(QWidget *w)
+{
+#ifndef QT_NO_ANIMATION
+ AnimationMap::iterator it = m_animation_map.find(w);
+ if (it == m_animation_map.end())
+ return;
+ QPropertyAnimation *anim = *it;
+ m_animation_map.erase(it);
+ anim->stop();
+#ifndef QT_NO_MAINWINDOW
+ m_mainWindowLayout->animationFinished(w);
+#endif
+#else
+ Q_UNUSED(w); //there is no animation to abort
+#endif //QT_NO_ANIMATION
+}
+
+#ifndef QT_NO_ANIMATION
+void QWidgetAnimator::animationFinished()
+{
+ QPropertyAnimation *anim = qobject_cast<QPropertyAnimation*>(sender());
+ abort(static_cast<QWidget*>(anim->targetObject()));
+}
+#endif //QT_NO_ANIMATION
+
+void QWidgetAnimator::animate(QWidget *widget, const QRect &_final_geometry, bool animate)
+{
+ QRect r = widget->geometry();
+ if (r.right() < 0 || r.bottom() < 0)
+ r = QRect();
+
+ animate = animate && !r.isNull() && !_final_geometry.isNull();
+
+ // might make the wigdet go away by sending it to negative space
+ const QRect final_geometry = _final_geometry.isValid() || widget->isWindow() ? _final_geometry :
+ QRect(QPoint(-500 - widget->width(), -500 - widget->height()), widget->size());
+
+#ifndef QT_NO_ANIMATION
+ AnimationMap::const_iterator it = m_animation_map.constFind(widget);
+ if (it != m_animation_map.constEnd() && (*it)->endValue().toRect() == final_geometry)
+ return;
+
+ QPropertyAnimation *anim = new QPropertyAnimation(widget, "geometry", widget);
+ anim->setDuration(animate ? 200 : 0);
+ anim->setEasingCurve(QEasingCurve::InOutQuad);
+ anim->setEndValue(final_geometry);
+ m_animation_map[widget] = anim;
+ connect(anim, SIGNAL(finished()), SLOT(animationFinished()));
+ anim->start(QPropertyAnimation::DeleteWhenStopped);
+#else
+ //we do it in one shot
+ widget->setGeometry(final_geometry);
+#ifndef QT_NO_MAINWINDOW
+ m_mainWindowLayout->animationFinished(widget);
+#endif //QT_NO_MAINWINDOW
+#endif //QT_NO_ANIMATION
+}
+
+bool QWidgetAnimator::animating() const
+{
+ return !m_animation_map.isEmpty();
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qwidgetanimator_p.h b/src/widgets/widgets/qwidgetanimator_p.h
new file mode 100644
index 0000000000..40a2f274eb
--- /dev/null
+++ b/src/widgets/widgets/qwidgetanimator_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGET_ANIMATOR_P_H
+#define QWIDGET_ANIMATOR_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 <qobject.h>
+#include <qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+class QMainWindowLayout;
+class QPropertyAnimation;
+class QRect;
+
+class QWidgetAnimator : public QObject
+{
+ Q_OBJECT
+public:
+ QWidgetAnimator(QMainWindowLayout *layout);
+ void animate(QWidget *widget, const QRect &final_geometry, bool animate);
+ bool animating() const;
+
+ void abort(QWidget *widget);
+
+#ifndef QT_NO_ANIMATION
+private Q_SLOTS:
+ void animationFinished();
+#endif
+
+private:
+ typedef QMap<QWidget*, QPropertyAnimation*> AnimationMap;
+ AnimationMap m_animation_map;
+ QMainWindowLayout *m_mainWindowLayout;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGET_ANIMATOR_P_H
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
new file mode 100644
index 0000000000..790ed73f99
--- /dev/null
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -0,0 +1,1862 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetlinecontrol_p.h"
+
+#ifndef QT_NO_LINEEDIT
+
+#include "qabstractitemview.h"
+#include "qclipboard.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#include "qlist.h"
+#endif
+#include "qapplication.h"
+#ifndef QT_NO_GRAPHICSVIEW
+#include "qgraphicssceneevent.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ Updates the internal text layout. Returns the ascent of the
+ created QTextLine.
+*/
+int QWidgetLineControl::redoTextLayout() const
+{
+ m_textLayout.clearLayout();
+
+ m_textLayout.beginLayout();
+ QTextLine l = m_textLayout.createLine();
+ m_textLayout.endLayout();
+
+#if defined(Q_WS_MAC)
+ if (m_threadChecks)
+ m_textLayoutThread = QThread::currentThread();
+#endif
+
+ return qRound(l.ascent());
+}
+
+/*!
+ \internal
+
+ Updates the display text based of the current edit text
+ If the text has changed will emit displayTextChanged()
+*/
+void QWidgetLineControl::updateDisplayText(bool forceUpdate)
+{
+ QString orig = m_textLayout.text();
+ QString str;
+ if (m_echoMode == QLineEdit::NoEcho)
+ str = QString::fromLatin1("");
+ else
+ str = m_text;
+
+ if (m_echoMode == QLineEdit::Password || (m_echoMode == QLineEdit::PasswordEchoOnEdit
+ && !m_passwordEchoEditing))
+ str.fill(m_passwordCharacter);
+
+ // replace certain non-printable characters with spaces (to avoid
+ // drawing boxes when using fonts that don't have glyphs for such
+ // characters)
+ QChar* uc = str.data();
+ for (int i = 0; i < (int)str.length(); ++i) {
+ if ((uc[i] < 0x20 && uc[i] != 0x09)
+ || uc[i] == QChar::LineSeparator
+ || uc[i] == QChar::ParagraphSeparator
+ || uc[i] == QChar::ObjectReplacementCharacter)
+ uc[i] = QChar(0x0020);
+ }
+
+ m_textLayout.setText(str);
+
+ QTextOption option = m_textLayout.textOption();
+ option.setTextDirection(m_layoutDirection);
+ option.setFlags(QTextOption::IncludeTrailingSpaces);
+ m_textLayout.setTextOption(option);
+
+ m_ascent = redoTextLayout();
+
+ if (str != orig || forceUpdate)
+ emit displayTextChanged(str);
+}
+
+#ifndef QT_NO_CLIPBOARD
+/*!
+ \internal
+
+ Copies the currently selected text into the clipboard using the given
+ \a mode.
+
+ \note If the echo mode is set to a mode other than Normal then copy
+ will not work. This is to prevent using copy as a method of bypassing
+ password features of the line control.
+*/
+void QWidgetLineControl::copy(QClipboard::Mode mode) const
+{
+ QString t = selectedText();
+ if (!t.isEmpty() && m_echoMode == QLineEdit::Normal) {
+ disconnect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
+ QApplication::clipboard()->setText(t, mode);
+ connect(QApplication::clipboard(), SIGNAL(selectionChanged()),
+ this, SLOT(_q_clipboardChanged()));
+ }
+}
+
+/*!
+ \internal
+
+ Inserts the text stored in the application clipboard into the line
+ control.
+
+ \sa insert()
+*/
+void QWidgetLineControl::paste(QClipboard::Mode clipboardMode)
+{
+ QString clip = QApplication::clipboard()->text(clipboardMode);
+ if (!clip.isEmpty() || hasSelectedText()) {
+ separate(); //make it a separate undo/redo command
+ insert(clip);
+ separate();
+ }
+}
+
+#endif // !QT_NO_CLIPBOARD
+
+/*!
+ \internal
+
+ Handles the behavior for the backspace key or function.
+ Removes the current selection if there is a selection, otherwise
+ removes the character prior to the cursor position.
+
+ \sa del()
+*/
+void QWidgetLineControl::backspace()
+{
+ int priorState = m_undoState;
+ if (hasSelectedText()) {
+ removeSelectedText();
+ } else if (m_cursor) {
+ --m_cursor;
+ if (m_maskData)
+ m_cursor = prevMaskBlank(m_cursor);
+ QChar uc = m_text.at(m_cursor);
+ if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
+ // second half of a surrogate, check if we have the first half as well,
+ // if yes delete both at once
+ uc = m_text.at(m_cursor - 1);
+ if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
+ internalDelete(true);
+ --m_cursor;
+ }
+ }
+ internalDelete(true);
+ }
+ finishChange(priorState);
+}
+
+/*!
+ \internal
+
+ Handles the behavior for the delete key or function.
+ Removes the current selection if there is a selection, otherwise
+ removes the character after the cursor position.
+
+ \sa del()
+*/
+void QWidgetLineControl::del()
+{
+ int priorState = m_undoState;
+ if (hasSelectedText()) {
+ removeSelectedText();
+ } else {
+ int n = textLayout()->nextCursorPosition(m_cursor) - m_cursor;
+ while (n--)
+ internalDelete();
+ }
+ finishChange(priorState);
+}
+
+/*!
+ \internal
+
+ Inserts the given \a newText at the current cursor position.
+ If there is any selected text it is removed prior to insertion of
+ the new text.
+*/
+void QWidgetLineControl::insert(const QString &newText)
+{
+ int priorState = m_undoState;
+ removeSelectedText();
+ internalInsert(newText);
+ finishChange(priorState);
+}
+
+/*!
+ \internal
+
+ Clears the line control text.
+*/
+void QWidgetLineControl::clear()
+{
+ int priorState = m_undoState;
+ m_selstart = 0;
+ m_selend = m_text.length();
+ removeSelectedText();
+ separate();
+ finishChange(priorState, /*update*/false, /*edited*/false);
+}
+
+/*!
+ \internal
+
+ Sets \a length characters from the given \a start position as selected.
+ The given \a start position must be within the current text for
+ the line control. If \a length characters cannot be selected, then
+ the selection will extend to the end of the current text.
+*/
+void QWidgetLineControl::setSelection(int start, int length)
+{
+ if(start < 0 || start > (int)m_text.length()){
+ qWarning("QWidgetLineControl::setSelection: Invalid start position");
+ return;
+ }
+
+ if (length > 0) {
+ if (start == m_selstart && start + length == m_selend)
+ return;
+ m_selstart = start;
+ m_selend = qMin(start + length, (int)m_text.length());
+ m_cursor = m_selend;
+ } else if (length < 0){
+ if (start == m_selend && start + length == m_selstart)
+ return;
+ m_selstart = qMax(start + length, 0);
+ m_selend = start;
+ m_cursor = m_selstart;
+ } else if (m_selstart != m_selend) {
+ m_selstart = 0;
+ m_selend = 0;
+ m_cursor = start;
+ } else {
+ m_cursor = start;
+ emitCursorPositionChanged();
+ return;
+ }
+ emit selectionChanged();
+ emitCursorPositionChanged();
+}
+
+void QWidgetLineControl::_q_clipboardChanged()
+{
+}
+
+void QWidgetLineControl::_q_deleteSelected()
+{
+ if (!hasSelectedText())
+ return;
+
+ int priorState = m_undoState;
+ emit resetInputContext();
+ removeSelectedText();
+ separate();
+ finishChange(priorState);
+}
+
+/*!
+ \internal
+
+ Initializes the line control with a starting text value of \a txt.
+*/
+void QWidgetLineControl::init(const QString &txt)
+{
+ m_text = txt;
+ updateDisplayText();
+ m_cursor = m_text.length();
+}
+
+/*!
+ \internal
+
+ Sets the password echo editing to \a editing. If password echo editing
+ is true, then the text of the password is displayed even if the echo
+ mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
+ does not affect other echo modes.
+*/
+void QWidgetLineControl::updatePasswordEchoEditing(bool editing)
+{
+ m_passwordEchoEditing = editing;
+ updateDisplayText();
+}
+
+/*!
+ \internal
+
+ Returns the cursor position of the given \a x pixel value in relation
+ to the displayed text. The given \a betweenOrOn specified what kind
+ of cursor position is requested.
+*/
+int QWidgetLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
+{
+ return textLayout()->lineAt(0).xToCursor(x, betweenOrOn);
+}
+
+/*!
+ \internal
+
+ Returns the bounds of the current cursor, as defined as a
+ between characters cursor.
+*/
+QRect QWidgetLineControl::cursorRect() const
+{
+ QTextLine l = textLayout()->lineAt(0);
+ int c = m_cursor;
+ if (m_preeditCursor != -1)
+ c += m_preeditCursor;
+ int cix = qRound(l.cursorToX(c));
+ int w = m_cursorWidth;
+ int ch = l.height() + 1;
+
+ return QRect(cix-5, 0, w+9, ch);
+}
+
+/*!
+ \internal
+
+ Fixes the current text so that it is valid given any set validators.
+
+ Returns true if the text was changed. Otherwise returns false.
+*/
+bool QWidgetLineControl::fixup() // this function assumes that validate currently returns != Acceptable
+{
+#ifndef QT_NO_VALIDATOR
+ if (m_validator) {
+ QString textCopy = m_text;
+ int cursorCopy = m_cursor;
+ m_validator->fixup(textCopy);
+ if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
+ if (textCopy != m_text || cursorCopy != m_cursor)
+ internalSetText(textCopy, cursorCopy);
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+/*!
+ \internal
+
+ Moves the cursor to the given position \a pos. If \a mark is true will
+ adjust the currently selected text.
+*/
+void QWidgetLineControl::moveCursor(int pos, bool mark)
+{
+ if (pos != m_cursor) {
+ separate();
+ if (m_maskData)
+ pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
+ }
+ if (mark) {
+ int anchor;
+ if (m_selend > m_selstart && m_cursor == m_selstart)
+ anchor = m_selend;
+ else if (m_selend > m_selstart && m_cursor == m_selend)
+ anchor = m_selstart;
+ else
+ anchor = m_cursor;
+ m_selstart = qMin(anchor, pos);
+ m_selend = qMax(anchor, pos);
+ updateDisplayText();
+ } else {
+ internalDeselect();
+ }
+ m_cursor = pos;
+ if (mark || m_selDirty) {
+ m_selDirty = false;
+ emit selectionChanged();
+ }
+ emitCursorPositionChanged();
+}
+
+/*!
+ \internal
+
+ Applies the given input method event \a event to the text of the line
+ control
+*/
+void QWidgetLineControl::processInputMethodEvent(QInputMethodEvent *event)
+{
+ int priorState = 0;
+ bool isGettingInput = !event->commitString().isEmpty()
+ || event->preeditString() != preeditAreaText()
+ || event->replacementLength() > 0;
+ bool cursorPositionChanged = false;
+
+ if (isGettingInput) {
+ // If any text is being input, remove selected text.
+ priorState = m_undoState;
+ if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) {
+ updatePasswordEchoEditing(true);
+ m_selstart = 0;
+ m_selend = m_text.length();
+ }
+ removeSelectedText();
+ }
+
+ int c = m_cursor; // cursor position after insertion of commit string
+ if (event->replacementStart() <= 0)
+ c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
+
+ m_cursor += event->replacementStart();
+ if (m_cursor < 0)
+ m_cursor = 0;
+
+ // insert commit string
+ if (event->replacementLength()) {
+ m_selstart = m_cursor;
+ m_selend = m_selstart + event->replacementLength();
+ removeSelectedText();
+ }
+ if (!event->commitString().isEmpty()) {
+ internalInsert(event->commitString());
+ cursorPositionChanged = true;
+ }
+
+ m_cursor = qBound(0, c, m_text.length());
+
+ for (int i = 0; i < event->attributes().size(); ++i) {
+ const QInputMethodEvent::Attribute &a = event->attributes().at(i);
+ if (a.type == QInputMethodEvent::Selection) {
+ m_cursor = qBound(0, a.start + a.length, m_text.length());
+ if (a.length) {
+ m_selstart = qMax(0, qMin(a.start, m_text.length()));
+ m_selend = m_cursor;
+ if (m_selend < m_selstart) {
+ qSwap(m_selstart, m_selend);
+ }
+ } else {
+ m_selstart = m_selend = 0;
+ }
+ cursorPositionChanged = true;
+ }
+ }
+#ifndef QT_NO_IM
+ setPreeditArea(m_cursor, event->preeditString());
+#endif //QT_NO_IM
+ const int oldPreeditCursor = m_preeditCursor;
+ m_preeditCursor = event->preeditString().length();
+ m_hideCursor = false;
+ QList<QTextLayout::FormatRange> formats;
+ for (int i = 0; i < event->attributes().size(); ++i) {
+ const QInputMethodEvent::Attribute &a = event->attributes().at(i);
+ if (a.type == QInputMethodEvent::Cursor) {
+ m_preeditCursor = a.start;
+ m_hideCursor = !a.length;
+ } else if (a.type == QInputMethodEvent::TextFormat) {
+ QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
+ if (f.isValid()) {
+ QTextLayout::FormatRange o;
+ o.start = a.start + m_cursor;
+ o.length = a.length;
+ o.format = f;
+ formats.append(o);
+ }
+ }
+ }
+ m_textLayout.setAdditionalFormats(formats);
+ updateDisplayText(/*force*/ true);
+ if (cursorPositionChanged)
+ emitCursorPositionChanged();
+ else if (m_preeditCursor != oldPreeditCursor)
+ emit updateMicroFocus();
+ if (isGettingInput)
+ finishChange(priorState);
+}
+
+/*!
+ \internal
+
+ Draws the display text for the line control using the given
+ \a painter, \a clip, and \a offset. Which aspects of the display text
+ are drawn is specified by the given \a flags.
+
+ If the flags contain DrawSelections, then the selection or input mask
+ backgrounds and foregrounds will be applied before drawing the text.
+
+ If the flags contain DrawCursor a cursor of the current cursorWidth()
+ will be drawn after drawing the text.
+
+ The display text will only be drawn if the flags contain DrawText
+*/
+void QWidgetLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags)
+{
+ QVector<QTextLayout::FormatRange> selections;
+ if (flags & DrawSelections) {
+ QTextLayout::FormatRange o;
+ if (m_selstart < m_selend) {
+ o.start = m_selstart;
+ o.length = m_selend - m_selstart;
+ o.format.setBackground(m_palette.brush(QPalette::Highlight));
+ o.format.setForeground(m_palette.brush(QPalette::HighlightedText));
+ } else {
+ // mask selection
+ if(!m_blinkPeriod || m_blinkStatus){
+ o.start = m_cursor;
+ o.length = 1;
+ o.format.setBackground(m_palette.brush(QPalette::Text));
+ o.format.setForeground(m_palette.brush(QPalette::Window));
+ }
+ }
+ selections.append(o);
+ }
+
+ if (flags & DrawText)
+ textLayout()->draw(painter, offset, selections, clip);
+
+ if (flags & DrawCursor){
+ int cursor = m_cursor;
+ if (m_preeditCursor != -1)
+ cursor += m_preeditCursor;
+ if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
+ textLayout()->drawCursor(painter, offset, cursor, m_cursorWidth);
+ }
+}
+
+/*!
+ \internal
+
+ Sets the selection to cover the word at the given cursor position.
+ The word boundaries are defined by the behavior of QTextLayout::SkipWords
+ cursor mode.
+*/
+void QWidgetLineControl::selectWordAtPos(int cursor)
+{
+ int next = cursor + 1;
+ if(next > end())
+ --next;
+ int c = textLayout()->previousCursorPosition(next, QTextLayout::SkipWords);
+ moveCursor(c, false);
+ // ## text layout should support end of words.
+ int end = textLayout()->nextCursorPosition(c, QTextLayout::SkipWords);
+ while (end > cursor && m_text[end-1].isSpace())
+ --end;
+ moveCursor(end, true);
+}
+
+/*!
+ \internal
+
+ Completes a change to the line control text. If the change is not valid
+ will undo the line control state back to the given \a validateFromState.
+
+ If \a edited is true and the change is valid, will emit textEdited() in
+ addition to textChanged(). Otherwise only emits textChanged() on a valid
+ change.
+
+ The \a update value is currently unused.
+*/
+bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool edited)
+{
+ Q_UNUSED(update)
+ bool lineDirty = m_selDirty;
+ if (m_textDirty) {
+ // do validation
+ bool wasValidInput = m_validInput;
+ m_validInput = true;
+#ifndef QT_NO_VALIDATOR
+ if (m_validator) {
+ m_validInput = false;
+ QString textCopy = m_text;
+ int cursorCopy = m_cursor;
+ m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
+ if (m_validInput) {
+ if (m_text != textCopy) {
+ internalSetText(textCopy, cursorCopy);
+ return true;
+ }
+ m_cursor = cursorCopy;
+ }
+ }
+#endif
+ if (validateFromState >= 0 && wasValidInput && !m_validInput) {
+ if (m_transactions.count())
+ return false;
+ internalUndo(validateFromState);
+ m_history.resize(m_undoState);
+ if (m_modifiedState > m_undoState)
+ m_modifiedState = -1;
+ m_validInput = true;
+ m_textDirty = false;
+ }
+ updateDisplayText();
+ lineDirty |= m_textDirty;
+ if (m_textDirty) {
+ m_textDirty = false;
+ QString actualText = text();
+ if (edited)
+ emit textEdited(actualText);
+ emit textChanged(actualText);
+ }
+ }
+ if (m_selDirty) {
+ m_selDirty = false;
+ emit selectionChanged();
+ }
+ emitCursorPositionChanged();
+ return true;
+}
+
+/*!
+ \internal
+
+ An internal function for setting the text of the line control.
+*/
+void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edited)
+{
+ internalDeselect();
+ emit resetInputContext();
+ QString oldText = m_text;
+ if (m_maskData) {
+ m_text = maskString(0, txt, true);
+ m_text += clearString(m_text.length(), m_maxLength - m_text.length());
+ } else {
+ m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
+ }
+ m_history.clear();
+ m_modifiedState = m_undoState = 0;
+ m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
+ m_textDirty = (oldText != m_text);
+ bool changed = finishChange(-1, true, edited);
+
+#ifndef QT_NO_ACCESSIBILITY
+ if (changed)
+ QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
+#endif
+}
+
+
+/*!
+ \internal
+
+ Adds the given \a command to the undo history
+ of the line control. Does not apply the command.
+*/
+void QWidgetLineControl::addCommand(const Command &cmd)
+{
+ if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
+ m_history.resize(m_undoState + 2);
+ m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
+ } else {
+ m_history.resize(m_undoState + 1);
+ }
+ m_separator = false;
+ m_history[m_undoState++] = cmd;
+}
+
+/*!
+ \internal
+
+ Inserts the given string \a s into the line
+ control.
+
+ Also adds the appropriate commands into the undo history.
+ This function does not call finishChange(), and may leave the text
+ in an invalid state.
+*/
+void QWidgetLineControl::internalInsert(const QString &s)
+{
+ if (hasSelectedText())
+ addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
+ if (m_maskData) {
+ QString ms = maskString(m_cursor, s);
+ for (int i = 0; i < (int) ms.length(); ++i) {
+ addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
+ addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
+ }
+ m_text.replace(m_cursor, ms.length(), ms);
+ m_cursor += ms.length();
+ m_cursor = nextMaskBlank(m_cursor);
+ m_textDirty = true;
+ } else {
+ int remaining = m_maxLength - m_text.length();
+ if (remaining != 0) {
+ m_text.insert(m_cursor, s.left(remaining));
+ for (int i = 0; i < (int) s.left(remaining).length(); ++i)
+ addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
+ m_textDirty = true;
+ }
+ }
+}
+
+/*!
+ \internal
+
+ deletes a single character from the current text. If \a wasBackspace,
+ the character prior to the cursor is removed. Otherwise the character
+ after the cursor is removed.
+
+ Also adds the appropriate commands into the undo history.
+ This function does not call finishChange(), and may leave the text
+ in an invalid state.
+*/
+void QWidgetLineControl::internalDelete(bool wasBackspace)
+{
+ if (m_cursor < (int) m_text.length()) {
+ if (hasSelectedText())
+ addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
+ addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
+ m_cursor, m_text.at(m_cursor), -1, -1));
+ if (m_maskData) {
+ m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
+ addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
+ } else {
+ m_text.remove(m_cursor, 1);
+ }
+ m_textDirty = true;
+ }
+}
+
+/*!
+ \internal
+
+ removes the currently selected text from the line control.
+
+ Also adds the appropriate commands into the undo history.
+ This function does not call finishChange(), and may leave the text
+ in an invalid state.
+*/
+void QWidgetLineControl::removeSelectedText()
+{
+ if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
+ separate();
+ int i ;
+ addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
+ if (m_selstart <= m_cursor && m_cursor < m_selend) {
+ // cursor is within the selection. Split up the commands
+ // to be able to restore the correct cursor position
+ for (i = m_cursor; i >= m_selstart; --i)
+ addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
+ for (i = m_selend - 1; i > m_cursor; --i)
+ addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
+ } else {
+ for (i = m_selend-1; i >= m_selstart; --i)
+ addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
+ }
+ if (m_maskData) {
+ m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
+ for (int i = 0; i < m_selend - m_selstart; ++i)
+ addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
+ } else {
+ m_text.remove(m_selstart, m_selend - m_selstart);
+ }
+ if (m_cursor > m_selstart)
+ m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
+ internalDeselect();
+ m_textDirty = true;
+ }
+}
+
+/*!
+ \internal
+
+ Parses the input mask specified by \a maskFields to generate
+ the mask data used to handle input masks.
+*/
+void QWidgetLineControl::parseInputMask(const QString &maskFields)
+{
+ int delimiter = maskFields.indexOf(QLatin1Char(';'));
+ if (maskFields.isEmpty() || delimiter == 0) {
+ if (m_maskData) {
+ delete [] m_maskData;
+ m_maskData = 0;
+ m_maxLength = 32767;
+ internalSetText(QString());
+ }
+ return;
+ }
+
+ if (delimiter == -1) {
+ m_blank = QLatin1Char(' ');
+ m_inputMask = maskFields;
+ } else {
+ m_inputMask = maskFields.left(delimiter);
+ m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
+ }
+
+ // calculate m_maxLength / m_maskData length
+ m_maxLength = 0;
+ QChar c = 0;
+ for (int i=0; i<m_inputMask.length(); i++) {
+ c = m_inputMask.at(i);
+ if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
+ m_maxLength++;
+ continue;
+ }
+ if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
+ c != QLatin1Char('<') && c != QLatin1Char('>') &&
+ c != QLatin1Char('{') && c != QLatin1Char('}') &&
+ c != QLatin1Char('[') && c != QLatin1Char(']'))
+ m_maxLength++;
+ }
+
+ delete [] m_maskData;
+ m_maskData = new MaskInputData[m_maxLength];
+
+ MaskInputData::Casemode m = MaskInputData::NoCaseMode;
+ c = 0;
+ bool s;
+ bool escape = false;
+ int index = 0;
+ for (int i = 0; i < m_inputMask.length(); i++) {
+ c = m_inputMask.at(i);
+ if (escape) {
+ s = true;
+ m_maskData[index].maskChar = c;
+ m_maskData[index].separator = s;
+ m_maskData[index].caseMode = m;
+ index++;
+ escape = false;
+ } else if (c == QLatin1Char('<')) {
+ m = MaskInputData::Lower;
+ } else if (c == QLatin1Char('>')) {
+ m = MaskInputData::Upper;
+ } else if (c == QLatin1Char('!')) {
+ m = MaskInputData::NoCaseMode;
+ } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
+ switch (c.unicode()) {
+ case 'A':
+ case 'a':
+ case 'N':
+ case 'n':
+ case 'X':
+ case 'x':
+ case '9':
+ case '0':
+ case 'D':
+ case 'd':
+ case '#':
+ case 'H':
+ case 'h':
+ case 'B':
+ case 'b':
+ s = false;
+ break;
+ case '\\':
+ escape = true;
+ default:
+ s = true;
+ break;
+ }
+
+ if (!escape) {
+ m_maskData[index].maskChar = c;
+ m_maskData[index].separator = s;
+ m_maskData[index].caseMode = m;
+ index++;
+ }
+ }
+ }
+ internalSetText(m_text);
+}
+
+
+/*!
+ \internal
+
+ checks if the key is valid compared to the inputMask
+*/
+bool QWidgetLineControl::isValidInput(QChar key, QChar mask) const
+{
+ switch (mask.unicode()) {
+ case 'A':
+ if (key.isLetter())
+ return true;
+ break;
+ case 'a':
+ if (key.isLetter() || key == m_blank)
+ return true;
+ break;
+ case 'N':
+ if (key.isLetterOrNumber())
+ return true;
+ break;
+ case 'n':
+ if (key.isLetterOrNumber() || key == m_blank)
+ return true;
+ break;
+ case 'X':
+ if (key.isPrint())
+ return true;
+ break;
+ case 'x':
+ if (key.isPrint() || key == m_blank)
+ return true;
+ break;
+ case '9':
+ if (key.isNumber())
+ return true;
+ break;
+ case '0':
+ if (key.isNumber() || key == m_blank)
+ return true;
+ break;
+ case 'D':
+ if (key.isNumber() && key.digitValue() > 0)
+ return true;
+ break;
+ case 'd':
+ if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
+ return true;
+ break;
+ case '#':
+ if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
+ return true;
+ break;
+ case 'B':
+ if (key == QLatin1Char('0') || key == QLatin1Char('1'))
+ return true;
+ break;
+ case 'b':
+ if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
+ return true;
+ break;
+ case 'H':
+ if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
+ return true;
+ break;
+ case 'h':
+ if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Returns true if the given text \a str is valid for any
+ validator or input mask set for the line control.
+
+ Otherwise returns false
+*/
+bool QWidgetLineControl::hasAcceptableInput(const QString &str) const
+{
+#ifndef QT_NO_VALIDATOR
+ QString textCopy = str;
+ int cursorCopy = m_cursor;
+ if (m_validator && m_validator->validate(textCopy, cursorCopy)
+ != QValidator::Acceptable)
+ return false;
+#endif
+
+ if (!m_maskData)
+ return true;
+
+ if (str.length() != m_maxLength)
+ return false;
+
+ for (int i=0; i < m_maxLength; ++i) {
+ if (m_maskData[i].separator) {
+ if (str.at(i) != m_maskData[i].maskChar)
+ return false;
+ } else {
+ if (!isValidInput(str.at(i), m_maskData[i].maskChar))
+ return false;
+ }
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
+ specifies from where characters should be gotten when a separator is met in \a str - true means
+ that blanks will be used, false that previous input is used.
+ Calling this when no inputMask is set is undefined.
+*/
+QString QWidgetLineControl::maskString(uint pos, const QString &str, bool clear) const
+{
+ if (pos >= (uint)m_maxLength)
+ return QString::fromLatin1("");
+
+ QString fill;
+ fill = clear ? clearString(0, m_maxLength) : m_text;
+
+ int strIndex = 0;
+ QString s = QString::fromLatin1("");
+ int i = pos;
+ while (i < m_maxLength) {
+ if (strIndex < str.length()) {
+ if (m_maskData[i].separator) {
+ s += m_maskData[i].maskChar;
+ if (str[(int)strIndex] == m_maskData[i].maskChar)
+ strIndex++;
+ ++i;
+ } else {
+ if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
+ switch (m_maskData[i].caseMode) {
+ case MaskInputData::Upper:
+ s += str[(int)strIndex].toUpper();
+ break;
+ case MaskInputData::Lower:
+ s += str[(int)strIndex].toLower();
+ break;
+ default:
+ s += str[(int)strIndex];
+ }
+ ++i;
+ } else {
+ // search for separator first
+ int n = findInMask(i, true, true, str[(int)strIndex]);
+ if (n != -1) {
+ if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
+ s += fill.mid(i, n-i+1);
+ i = n + 1; // update i to find + 1
+ }
+ } else {
+ // search for valid m_blank if not
+ n = findInMask(i, true, false, str[(int)strIndex]);
+ if (n != -1) {
+ s += fill.mid(i, n-i);
+ switch (m_maskData[n].caseMode) {
+ case MaskInputData::Upper:
+ s += str[(int)strIndex].toUpper();
+ break;
+ case MaskInputData::Lower:
+ s += str[(int)strIndex].toLower();
+ break;
+ default:
+ s += str[(int)strIndex];
+ }
+ i = n + 1; // updates i to find + 1
+ }
+ }
+ }
+ ++strIndex;
+ }
+ } else
+ break;
+ }
+
+ return s;
+}
+
+
+
+/*!
+ \internal
+
+ Returns a "cleared" string with only separators and blank chars.
+ Calling this when no inputMask is set is undefined.
+*/
+QString QWidgetLineControl::clearString(uint pos, uint len) const
+{
+ if (pos >= (uint)m_maxLength)
+ return QString();
+
+ QString s;
+ int end = qMin((uint)m_maxLength, pos + len);
+ for (int i = pos; i < end; ++i)
+ if (m_maskData[i].separator)
+ s += m_maskData[i].maskChar;
+ else
+ s += m_blank;
+
+ return s;
+}
+
+/*!
+ \internal
+
+ Strips blank parts of the input in a QWidgetLineControl when an inputMask is set,
+ separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
+*/
+QString QWidgetLineControl::stripString(const QString &str) const
+{
+ if (!m_maskData)
+ return str;
+
+ QString s;
+ int end = qMin(m_maxLength, (int)str.length());
+ for (int i = 0; i < end; ++i)
+ if (m_maskData[i].separator)
+ s += m_maskData[i].maskChar;
+ else
+ if (str[i] != m_blank)
+ s += str[i];
+
+ return s;
+}
+
+/*!
+ \internal
+ searches forward/backward in m_maskData for either a separator or a m_blank
+*/
+int QWidgetLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
+{
+ if (pos >= m_maxLength || pos < 0)
+ return -1;
+
+ int end = forward ? m_maxLength : -1;
+ int step = forward ? 1 : -1;
+ int i = pos;
+
+ while (i != end) {
+ if (findSeparator) {
+ if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
+ return i;
+ } else {
+ if (!m_maskData[i].separator) {
+ if (searchChar.isNull())
+ return i;
+ else if (isValidInput(searchChar, m_maskData[i].maskChar))
+ return i;
+ }
+ }
+ i += step;
+ }
+ return -1;
+}
+
+void QWidgetLineControl::internalUndo(int until)
+{
+ if (!isUndoAvailable())
+ return;
+ internalDeselect();
+ while (m_undoState && m_undoState > until) {
+ Command& cmd = m_history[--m_undoState];
+ switch (cmd.type) {
+ case Insert:
+ m_text.remove(cmd.pos, 1);
+ m_cursor = cmd.pos;
+ break;
+ case SetSelection:
+ m_selstart = cmd.selStart;
+ m_selend = cmd.selEnd;
+ m_cursor = cmd.pos;
+ break;
+ case Remove:
+ case RemoveSelection:
+ m_text.insert(cmd.pos, cmd.uc);
+ m_cursor = cmd.pos + 1;
+ break;
+ case Delete:
+ case DeleteSelection:
+ m_text.insert(cmd.pos, cmd.uc);
+ m_cursor = cmd.pos;
+ break;
+ case Separator:
+ continue;
+ }
+ if (until < 0 && m_undoState) {
+ Command& next = m_history[m_undoState-1];
+ if (next.type != cmd.type && next.type < RemoveSelection
+ && (cmd.type < RemoveSelection || next.type == Separator))
+ break;
+ }
+ }
+ m_textDirty = true;
+ emitCursorPositionChanged();
+}
+
+void QWidgetLineControl::internalRedo()
+{
+ if (!isRedoAvailable())
+ return;
+ internalDeselect();
+ while (m_undoState < (int)m_history.size()) {
+ Command& cmd = m_history[m_undoState++];
+ switch (cmd.type) {
+ case Insert:
+ m_text.insert(cmd.pos, cmd.uc);
+ m_cursor = cmd.pos + 1;
+ break;
+ case SetSelection:
+ m_selstart = cmd.selStart;
+ m_selend = cmd.selEnd;
+ m_cursor = cmd.pos;
+ break;
+ case Remove:
+ case Delete:
+ case RemoveSelection:
+ case DeleteSelection:
+ m_text.remove(cmd.pos, 1);
+ m_selstart = cmd.selStart;
+ m_selend = cmd.selEnd;
+ m_cursor = cmd.pos;
+ break;
+ case Separator:
+ m_selstart = cmd.selStart;
+ m_selend = cmd.selEnd;
+ m_cursor = cmd.pos;
+ break;
+ }
+ if (m_undoState < (int)m_history.size()) {
+ Command& next = m_history[m_undoState];
+ if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
+ && (next.type < RemoveSelection || cmd.type == Separator))
+ break;
+ }
+ }
+ m_textDirty = true;
+ emitCursorPositionChanged();
+}
+
+/*!
+ \internal
+
+ If the current cursor position differs from the last emitted cursor
+ position, emits cursorPositionChanged().
+*/
+void QWidgetLineControl::emitCursorPositionChanged()
+{
+ if (m_cursor != m_lastCursorPos) {
+ const int oldLast = m_lastCursorPos;
+ m_lastCursorPos = m_cursor;
+ cursorPositionChanged(oldLast, m_cursor);
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved);
+#endif
+ }
+}
+
+#ifndef QT_NO_COMPLETER
+// iterating forward(dir=1)/backward(dir=-1) from the
+// current row based. dir=0 indicates a new completion prefix was set.
+bool QWidgetLineControl::advanceToEnabledItem(int dir)
+{
+ int start = m_completer->currentRow();
+ if (start == -1)
+ return false;
+ int i = start + dir;
+ if (dir == 0) dir = 1;
+ do {
+ if (!m_completer->setCurrentRow(i)) {
+ if (!m_completer->wrapAround())
+ break;
+ i = i > 0 ? 0 : m_completer->completionCount() - 1;
+ } else {
+ QModelIndex currentIndex = m_completer->currentIndex();
+ if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
+ return true;
+ i += dir;
+ }
+ } while (i != start);
+
+ m_completer->setCurrentRow(start); // restore
+ return false;
+}
+
+void QWidgetLineControl::complete(int key)
+{
+ if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
+ return;
+
+ QString text = this->text();
+ if (m_completer->completionMode() == QCompleter::InlineCompletion) {
+ if (key == Qt::Key_Backspace)
+ return;
+ int n = 0;
+ if (key == Qt::Key_Up || key == Qt::Key_Down) {
+ if (textAfterSelection().length())
+ return;
+ QString prefix = hasSelectedText() ? textBeforeSelection()
+ : text;
+ if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0
+ || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) {
+ m_completer->setCompletionPrefix(prefix);
+ } else {
+ n = (key == Qt::Key_Up) ? -1 : +1;
+ }
+ } else {
+ m_completer->setCompletionPrefix(text);
+ }
+ if (!advanceToEnabledItem(n))
+ return;
+ } else {
+#ifndef QT_KEYPAD_NAVIGATION
+ if (text.isEmpty()) {
+ m_completer->popup()->hide();
+ return;
+ }
+#endif
+ m_completer->setCompletionPrefix(text);
+ }
+
+ m_completer->complete();
+}
+#endif
+
+void QWidgetLineControl::setCursorBlinkPeriod(int msec)
+{
+ if (msec == m_blinkPeriod)
+ return;
+ if (m_blinkTimer) {
+ killTimer(m_blinkTimer);
+ }
+ if (msec) {
+ m_blinkTimer = startTimer(msec / 2);
+ m_blinkStatus = 1;
+ } else {
+ m_blinkTimer = 0;
+ if (m_blinkStatus == 1)
+ emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
+ }
+ m_blinkPeriod = msec;
+}
+
+void QWidgetLineControl::resetCursorBlinkTimer()
+{
+ if (m_blinkPeriod == 0 || m_blinkTimer == 0)
+ return;
+ killTimer(m_blinkTimer);
+ m_blinkTimer = startTimer(m_blinkPeriod / 2);
+ m_blinkStatus = 1;
+}
+
+void QWidgetLineControl::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_blinkTimer) {
+ m_blinkStatus = !m_blinkStatus;
+ emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
+ } else if (event->timerId() == m_deleteAllTimer) {
+ killTimer(m_deleteAllTimer);
+ m_deleteAllTimer = 0;
+ clear();
+ } else if (event->timerId() == m_tripleClickTimer) {
+ killTimer(m_tripleClickTimer);
+ m_tripleClickTimer = 0;
+ }
+}
+
+bool QWidgetLineControl::processEvent(QEvent* ev)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled()) {
+ if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) {
+ QKeyEvent *ke = (QKeyEvent *)ev;
+ if (ke->key() == Qt::Key_Back) {
+ if (ke->isAutoRepeat()) {
+ // Swallow it. We don't want back keys running amok.
+ ke->accept();
+ return true;
+ }
+ if ((ev->type() == QEvent::KeyRelease)
+ && !isReadOnly()
+ && m_deleteAllTimer) {
+ killTimer(m_deleteAllTimer);
+ m_deleteAllTimer = 0;
+ backspace();
+ ke->accept();
+ return true;
+ }
+ }
+ }
+ }
+#endif
+ switch(ev->type()){
+#ifndef QT_NO_GRAPHICSVIEW
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMousePress:{
+ QGraphicsSceneMouseEvent *gvEv = static_cast<QGraphicsSceneMouseEvent*>(ev);
+ QMouseEvent mouse(ev->type(),
+ gvEv->pos(), gvEv->pos(), gvEv->screenPos(), gvEv->button(), gvEv->buttons(), gvEv->modifiers());
+ processMouseEvent(&mouse); break;
+ }
+#endif
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ processMouseEvent(static_cast<QMouseEvent*>(ev)); break;
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ processKeyEvent(static_cast<QKeyEvent*>(ev)); break;
+ case QEvent::InputMethod:
+ processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break;
+#ifndef QT_NO_SHORTCUT
+ case QEvent::ShortcutOverride:{
+ if (isReadOnly())
+ return false;
+ QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
+ if (ke == QKeySequence::Copy
+ || ke == QKeySequence::Paste
+ || ke == QKeySequence::Cut
+ || ke == QKeySequence::Redo
+ || ke == QKeySequence::Undo
+ || ke == QKeySequence::MoveToNextWord
+ || ke == QKeySequence::MoveToPreviousWord
+ || ke == QKeySequence::MoveToStartOfDocument
+ || ke == QKeySequence::MoveToEndOfDocument
+ || ke == QKeySequence::SelectNextWord
+ || ke == QKeySequence::SelectPreviousWord
+ || ke == QKeySequence::SelectStartOfLine
+ || ke == QKeySequence::SelectEndOfLine
+ || ke == QKeySequence::SelectStartOfBlock
+ || ke == QKeySequence::SelectEndOfBlock
+ || ke == QKeySequence::SelectStartOfDocument
+ || ke == QKeySequence::SelectAll
+ || ke == QKeySequence::SelectEndOfDocument) {
+ ke->accept();
+ } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
+ || ke->modifiers() == Qt::KeypadModifier) {
+ if (ke->key() < Qt::Key_Escape) {
+ ke->accept();
+ } else {
+ switch (ke->key()) {
+ case Qt::Key_Delete:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Backspace:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ ke->accept();
+ default:
+ break;
+ }
+ }
+ }
+ }
+#endif
+ default:
+ return false;
+ }
+ return true;
+}
+
+void QWidgetLineControl::processMouseEvent(QMouseEvent* ev)
+{
+
+ switch (ev->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::MouseButtonPress:{
+ if (m_tripleClickTimer
+ && (ev->pos() - m_tripleClick).manhattanLength()
+ < QApplication::startDragDistance()) {
+ selectAll();
+ return;
+ }
+ if (ev->button() == Qt::RightButton)
+ return;
+
+ bool mark = ev->modifiers() & Qt::ShiftModifier;
+ int cursor = xToPos(ev->pos().x());
+ moveCursor(cursor, mark);
+ break;
+ }
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::MouseButtonDblClick:
+ if (ev->button() == Qt::LeftButton) {
+ selectWordAtPos(xToPos(ev->pos().x()));
+ if (m_tripleClickTimer)
+ killTimer(m_tripleClickTimer);
+ m_tripleClickTimer = startTimer(QApplication::doubleClickInterval());
+ m_tripleClick = ev->pos();
+ }
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::MouseButtonRelease:
+#ifndef QT_NO_CLIPBOARD
+ if (QApplication::clipboard()->supportsSelection()) {
+ if (ev->button() == Qt::LeftButton) {
+ copy(QClipboard::Selection);
+ } else if (!isReadOnly() && ev->button() == Qt::MidButton) {
+ deselect();
+ insert(QApplication::clipboard()->text(QClipboard::Selection));
+ }
+ }
+#endif
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::MouseMove:
+ if (ev->buttons() & Qt::LeftButton) {
+ moveCursor(xToPos(ev->pos().x()), true);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
+{
+ bool inlineCompletionAccepted = false;
+
+#ifndef QT_NO_COMPLETER
+ if (m_completer) {
+ QCompleter::CompletionMode completionMode = m_completer->completionMode();
+ if ((completionMode == QCompleter::PopupCompletion
+ || completionMode == QCompleter::UnfilteredPopupCompletion)
+ && m_completer->popup()
+ && m_completer->popup()->isVisible()) {
+ // The following keys are forwarded by the completer to the widget
+ // Ignoring the events lets the completer provide suitable default behavior
+ switch (event->key()) {
+ case Qt::Key_Escape:
+ event->ignore();
+ return;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_F4:
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+ if (!QApplication::keypadNavigationEnabled())
+ break;
+#endif
+ m_completer->popup()->hide(); // just hide. will end up propagating to parent
+ default:
+ break; // normal key processing
+ }
+ } else if (completionMode == QCompleter::InlineCompletion) {
+ switch (event->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_F4:
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Select:
+ if (!QApplication::keypadNavigationEnabled())
+ break;
+#endif
+ if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
+ && textAfterSelection().isEmpty()) {
+ setText(m_completer->currentCompletion());
+ inlineCompletionAccepted = true;
+ }
+ default:
+ break; // normal key processing
+ }
+ }
+ }
+#endif // QT_NO_COMPLETER
+
+ if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
+ if (hasAcceptableInput() || fixup()) {
+ emit accepted();
+ emit editingFinished();
+ }
+ if (inlineCompletionAccepted)
+ event->accept();
+ else
+ event->ignore();
+ return;
+ }
+
+ if (echoMode() == QLineEdit::PasswordEchoOnEdit
+ && !passwordEchoEditing()
+ && !isReadOnly()
+ && !event->text().isEmpty()
+#ifdef QT_KEYPAD_NAVIGATION
+ && event->key() != Qt::Key_Select
+ && event->key() != Qt::Key_Up
+ && event->key() != Qt::Key_Down
+ && event->key() != Qt::Key_Back
+#endif
+ && !(event->modifiers() & Qt::ControlModifier)) {
+ // Clear the edit and reset to normal echo mode while editing; the
+ // echo mode switches back when the edit loses focus
+ // ### resets current content. dubious code; you can
+ // navigate with keys up, down, back, and select(?), but if you press
+ // "left" or "right" it clears?
+ updatePasswordEchoEditing(true);
+ clear();
+ }
+
+ bool unknown = false;
+ bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
+
+ if (false) {
+ }
+#ifndef QT_NO_SHORTCUT
+ else if (event == QKeySequence::Undo) {
+ if (!isReadOnly())
+ undo();
+ }
+ else if (event == QKeySequence::Redo) {
+ if (!isReadOnly())
+ redo();
+ }
+ else if (event == QKeySequence::SelectAll) {
+ selectAll();
+ }
+#ifndef QT_NO_CLIPBOARD
+ else if (event == QKeySequence::Copy) {
+ copy();
+ }
+ else if (event == QKeySequence::Paste) {
+ if (!isReadOnly()) {
+ QClipboard::Mode mode = QClipboard::Clipboard;
+#ifdef Q_WS_X11
+ if (event->modifiers() == (Qt::CTRL | Qt::SHIFT) && event->key() == Qt::Key_Insert)
+ mode = QClipboard::Selection;
+#endif
+ paste(mode);
+ }
+ }
+ else if (event == QKeySequence::Cut) {
+ if (!isReadOnly()) {
+ copy();
+ del();
+ }
+ }
+ else if (event == QKeySequence::DeleteEndOfLine) {
+ if (!isReadOnly()) {
+ setSelection(cursor(), end());
+ copy();
+ del();
+ }
+ }
+#endif //QT_NO_CLIPBOARD
+ else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
+ home(0);
+ }
+ else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
+ end(0);
+ }
+ else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
+ home(1);
+ }
+ else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
+ end(1);
+ }
+ else if (event == QKeySequence::MoveToNextChar) {
+#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
+ if (hasSelectedText()) {
+#else
+ if (hasSelectedText() && m_completer
+ && m_completer->completionMode() == QCompleter::InlineCompletion) {
+#endif
+ moveCursor(selectionEnd(), false);
+ } else {
+ cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
+ }
+ }
+ else if (event == QKeySequence::SelectNextChar) {
+ cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
+ }
+ else if (event == QKeySequence::MoveToPreviousChar) {
+#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
+ if (hasSelectedText()) {
+#else
+ if (hasSelectedText() && m_completer
+ && m_completer->completionMode() == QCompleter::InlineCompletion) {
+#endif
+ moveCursor(selectionStart(), false);
+ } else {
+ cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
+ }
+ }
+ else if (event == QKeySequence::SelectPreviousChar) {
+ cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
+ }
+ else if (event == QKeySequence::MoveToNextWord) {
+ if (echoMode() == QLineEdit::Normal)
+ layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
+ else
+ layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
+ }
+ else if (event == QKeySequence::MoveToPreviousWord) {
+ if (echoMode() == QLineEdit::Normal)
+ layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
+ else if (!isReadOnly()) {
+ layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
+ }
+ }
+ else if (event == QKeySequence::SelectNextWord) {
+ if (echoMode() == QLineEdit::Normal)
+ layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
+ else
+ layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
+ }
+ else if (event == QKeySequence::SelectPreviousWord) {
+ if (echoMode() == QLineEdit::Normal)
+ layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
+ else
+ layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
+ }
+ else if (event == QKeySequence::Delete) {
+ if (!isReadOnly())
+ del();
+ }
+ else if (event == QKeySequence::DeleteEndOfWord) {
+ if (!isReadOnly()) {
+ cursorWordForward(true);
+ del();
+ }
+ }
+ else if (event == QKeySequence::DeleteStartOfWord) {
+ if (!isReadOnly()) {
+ cursorWordBackward(true);
+ del();
+ }
+ }
+#endif // QT_NO_SHORTCUT
+ else {
+ bool handled = false;
+#ifdef Q_WS_MAC
+ if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
+ Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
+ if (myModifiers & Qt::ShiftModifier) {
+ if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
+ || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
+ || myModifiers == Qt::ShiftModifier) {
+
+ event->key() == Qt::Key_Up ? home(1) : end(1);
+ }
+ } else {
+ if ((myModifiers == Qt::ControlModifier
+ || myModifiers == Qt::AltModifier
+ || myModifiers == Qt::NoModifier)) {
+ event->key() == Qt::Key_Up ? home(0) : end(0);
+ }
+ }
+ handled = true;
+ }
+#endif
+ if (event->modifiers() & Qt::ControlModifier) {
+ switch (event->key()) {
+ case Qt::Key_Backspace:
+ if (!isReadOnly()) {
+ cursorWordBackward(true);
+ del();
+ }
+ break;
+#ifndef QT_NO_COMPLETER
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ complete(event->key());
+ break;
+#endif
+#if defined(Q_WS_X11)
+ case Qt::Key_E:
+ end(0);
+ break;
+
+ case Qt::Key_U:
+ if (!isReadOnly()) {
+ setSelection(0, text().size());
+#ifndef QT_NO_CLIPBOARD
+ copy();
+#endif
+ del();
+ }
+ break;
+#endif
+ default:
+ if (!handled)
+ unknown = true;
+ }
+ } else { // ### check for *no* modifier
+ switch (event->key()) {
+ case Qt::Key_Backspace:
+ if (!isReadOnly()) {
+ backspace();
+#ifndef QT_NO_COMPLETER
+ complete(Qt::Key_Backspace);
+#endif
+ }
+ break;
+#ifdef QT_KEYPAD_NAVIGATION
+ case Qt::Key_Back:
+ if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
+ && !isReadOnly()) {
+ if (text().length() == 0) {
+ setText(m_cancelText);
+
+ if (passwordEchoEditing())
+ updatePasswordEchoEditing(false);
+
+ emit editFocusChange(false);
+ } else if (!m_deleteAllTimer) {
+ m_deleteAllTimer = startTimer(750);
+ }
+ } else {
+ unknown = true;
+ }
+ break;
+#endif
+ default:
+ if (!handled)
+ unknown = true;
+ }
+ }
+ }
+
+ if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
+ setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
+ unknown = false;
+ }
+
+ if (unknown && !isReadOnly()) {
+ QString t = event->text();
+ if (!t.isEmpty() && t.at(0).isPrint()) {
+ insert(t);
+#ifndef QT_NO_COMPLETER
+ complete(event->key());
+#endif
+ event->accept();
+ return;
+ }
+ }
+
+ if (unknown)
+ event->ignore();
+ else
+ event->accept();
+}
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h
new file mode 100644
index 0000000000..4169d2de29
--- /dev/null
+++ b/src/widgets/widgets/qwidgetlinecontrol_p.h
@@ -0,0 +1,499 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWidgetLineControl_P_H
+#define QWidgetLineControl_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 "QtCore/qglobal.h"
+
+#ifndef QT_NO_LINEEDIT
+#include "private/qwidget_p.h"
+#include "QtWidgets/qlineedit.h"
+#include "QtGui/qtextlayout.h"
+#include "QtWidgets/qstyleoption.h"
+#include "QtCore/qpointer.h"
+#include "QtGui/qclipboard.h"
+#include "QtCore/qpoint.h"
+#include "QtWidgets/qcompleter.h"
+#include "QtWidgets/qaccessible.h"
+#include "QtCore/qthread.h"
+
+#include "qplatformdefs.h"
+
+QT_BEGIN_HEADER
+
+#ifdef DrawText
+# undef DrawText
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class Q_WIDGETS_EXPORT QWidgetLineControl : public QObject
+{
+ Q_OBJECT
+
+public:
+ QWidgetLineControl(const QString &txt = QString())
+ : m_cursor(0), m_preeditCursor(0), m_cursorWidth(0), m_layoutDirection(Qt::LayoutDirectionAuto),
+ m_hideCursor(false), m_separator(0), m_readOnly(0),
+ m_dragEnabled(0), m_echoMode(0), m_textDirty(0), m_selDirty(0),
+ m_validInput(1), m_blinkStatus(0), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0),
+ m_ascent(0), m_maxLength(32767), m_lastCursorPos(-1),
+ m_tripleClickTimer(0), m_maskData(0), m_modifiedState(0), m_undoState(0),
+ m_selstart(0), m_selend(0), m_passwordEchoEditing(false)
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ , m_passwordEchoTimer(0)
+#endif
+#if defined(Q_WS_MAC)
+ , m_threadChecks(false)
+ , m_textLayoutThread(0)
+ #endif
+ {
+ init(txt);
+ }
+
+ ~QWidgetLineControl()
+ {
+ delete [] m_maskData;
+ }
+
+ int nextMaskBlank(int pos)
+ {
+ int c = findInMask(pos, true, false);
+ m_separator |= (c != pos);
+ return (c != -1 ? c : m_maxLength);
+ }
+
+ int prevMaskBlank(int pos)
+ {
+ int c = findInMask(pos, false, false);
+ m_separator |= (c != pos);
+ return (c != -1 ? c : 0);
+ }
+
+ bool isUndoAvailable() const { return !m_readOnly && m_undoState; }
+ bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); }
+ void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; }
+
+ bool isModified() const { return m_modifiedState != m_undoState; }
+ void setModified(bool modified) { m_modifiedState = modified ? -1 : m_undoState; }
+
+ bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); }
+ bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; }
+
+ int width() const { return qRound(m_textLayout.lineAt(0).width()) + 1; }
+ int height() const { return qRound(m_textLayout.lineAt(0).height()) + 1; }
+ int ascent() const { return m_ascent; }
+ qreal naturalTextWidth() const { return m_textLayout.lineAt(0).naturalTextWidth(); }
+
+ void setSelection(int start, int length);
+
+ inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); }
+ QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); }
+ QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); }
+
+ int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
+ int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
+ bool inSelection(int x) const
+ {
+ if (m_selstart >= m_selend)
+ return false;
+ int pos = xToPos(x, QTextLine::CursorOnCharacter);
+ return pos >= m_selstart && pos < m_selend;
+ }
+
+ void removeSelection()
+ {
+ int priorState = m_undoState;
+ removeSelectedText();
+ finishChange(priorState);
+ }
+
+ int start() const { return 0; }
+ int end() const { return m_text.length(); }
+
+#ifndef QT_NO_CLIPBOARD
+ void copy(QClipboard::Mode mode = QClipboard::Clipboard) const;
+ void paste(QClipboard::Mode mode = QClipboard::Clipboard);
+#endif
+
+ int cursor() const{ return m_cursor; }
+ int preeditCursor() const { return m_preeditCursor; }
+
+ int cursorWidth() const { return m_cursorWidth; }
+ void setCursorWidth(int value) { m_cursorWidth = value; }
+
+ Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
+ void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
+
+ void moveCursor(int pos, bool mark = false);
+ void cursorForward(bool mark, int steps)
+ {
+ int c = m_cursor;
+ if (steps > 0) {
+ while (steps--)
+ c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c)
+ : m_textLayout.nextCursorPosition(c);
+ } else if (steps < 0) {
+ while (steps++)
+ c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c)
+ : m_textLayout.previousCursorPosition(c);
+ }
+ moveCursor(c, mark);
+ }
+
+ void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
+ void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
+
+ void home(bool mark) { moveCursor(0, mark); }
+ void end(bool mark) { moveCursor(text().length(), mark); }
+
+ int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const;
+ QRect cursorRect() const;
+
+ qreal cursorToX(int cursor) const { return m_textLayout.lineAt(0).cursorToX(cursor); }
+ qreal cursorToX() const
+ {
+ int cursor = m_cursor;
+ if (m_preeditCursor != -1)
+ cursor += m_preeditCursor;
+ return cursorToX(cursor);
+ }
+
+ bool isReadOnly() const { return m_readOnly; }
+ void setReadOnly(bool enable) { m_readOnly = enable; }
+
+ QString text() const
+ {
+ QString res = m_maskData ? stripString(m_text) : m_text;
+ return (res.isNull() ? QString::fromLatin1("") : res);
+ }
+ void setText(const QString &txt) { internalSetText(txt, -1, false); }
+ QString displayText() const { return m_textLayout.text(); }
+
+ void backspace();
+ void del();
+ void deselect() { internalDeselect(); finishChange(); }
+ void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); }
+
+ void insert(const QString &);
+ void clear();
+ void undo() { internalUndo(); finishChange(-1, true); }
+ void redo() { internalRedo(); finishChange(); }
+ void selectWordAtPos(int);
+
+ uint echoMode() const { return m_echoMode; }
+ void setEchoMode(uint mode)
+ {
+ m_echoMode = mode;
+ m_passwordEchoEditing = false;
+ updateDisplayText();
+ }
+
+ int maxLength() const { return m_maxLength; }
+ void setMaxLength(int maxLength)
+ {
+ if (m_maskData)
+ return;
+ m_maxLength = maxLength;
+ setText(m_text);
+ }
+
+#ifndef QT_NO_VALIDATOR
+ const QValidator *validator() const { return m_validator; }
+ void setValidator(const QValidator *v) { m_validator = const_cast<QValidator*>(v); }
+#endif
+
+#ifndef QT_NO_COMPLETER
+ QCompleter *completer() const { return m_completer; }
+ /* Note that you must set the widget for the completer separately */
+ void setCompleter(const QCompleter *c) { m_completer = const_cast<QCompleter*>(c); }
+ void complete(int key);
+#endif
+
+ int cursorPosition() const { return m_cursor; }
+ void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); }
+
+ bool hasAcceptableInput() const { return hasAcceptableInput(m_text); }
+ bool fixup();
+
+ QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); }
+ void setInputMask(const QString &mask)
+ {
+ parseInputMask(mask);
+ if (m_maskData)
+ moveCursor(nextMaskBlank(0));
+ }
+
+ // input methods
+#ifndef QT_NO_IM
+ bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); }
+ void setPreeditArea(int cursor, const QString &text) { m_textLayout.setPreeditArea(cursor, text); }
+#endif
+
+ QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
+
+ void updatePasswordEchoEditing(bool editing);
+ bool passwordEchoEditing() const { return m_passwordEchoEditing; }
+
+ QChar passwordCharacter() const { return m_passwordCharacter; }
+ void setPasswordCharacter(const QChar &character) { m_passwordCharacter = character; updateDisplayText(); }
+
+ Qt::LayoutDirection layoutDirection() const {
+ if (m_layoutDirection == Qt::LayoutDirectionAuto) {
+ if (m_text.isEmpty())
+ return QApplication::keyboardInputDirection();
+ return m_text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
+ }
+ return m_layoutDirection;
+ }
+ void setLayoutDirection(Qt::LayoutDirection direction)
+ {
+ if (direction != m_layoutDirection) {
+ m_layoutDirection = direction;
+ updateDisplayText();
+ }
+ }
+
+ void setFont(const QFont &font) { m_textLayout.setFont(font); updateDisplayText(); }
+
+ void processInputMethodEvent(QInputMethodEvent *event);
+ void processMouseEvent(QMouseEvent* ev);
+ void processKeyEvent(QKeyEvent* ev);
+
+ int cursorBlinkPeriod() const { return m_blinkPeriod; }
+ void setCursorBlinkPeriod(int msec);
+ void resetCursorBlinkTimer();
+
+ bool cursorBlinkStatus() const { return m_blinkStatus; }
+
+ QString cancelText() const { return m_cancelText; }
+ void setCancelText(const QString &text) { m_cancelText = text; }
+
+ const QPalette &palette() const { return m_palette; }
+ void setPalette(const QPalette &p) { m_palette = p; }
+
+ enum DrawFlags {
+ DrawText = 0x01,
+ DrawSelections = 0x02,
+ DrawCursor = 0x04,
+ DrawAll = DrawText | DrawSelections | DrawCursor
+ };
+ void draw(QPainter *, const QPoint &, const QRect &, int flags = DrawAll);
+
+ bool processEvent(QEvent *ev);
+
+ QTextLayout *textLayout() const
+ {
+#if defined(Q_WS_MAC)
+ if (m_threadChecks && QThread::currentThread() != m_textLayoutThread)
+ redoTextLayout();
+#endif
+ return &m_textLayout;
+ }
+
+#if defined(Q_WS_MAC)
+ void setThreadChecks(bool threadChecks)
+ {
+ m_threadChecks = threadChecks;
+ }
+
+ bool threadChecks() const
+ {
+ return m_threadChecks;
+ }
+#endif
+
+private:
+ void init(const QString &txt);
+ void removeSelectedText();
+ void internalSetText(const QString &txt, int pos = -1, bool edited = true);
+ void updateDisplayText(bool forceUpdate = false);
+
+ void internalInsert(const QString &s);
+ void internalDelete(bool wasBackspace = false);
+ void internalRemove(int pos);
+
+ inline void internalDeselect()
+ {
+ m_selDirty |= (m_selend > m_selstart);
+ m_selstart = m_selend = 0;
+ }
+
+ void internalUndo(int until = -1);
+ void internalRedo();
+
+ QString m_text;
+ QPalette m_palette;
+ int m_cursor;
+ int m_preeditCursor;
+ int m_cursorWidth;
+ Qt::LayoutDirection m_layoutDirection;
+ uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas
+ uint m_separator : 1;
+ uint m_readOnly : 1;
+ uint m_dragEnabled : 1;
+ uint m_echoMode : 2;
+ uint m_textDirty : 1;
+ uint m_selDirty : 1;
+ uint m_validInput : 1;
+ uint m_blinkStatus : 1;
+ int m_blinkPeriod; // 0 for non-blinking cursor
+ int m_blinkTimer;
+ int m_deleteAllTimer;
+ int m_ascent;
+ int m_maxLength;
+ int m_lastCursorPos;
+ QList<int> m_transactions;
+ QPoint m_tripleClick;
+ int m_tripleClickTimer;
+ QString m_cancelText;
+
+ void emitCursorPositionChanged();
+
+ bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
+
+#ifndef QT_NO_VALIDATOR
+ QPointer<QValidator> m_validator;
+#endif
+ QPointer<QCompleter> m_completer;
+#ifndef QT_NO_COMPLETER
+ bool advanceToEnabledItem(int dir);
+#endif
+
+ struct MaskInputData {
+ enum Casemode { NoCaseMode, Upper, Lower };
+ QChar maskChar; // either the separator char or the inputmask
+ bool separator;
+ Casemode caseMode;
+ };
+ QString m_inputMask;
+ QChar m_blank;
+ MaskInputData *m_maskData;
+
+ // undo/redo handling
+ enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
+ struct Command {
+ inline Command() {}
+ inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
+ uint type : 4;
+ QChar uc;
+ int pos, selStart, selEnd;
+ };
+ int m_modifiedState;
+ int m_undoState;
+ QVector<Command> m_history;
+ void addCommand(const Command& cmd);
+
+ inline void separate() { m_separator = true; }
+
+ // selection
+ int m_selstart;
+ int m_selend;
+
+ // masking
+ void parseInputMask(const QString &maskFields);
+ bool isValidInput(QChar key, QChar mask) const;
+ bool hasAcceptableInput(const QString &text) const;
+ QString maskString(uint pos, const QString &str, bool clear = false) const;
+ QString clearString(uint pos, uint len) const;
+ QString stripString(const QString &str) const;
+ int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
+
+ // complex text layout (must be mutable so it can be reshaped at will)
+ mutable QTextLayout m_textLayout;
+
+ bool m_passwordEchoEditing;
+ QChar m_passwordCharacter;
+
+ int redoTextLayout() const;
+#if defined(Q_WS_MAC)
+ bool m_threadChecks;
+ mutable QThread *m_textLayoutThread;
+#endif
+
+Q_SIGNALS:
+ void cursorPositionChanged(int, int);
+ void selectionChanged();
+
+ void displayTextChanged(const QString &);
+ void textChanged(const QString &);
+ void textEdited(const QString &);
+
+ void resetInputContext();
+ void updateMicroFocus();
+
+ void accepted();
+ void editingFinished();
+ void updateNeeded(const QRect &);
+
+#ifdef QT_KEYPAD_NAVIGATION
+ void editFocusChange(bool);
+#endif
+protected:
+ virtual void timerEvent(QTimerEvent *event);
+
+private Q_SLOTS:
+ void _q_clipboardChanged();
+ void _q_deleteSelected();
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_LINEEDIT
+
+#endif // QWidgetLineControl_P_H
diff --git a/src/widgets/widgets/qwidgetresizehandler.cpp b/src/widgets/widgets/qwidgetresizehandler.cpp
new file mode 100644
index 0000000000..f43e0f7dfa
--- /dev/null
+++ b/src/widgets/widgets/qwidgetresizehandler.cpp
@@ -0,0 +1,547 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetresizehandler_p.h"
+
+#ifndef QT_NO_RESIZEHANDLER
+#include "qframe.h"
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#include "qcursor.h"
+#include "qsizegrip.h"
+#include "qevent.h"
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#endif
+#include "qdebug.h"
+#include "private/qlayoutengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define RANGE 4
+
+static bool resizeHorizontalDirectionFixed = false;
+static bool resizeVerticalDirectionFixed = false;
+
+QWidgetResizeHandler::QWidgetResizeHandler(QWidget *parent, QWidget *cw)
+ : QObject(parent), widget(parent), childWidget(cw ? cw : parent),
+ fw(0), extrahei(0), buttonDown(false), moveResizeMode(false), sizeprotect(true), movingEnabled(true)
+{
+ mode = Nowhere;
+ widget->setMouseTracking(true);
+ QFrame *frame = qobject_cast<QFrame*>(widget);
+ range = frame ? frame->frameWidth() : RANGE;
+ range = qMax(RANGE, range);
+ activeForMove = activeForResize = true;
+ widget->installEventFilter(this);
+}
+
+void QWidgetResizeHandler::setActive(Action ac, bool b)
+{
+ if (ac & Move)
+ activeForMove = b;
+ if (ac & Resize)
+ activeForResize = b;
+
+ if (!isActive())
+ setMouseCursor(Nowhere);
+}
+
+bool QWidgetResizeHandler::isActive(Action ac) const
+{
+ bool b = false;
+ if (ac & Move) b = activeForMove;
+ if (ac & Resize) b |= activeForResize;
+
+ return b;
+}
+
+bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
+{
+ if (!isActive()
+ || (ee->type() != QEvent::MouseButtonPress
+ && ee->type() != QEvent::MouseButtonRelease
+ && ee->type() != QEvent::MouseMove
+ && ee->type() != QEvent::KeyPress
+ && ee->type() != QEvent::ShortcutOverride)
+ )
+ return false;
+
+ Q_ASSERT(o == widget);
+ QWidget *w = widget;
+ if (QApplication::activePopupWidget()) {
+ if (buttonDown && ee->type() == QEvent::MouseButtonRelease)
+ buttonDown = false;
+ return false;
+ }
+
+ QMouseEvent *e = (QMouseEvent*)ee;
+ switch (e->type()) {
+ case QEvent::MouseButtonPress: {
+ if (w->isMaximized())
+ break;
+ if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos())))
+ return false;
+ if (e->button() == Qt::LeftButton) {
+#if defined(Q_WS_X11)
+ /*
+ Implicit grabs do not stop the X server from changing
+ the cursor in children, which looks *really* bad when
+ doing resizingk, so we grab the cursor. Note that we do
+ not do this on Windows since double clicks are lost due
+ to the grab (see change 198463).
+ */
+ if (e->spontaneous())
+# if !defined(QT_NO_CURSOR)
+ widget->grabMouse(widget->cursor());
+# else
+ widget->grabMouse();
+# endif // QT_NO_CURSOR
+#endif // Q_WS_X11
+ buttonDown = false;
+ emit activate();
+ bool me = movingEnabled;
+ movingEnabled = (me && o == widget);
+ mouseMoveEvent(e);
+ movingEnabled = me;
+ buttonDown = true;
+ moveOffset = widget->mapFromGlobal(e->globalPos());
+ invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
+ if (mode == Center) {
+ if (movingEnabled)
+ return true;
+ } else {
+ return true;
+ }
+ }
+ } break;
+ case QEvent::MouseButtonRelease:
+ if (w->isMaximized())
+ break;
+ if (e->button() == Qt::LeftButton) {
+ moveResizeMode = false;
+ buttonDown = false;
+ widget->releaseMouse();
+ widget->releaseKeyboard();
+ if (mode == Center) {
+ if (movingEnabled)
+ return true;
+ } else {
+ return true;
+ }
+ }
+ break;
+ case QEvent::MouseMove: {
+ if (w->isMaximized())
+ break;
+ buttonDown = buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
+ bool me = movingEnabled;
+ movingEnabled = (me && o == widget && (buttonDown || moveResizeMode));
+ mouseMoveEvent(e);
+ movingEnabled = me;
+ if (mode == Center) {
+ if (movingEnabled)
+ return true;
+ } else {
+ return true;
+ }
+ } break;
+ case QEvent::KeyPress:
+ keyPressEvent((QKeyEvent*)e);
+ break;
+ case QEvent::ShortcutOverride:
+ if (buttonDown) {
+ ((QKeyEvent*)ee)->accept();
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QWidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
+{
+ QPoint pos = widget->mapFromGlobal(e->globalPos());
+ if (!moveResizeMode && !buttonDown) {
+ if (pos.y() <= range && pos.x() <= range)
+ mode = TopLeft;
+ else if (pos.y() >= widget->height()-range && pos.x() >= widget->width()-range)
+ mode = BottomRight;
+ else if (pos.y() >= widget->height()-range && pos.x() <= range)
+ mode = BottomLeft;
+ else if (pos.y() <= range && pos.x() >= widget->width()-range)
+ mode = TopRight;
+ else if (pos.y() <= range)
+ mode = Top;
+ else if (pos.y() >= widget->height()-range)
+ mode = Bottom;
+ else if (pos.x() <= range)
+ mode = Left;
+ else if ( pos.x() >= widget->width()-range)
+ mode = Right;
+ else if (widget->rect().contains(pos))
+ mode = Center;
+ else
+ mode = Nowhere;
+
+ if (widget->isMinimized() || !isActive(Resize))
+ mode = Center;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+#endif
+ return;
+ }
+
+ if (mode == Center && !movingEnabled)
+ return;
+
+ if (widget->testAttribute(Qt::WA_WState_ConfigPending))
+ return;
+
+
+ QPoint globalPos = (!widget->isWindow() && widget->parentWidget()) ?
+ widget->parentWidget()->mapFromGlobal(e->globalPos()) : e->globalPos();
+ if (!widget->isWindow() && !widget->parentWidget()->rect().contains(globalPos)) {
+ if (globalPos.x() < 0)
+ globalPos.rx() = 0;
+ if (globalPos.y() < 0)
+ globalPos.ry() = 0;
+ if (sizeprotect && globalPos.x() > widget->parentWidget()->width())
+ globalPos.rx() = widget->parentWidget()->width();
+ if (sizeprotect && globalPos.y() > widget->parentWidget()->height())
+ globalPos.ry() = widget->parentWidget()->height();
+ }
+
+ QPoint p = globalPos + invertedMoveOffset;
+ QPoint pp = globalPos - moveOffset;
+
+#ifdef Q_WS_X11
+ // Workaround for window managers which refuse to move a tool window partially offscreen.
+ QRect desktop = QApplication::desktop()->availableGeometry(widget);
+ pp.rx() = qMax(pp.x(), desktop.left());
+ pp.ry() = qMax(pp.y(), desktop.top());
+ p.rx() = qMin(p.x(), desktop.right());
+ p.ry() = qMin(p.y(), desktop.bottom());
+#endif
+
+ QSize ms = qSmartMinSize(childWidget);
+ int mw = ms.width();
+ int mh = ms.height();
+ if (childWidget != widget) {
+ mw += 2 * fw;
+ mh += 2 * fw + extrahei;
+ }
+
+ QSize maxsize(childWidget->maximumSize());
+ if (childWidget != widget)
+ maxsize += QSize(2 * fw, 2 * fw + extrahei);
+ QSize mpsize(widget->geometry().right() - pp.x() + 1,
+ widget->geometry().bottom() - pp.y() + 1);
+ mpsize = mpsize.expandedTo(widget->minimumSize()).expandedTo(QSize(mw, mh))
+ .boundedTo(maxsize);
+ QPoint mp(widget->geometry().right() - mpsize.width() + 1,
+ widget->geometry().bottom() - mpsize.height() + 1);
+
+ QRect geom = widget->geometry();
+
+ switch (mode) {
+ case TopLeft:
+ geom = QRect(mp, widget->geometry().bottomRight()) ;
+ break;
+ case BottomRight:
+ geom = QRect(widget->geometry().topLeft(), p) ;
+ break;
+ case BottomLeft:
+ geom = QRect(QPoint(mp.x(), widget->geometry().y()), QPoint(widget->geometry().right(), p.y())) ;
+ break;
+ case TopRight:
+ geom = QRect(QPoint(widget->geometry().x(), mp.y()), QPoint(p.x(), widget->geometry().bottom())) ;
+ break;
+ case Top:
+ geom = QRect(QPoint(widget->geometry().left(), mp.y()), widget->geometry().bottomRight()) ;
+ break;
+ case Bottom:
+ geom = QRect(widget->geometry().topLeft(), QPoint(widget->geometry().right(), p.y())) ;
+ break;
+ case Left:
+ geom = QRect(QPoint(mp.x(), widget->geometry().top()), widget->geometry().bottomRight()) ;
+ break;
+ case Right:
+ geom = QRect(widget->geometry().topLeft(), QPoint(p.x(), widget->geometry().bottom())) ;
+ break;
+ case Center:
+ geom.moveTopLeft(pp);
+ break;
+ default:
+ break;
+ }
+
+ geom = QRect(geom.topLeft(),
+ geom.size().expandedTo(widget->minimumSize())
+ .expandedTo(QSize(mw, mh))
+ .boundedTo(maxsize));
+
+ if (geom != widget->geometry() &&
+ (widget->isWindow() || widget->parentWidget()->rect().intersects(geom))) {
+ if (mode == Center)
+ widget->move(geom.topLeft());
+ else
+ widget->setGeometry(geom);
+ }
+
+ QApplication::syncX();
+}
+
+void QWidgetResizeHandler::setMouseCursor(MousePosition m)
+{
+#ifdef QT_NO_CURSOR
+ Q_UNUSED(m);
+#else
+ QObjectList children = widget->children();
+ for (int i = 0; i < children.size(); ++i) {
+ if (QWidget *w = qobject_cast<QWidget*>(children.at(i))) {
+ if (!w->testAttribute(Qt::WA_SetCursor) && !w->inherits("QWorkspaceTitleBar")) {
+ w->setCursor(Qt::ArrowCursor);
+ }
+ }
+ }
+
+ switch (m) {
+ case TopLeft:
+ case BottomRight:
+ widget->setCursor(Qt::SizeFDiagCursor);
+ break;
+ case BottomLeft:
+ case TopRight:
+ widget->setCursor(Qt::SizeBDiagCursor);
+ break;
+ case Top:
+ case Bottom:
+ widget->setCursor(Qt::SizeVerCursor);
+ break;
+ case Left:
+ case Right:
+ widget->setCursor(Qt::SizeHorCursor);
+ break;
+ default:
+ widget->setCursor(Qt::ArrowCursor);
+ break;
+ }
+#endif // QT_NO_CURSOR
+}
+
+void QWidgetResizeHandler::keyPressEvent(QKeyEvent * e)
+{
+ if (!isMove() && !isResize())
+ return;
+ bool is_control = e->modifiers() & Qt::ControlModifier;
+ int delta = is_control?1:8;
+ QPoint pos = QCursor::pos();
+ switch (e->key()) {
+ case Qt::Key_Left:
+ pos.rx() -= delta;
+ if (pos.x() <= QApplication::desktop()->geometry().left()) {
+ if (mode == TopLeft || mode == BottomLeft) {
+ moveOffset.rx() += delta;
+ invertedMoveOffset.rx() += delta;
+ } else {
+ moveOffset.rx() -= delta;
+ invertedMoveOffset.rx() -= delta;
+ }
+ }
+ if (isResize() && !resizeHorizontalDirectionFixed) {
+ resizeHorizontalDirectionFixed = true;
+ if (mode == BottomRight)
+ mode = BottomLeft;
+ else if (mode == TopRight)
+ mode = TopLeft;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+ widget->grabMouse(widget->cursor());
+#else
+ widget->grabMouse();
+#endif
+ }
+ break;
+ case Qt::Key_Right:
+ pos.rx() += delta;
+ if (pos.x() >= QApplication::desktop()->geometry().right()) {
+ if (mode == TopRight || mode == BottomRight) {
+ moveOffset.rx() += delta;
+ invertedMoveOffset.rx() += delta;
+ } else {
+ moveOffset.rx() -= delta;
+ invertedMoveOffset.rx() -= delta;
+ }
+ }
+ if (isResize() && !resizeHorizontalDirectionFixed) {
+ resizeHorizontalDirectionFixed = true;
+ if (mode == BottomLeft)
+ mode = BottomRight;
+ else if (mode == TopLeft)
+ mode = TopRight;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+ widget->grabMouse(widget->cursor());
+#else
+ widget->grabMouse();
+#endif
+ }
+ break;
+ case Qt::Key_Up:
+ pos.ry() -= delta;
+ if (pos.y() <= QApplication::desktop()->geometry().top()) {
+ if (mode == TopLeft || mode == TopRight) {
+ moveOffset.ry() += delta;
+ invertedMoveOffset.ry() += delta;
+ } else {
+ moveOffset.ry() -= delta;
+ invertedMoveOffset.ry() -= delta;
+ }
+ }
+ if (isResize() && !resizeVerticalDirectionFixed) {
+ resizeVerticalDirectionFixed = true;
+ if (mode == BottomLeft)
+ mode = TopLeft;
+ else if (mode == BottomRight)
+ mode = TopRight;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+ widget->grabMouse(widget->cursor());
+#else
+ widget->grabMouse();
+#endif
+ }
+ break;
+ case Qt::Key_Down:
+ pos.ry() += delta;
+ if (pos.y() >= QApplication::desktop()->geometry().bottom()) {
+ if (mode == BottomLeft || mode == BottomRight) {
+ moveOffset.ry() += delta;
+ invertedMoveOffset.ry() += delta;
+ } else {
+ moveOffset.ry() -= delta;
+ invertedMoveOffset.ry() -= delta;
+ }
+ }
+ if (isResize() && !resizeVerticalDirectionFixed) {
+ resizeVerticalDirectionFixed = true;
+ if (mode == TopLeft)
+ mode = BottomLeft;
+ else if (mode == TopRight)
+ mode = BottomRight;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+ widget->grabMouse(widget->cursor());
+#else
+ widget->grabMouse();
+#endif
+ }
+ break;
+ case Qt::Key_Space:
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Escape:
+ moveResizeMode = false;
+ widget->releaseMouse();
+ widget->releaseKeyboard();
+ buttonDown = false;
+ break;
+ default:
+ return;
+ }
+ QCursor::setPos(pos);
+}
+
+
+void QWidgetResizeHandler::doResize()
+{
+ if (!activeForResize)
+ return;
+
+ moveResizeMode = true;
+ moveOffset = widget->mapFromGlobal(QCursor::pos());
+ if (moveOffset.x() < widget->width()/2) {
+ if (moveOffset.y() < widget->height()/2)
+ mode = TopLeft;
+ else
+ mode = BottomLeft;
+ } else {
+ if (moveOffset.y() < widget->height()/2)
+ mode = TopRight;
+ else
+ mode = BottomRight;
+ }
+ invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
+#ifndef QT_NO_CURSOR
+ setMouseCursor(mode);
+ widget->grabMouse(widget->cursor() );
+#else
+ widget->grabMouse();
+#endif
+ widget->grabKeyboard();
+ resizeHorizontalDirectionFixed = false;
+ resizeVerticalDirectionFixed = false;
+}
+
+void QWidgetResizeHandler::doMove()
+{
+ if (!activeForMove)
+ return;
+
+ mode = Center;
+ moveResizeMode = true;
+ moveOffset = widget->mapFromGlobal(QCursor::pos());
+ invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
+#ifndef QT_NO_CURSOR
+ widget->grabMouse(Qt::SizeAllCursor);
+#else
+ widget->grabMouse();
+#endif
+ widget->grabKeyboard();
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_RESIZEHANDLER
diff --git a/src/widgets/widgets/qwidgetresizehandler_p.h b/src/widgets/widgets/qwidgetresizehandler_p.h
new file mode 100644
index 0000000000..9d09d63967
--- /dev/null
+++ b/src/widgets/widgets/qwidgetresizehandler_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETRESIZEHANDLER_P_H
+#define QWIDGETRESIZEHANDLER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. This header file may
+// change from version to version without notice, or even be
+// removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qobject.h"
+#include "QtCore/qpoint.h"
+
+#ifndef QT_NO_RESIZEHANDLER
+
+QT_BEGIN_NAMESPACE
+
+class QMouseEvent;
+class QKeyEvent;
+
+class Q_WIDGETS_EXPORT QWidgetResizeHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Action {
+ Move = 0x01,
+ Resize = 0x02,
+ Any = Move|Resize
+ };
+
+ explicit QWidgetResizeHandler(QWidget *parent, QWidget *cw = 0);
+ void setActive(bool b) { setActive(Any, b); }
+ void setActive(Action ac, bool b);
+ bool isActive() const { return isActive(Any); }
+ bool isActive(Action ac) const;
+ void setMovingEnabled(bool b) { movingEnabled = b; }
+ bool isMovingEnabled() const { return movingEnabled; }
+
+ bool isButtonDown() const { return buttonDown; }
+
+ void setExtraHeight(int h) { extrahei = h; }
+ void setSizeProtection(bool b) { sizeprotect = b; }
+
+ void setFrameWidth(int w) { fw = w; }
+
+ void doResize();
+ void doMove();
+
+Q_SIGNALS:
+ void activate();
+
+protected:
+ bool eventFilter(QObject *o, QEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+
+private:
+ Q_DISABLE_COPY(QWidgetResizeHandler)
+
+ enum MousePosition {
+ Nowhere,
+ TopLeft, BottomRight, BottomLeft, TopRight,
+ Top, Bottom, Left, Right,
+ Center
+ };
+
+ QWidget *widget;
+ QWidget *childWidget;
+ QPoint moveOffset;
+ QPoint invertedMoveOffset;
+ MousePosition mode;
+ int fw;
+ int extrahei;
+ int range;
+ uint buttonDown :1;
+ uint moveResizeMode :1;
+ uint activeForResize :1;
+ uint sizeprotect :1;
+ uint movingEnabled :1;
+ uint activeForMove :1;
+
+ void setMouseCursor(MousePosition m);
+ bool isMove() const {
+ return moveResizeMode && mode == Center;
+ }
+ bool isResize() const {
+ return moveResizeMode && !isMove();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RESIZEHANDLER
+
+#endif // QWIDGETRESIZEHANDLER_P_H
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
new file mode 100644
index 0000000000..43ebb6b078
--- /dev/null
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -0,0 +1,3148 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgettextcontrol_p.h"
+#include "qwidgettextcontrol_p_p.h"
+
+#ifndef QT_NO_TEXTCONTROL
+
+#include <qfont.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qdebug.h>
+#include <qmime.h>
+#include <qdrag.h>
+#include <qclipboard.h>
+#include <qmenu.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include "private/qtextdocumentlayout_p.h"
+#include "private/qabstracttextdocumentlayout_p.h"
+#include "private/qtextedit_p.h"
+#include "qtextdocument.h"
+#include "private/qtextdocument_p.h"
+#include "qtextlist.h"
+#include "private/qwidgettextcontrol_p.h"
+#include "qgraphicssceneevent.h"
+#include "qpagedpaintdevice.h"
+#include "private/qpagedpaintdevice_p.h"
+#include "qtextdocumentwriter.h"
+#include "private/qtextcursor_p.h"
+
+#include <qtextformat.h>
+#include <qdatetime.h>
+#include <qbuffer.h>
+#include <qapplication.h>
+#include <limits.h>
+#include <qtexttable.h>
+#include <qvariant.h>
+#include <qurl.h>
+#include <qdesktopservices.h>
+#include <qinputcontext.h>
+#include <qtooltip.h>
+#include <qstyleoption.h>
+#include <QtWidgets/qlineedit.h>
+
+#ifndef QT_NO_SHORTCUT
+#include "private/qapplication_p.h"
+#include "private/qshortcutmap_p.h"
+#include <qkeysequence.h>
+#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1Char('\t') + QString(QKeySequence(k)) : QString())
+#else
+#define ACCEL_KEY(k) QString()
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_CONTEXTMENU
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+extern bool qt_use_rtl_extensions;
+#endif
+#endif
+
+// could go into QTextCursor...
+static QTextLine currentTextLine(const QTextCursor &cursor)
+{
+ const QTextBlock block = cursor.block();
+ if (!block.isValid())
+ return QTextLine();
+
+ const QTextLayout *layout = block.layout();
+ if (!layout)
+ return QTextLine();
+
+ const int relativePos = cursor.position() - block.position();
+ return layout->lineForTextPosition(relativePos);
+}
+
+QWidgetTextControlPrivate::QWidgetTextControlPrivate()
+ : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
+ interactionFlags(Qt::TextEditorInteraction),
+ dragEnabled(true),
+#ifndef QT_NO_DRAGANDDROP
+ mousePressed(false), mightStartDrag(false),
+#endif
+ lastSelectionState(false), ignoreAutomaticScrollbarAdjustement(false),
+ overwriteMode(false),
+ acceptRichText(true),
+ preeditCursor(0), hideCursor(false),
+ hasFocus(false),
+#ifdef QT_KEYPAD_NAVIGATION
+ hasEditFocus(false),
+#endif
+ isEnabled(true),
+ hadSelectionOnMousePress(false),
+ ignoreUnusedNavigationEvents(false),
+ openExternalLinks(false),
+ wordSelectionEnabled(false)
+{}
+
+bool QWidgetTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
+{
+#ifdef QT_NO_SHORTCUT
+ Q_UNUSED(e);
+#endif
+
+ Q_Q(QWidgetTextControl);
+ if (cursor.isNull())
+ return false;
+
+ const QTextCursor oldSelection = cursor;
+ const int oldCursorPos = cursor.position();
+
+ QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
+ QTextCursor::MoveOperation op = QTextCursor::NoMove;
+
+ if (false) {
+ }
+#ifndef QT_NO_SHORTCUT
+ if (e == QKeySequence::MoveToNextChar) {
+ op = QTextCursor::Right;
+ }
+ else if (e == QKeySequence::MoveToPreviousChar) {
+ op = QTextCursor::Left;
+ }
+ else if (e == QKeySequence::SelectNextChar) {
+ op = QTextCursor::Right;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectPreviousChar) {
+ op = QTextCursor::Left;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectNextWord) {
+ op = QTextCursor::WordRight;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectPreviousWord) {
+ op = QTextCursor::WordLeft;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectStartOfLine) {
+ op = QTextCursor::StartOfLine;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectEndOfLine) {
+ op = QTextCursor::EndOfLine;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectStartOfBlock) {
+ op = QTextCursor::StartOfBlock;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectEndOfBlock) {
+ op = QTextCursor::EndOfBlock;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectStartOfDocument) {
+ op = QTextCursor::Start;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectEndOfDocument) {
+ op = QTextCursor::End;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectPreviousLine) {
+ op = QTextCursor::Up;
+ mode = QTextCursor::KeepAnchor;
+ }
+ else if (e == QKeySequence::SelectNextLine) {
+ op = QTextCursor::Down;
+ mode = QTextCursor::KeepAnchor;
+ {
+ QTextBlock block = cursor.block();
+ QTextLine line = currentTextLine(cursor);
+ if (!block.next().isValid()
+ && line.isValid()
+ && line.lineNumber() == block.layout()->lineCount() - 1)
+ op = QTextCursor::End;
+ }
+ }
+ else if (e == QKeySequence::MoveToNextWord) {
+ op = QTextCursor::WordRight;
+ }
+ else if (e == QKeySequence::MoveToPreviousWord) {
+ op = QTextCursor::WordLeft;
+ }
+ else if (e == QKeySequence::MoveToEndOfBlock) {
+ op = QTextCursor::EndOfBlock;
+ }
+ else if (e == QKeySequence::MoveToStartOfBlock) {
+ op = QTextCursor::StartOfBlock;
+ }
+ else if (e == QKeySequence::MoveToNextLine) {
+ op = QTextCursor::Down;
+ }
+ else if (e == QKeySequence::MoveToPreviousLine) {
+ op = QTextCursor::Up;
+ }
+ else if (e == QKeySequence::MoveToPreviousLine) {
+ op = QTextCursor::Up;
+ }
+ else if (e == QKeySequence::MoveToStartOfLine) {
+ op = QTextCursor::StartOfLine;
+ }
+ else if (e == QKeySequence::MoveToEndOfLine) {
+ op = QTextCursor::EndOfLine;
+ }
+ else if (e == QKeySequence::MoveToStartOfDocument) {
+ op = QTextCursor::Start;
+ }
+ else if (e == QKeySequence::MoveToEndOfDocument) {
+ op = QTextCursor::End;
+ }
+#endif // QT_NO_SHORTCUT
+ else {
+ return false;
+ }
+
+// Except for pageup and pagedown, Mac OS X has very different behavior, we don't do it all, but
+// here's the breakdown:
+// Shift still works as an anchor, but only one of the other keys can be down Ctrl (Command),
+// Alt (Option), or Meta (Control).
+// Command/Control + Left/Right -- Move to left or right of the line
+// + Up/Down -- Move to top bottom of the file. (Control doesn't move the cursor)
+// Option + Left/Right -- Move one word Left/right.
+// + Up/Down -- Begin/End of Paragraph.
+// Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
+
+ bool visualNavigation = cursor.visualNavigation();
+ cursor.setVisualNavigation(true);
+ const bool moved = cursor.movePosition(op, mode);
+ cursor.setVisualNavigation(visualNavigation);
+ q->ensureCursorVisible();
+
+ bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
+ bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
+
+#ifdef QT_KEYPAD_NAVIGATION
+ ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled();
+ isNavigationEvent = isNavigationEvent ||
+ (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
+ && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
+#else
+ isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
+#endif
+
+ if (moved) {
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+ emit q->microFocusChanged();
+ } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
+ return false;
+ }
+
+ selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
+
+ repaintOldAndNewSelection(oldSelection);
+
+ return true;
+}
+
+void QWidgetTextControlPrivate::updateCurrentCharFormat()
+{
+ Q_Q(QWidgetTextControl);
+
+ QTextCharFormat fmt = cursor.charFormat();
+ if (fmt == lastCharFormat)
+ return;
+ lastCharFormat = fmt;
+
+ emit q->currentCharFormatChanged(fmt);
+ emit q->microFocusChanged();
+}
+
+void QWidgetTextControlPrivate::indent()
+{
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextList *list = cursor.currentList();
+ if (!list) {
+ QTextBlockFormat modifier;
+ modifier.setIndent(blockFmt.indent() + 1);
+ cursor.mergeBlockFormat(modifier);
+ } else {
+ QTextListFormat format = list->format();
+ format.setIndent(format.indent() + 1);
+
+ if (list->itemNumber(cursor.block()) == 1)
+ list->setFormat(format);
+ else
+ cursor.createList(format);
+ }
+}
+
+void QWidgetTextControlPrivate::outdent()
+{
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextList *list = cursor.currentList();
+
+ if (!list) {
+ QTextBlockFormat modifier;
+ modifier.setIndent(blockFmt.indent() - 1);
+ cursor.mergeBlockFormat(modifier);
+ } else {
+ QTextListFormat listFmt = list->format();
+ listFmt.setIndent(listFmt.indent() - 1);
+ list->setFormat(listFmt);
+ }
+}
+
+void QWidgetTextControlPrivate::gotoNextTableCell()
+{
+ QTextTable *table = cursor.currentTable();
+ QTextTableCell cell = table->cellAt(cursor);
+
+ int newColumn = cell.column() + cell.columnSpan();
+ int newRow = cell.row();
+
+ if (newColumn >= table->columns()) {
+ newColumn = 0;
+ ++newRow;
+ if (newRow >= table->rows())
+ table->insertRows(table->rows(), 1);
+ }
+
+ cell = table->cellAt(newRow, newColumn);
+ cursor = cell.firstCursorPosition();
+}
+
+void QWidgetTextControlPrivate::gotoPreviousTableCell()
+{
+ QTextTable *table = cursor.currentTable();
+ QTextTableCell cell = table->cellAt(cursor);
+
+ int newColumn = cell.column() - 1;
+ int newRow = cell.row();
+
+ if (newColumn < 0) {
+ newColumn = table->columns() - 1;
+ --newRow;
+ if (newRow < 0)
+ return;
+ }
+
+ cell = table->cellAt(newRow, newColumn);
+ cursor = cell.firstCursorPosition();
+}
+
+void QWidgetTextControlPrivate::createAutoBulletList()
+{
+ cursor.beginEditBlock();
+
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+
+ QTextListFormat listFmt;
+ listFmt.setStyle(QTextListFormat::ListDisc);
+ listFmt.setIndent(blockFmt.indent() + 1);
+
+ blockFmt.setIndent(0);
+ cursor.setBlockFormat(blockFmt);
+
+ cursor.createList(listFmt);
+
+ cursor.endEditBlock();
+}
+
+void QWidgetTextControlPrivate::init(Qt::TextFormat format, const QString &text, QTextDocument *document)
+{
+ Q_Q(QWidgetTextControl);
+ setContent(format, text, document);
+
+ doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
+ q->setCursorWidth(-1);
+}
+
+void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
+{
+ Q_Q(QWidgetTextControl);
+
+ // for use when called from setPlainText. we may want to re-use the currently
+ // set char format then.
+ const QTextCharFormat charFormatForInsertion = cursor.charFormat();
+
+ bool clearDocument = true;
+ if (!doc) {
+ if (document) {
+ doc = document;
+ clearDocument = false;
+ } else {
+ palette = QApplication::palette("QWidgetTextControl");
+ doc = new QTextDocument(q);
+ }
+ _q_documentLayoutChanged();
+ cursor = QTextCursor(doc);
+
+// #### doc->documentLayout()->setPaintDevice(viewport);
+
+ QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
+ QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
+ QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged()));
+
+ // convenience signal forwards
+ QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
+ QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
+ QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
+ QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
+ }
+
+ bool previousUndoRedoState = doc->isUndoRedoEnabled();
+ if (!document)
+ doc->setUndoRedoEnabled(false);
+
+ //Saving the index save some time.
+ static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()");
+ static int textChangedIndex = QWidgetTextControl::staticMetaObject.indexOfSignal("textChanged()");
+ // avoid multiple textChanged() signals being emitted
+ QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
+
+ if (!text.isEmpty()) {
+ // clear 'our' cursor for insertion to prevent
+ // the emission of the cursorPositionChanged() signal.
+ // instead we emit it only once at the end instead of
+ // at the end of the document after loading and when
+ // positioning the cursor again to the start of the
+ // document.
+ cursor = QTextCursor();
+ if (format == Qt::PlainText) {
+ QTextCursor formatCursor(doc);
+ // put the setPlainText and the setCharFormat into one edit block,
+ // so that the syntax highlight triggers only /once/ for the entire
+ // document, not twice.
+ formatCursor.beginEditBlock();
+ doc->setPlainText(text);
+ doc->setUndoRedoEnabled(false);
+ formatCursor.select(QTextCursor::Document);
+ formatCursor.setCharFormat(charFormatForInsertion);
+ formatCursor.endEditBlock();
+ } else {
+#ifndef QT_NO_TEXTHTMLPARSER
+ doc->setHtml(text);
+#else
+ doc->setPlainText(text);
+#endif
+ doc->setUndoRedoEnabled(false);
+ }
+ cursor = QTextCursor(doc);
+ } else if (clearDocument) {
+ doc->clear();
+ }
+ cursor.setCharFormat(charFormatForInsertion);
+
+ QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
+ emit q->textChanged();
+ if (!document)
+ doc->setUndoRedoEnabled(previousUndoRedoState);
+ _q_updateCurrentCharFormatAndSelection();
+ if (!document)
+ doc->setModified(false);
+
+ q->ensureCursorVisible();
+ emit q->cursorPositionChanged();
+}
+
+void QWidgetTextControlPrivate::startDrag()
+{
+#ifndef QT_NO_DRAGANDDROP
+ Q_Q(QWidgetTextControl);
+ mousePressed = false;
+ if (!contextWidget)
+ return;
+ QMimeData *data = q->createMimeDataFromSelection();
+
+ QDrag *drag = new QDrag(contextWidget);
+ drag->setMimeData(data);
+
+ Qt::DropActions actions = Qt::CopyAction;
+ Qt::DropAction action;
+ if (interactionFlags & Qt::TextEditable) {
+ actions |= Qt::MoveAction;
+ action = drag->exec(actions, Qt::MoveAction);
+ } else {
+ action = drag->exec(actions, Qt::CopyAction);
+ }
+
+ if (action == Qt::MoveAction && drag->target() != contextWidget)
+ cursor.removeSelectedText();
+#endif
+}
+
+void QWidgetTextControlPrivate::setCursorPosition(const QPointF &pos)
+{
+ Q_Q(QWidgetTextControl);
+ const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
+ if (cursorPos == -1)
+ return;
+ cursor.setPosition(cursorPos);
+}
+
+void QWidgetTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
+{
+ cursor.setPosition(pos, mode);
+
+ if (mode != QTextCursor::KeepAnchor) {
+ selectedWordOnDoubleClick = QTextCursor();
+ selectedBlockOnTrippleClick = QTextCursor();
+ }
+}
+
+void QWidgetTextControlPrivate::repaintCursor()
+{
+ Q_Q(QWidgetTextControl);
+ emit q->updateRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
+}
+
+void QWidgetTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
+{
+ Q_Q(QWidgetTextControl);
+ if (cursor.hasSelection()
+ && oldSelection.hasSelection()
+ && cursor.currentFrame() == oldSelection.currentFrame()
+ && !cursor.hasComplexSelection()
+ && !oldSelection.hasComplexSelection()
+ && cursor.anchor() == oldSelection.anchor()
+ ) {
+ QTextCursor differenceSelection(doc);
+ differenceSelection.setPosition(oldSelection.position());
+ differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
+ emit q->updateRequest(q->selectionRect(differenceSelection));
+ } else {
+ if (!oldSelection.isNull())
+ emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
+ emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
+ }
+}
+
+void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
+{
+ Q_Q(QWidgetTextControl);
+ if (forceEmitSelectionChanged)
+ emit q->selectionChanged();
+
+ bool current = cursor.hasSelection();
+ if (current == lastSelectionState)
+ return;
+
+ lastSelectionState = current;
+ emit q->copyAvailable(current);
+ if (!forceEmitSelectionChanged)
+ emit q->selectionChanged();
+ emit q->microFocusChanged();
+}
+
+void QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
+{
+ updateCurrentCharFormat();
+ selectionChanged();
+}
+
+#ifndef QT_NO_CLIPBOARD
+void QWidgetTextControlPrivate::setClipboardSelection()
+{
+ QClipboard *clipboard = QApplication::clipboard();
+ if (!cursor.hasSelection() || !clipboard->supportsSelection())
+ return;
+ Q_Q(QWidgetTextControl);
+ QMimeData *data = q->createMimeDataFromSelection();
+ clipboard->setMimeData(data, QClipboard::Selection);
+}
+#endif
+
+void QWidgetTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
+{
+ Q_Q(QWidgetTextControl);
+ if (someCursor.isCopyOf(cursor)) {
+ emit q->cursorPositionChanged();
+ emit q->microFocusChanged();
+ }
+}
+
+void QWidgetTextControlPrivate::_q_documentLayoutChanged()
+{
+ Q_Q(QWidgetTextControl);
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ QObject::connect(layout, SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
+ QObject::connect(layout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(_q_updateBlock(QTextBlock)));
+ QObject::connect(layout, SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
+
+}
+
+void QWidgetTextControlPrivate::setBlinkingCursorEnabled(bool enable)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (enable && QApplication::cursorFlashTime() > 0)
+ cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
+ else
+ cursorBlinkTimer.stop();
+
+ cursorOn = enable;
+
+ repaintCursor();
+}
+
+void QWidgetTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
+{
+ Q_Q(QWidgetTextControl);
+
+ // if inside the initial selected word keep that
+ if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
+ && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
+ q->setTextCursor(selectedWordOnDoubleClick);
+ return;
+ }
+
+ QTextCursor curs = selectedWordOnDoubleClick;
+ curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
+
+ if (!curs.movePosition(QTextCursor::StartOfWord))
+ return;
+ const int wordStartPos = curs.position();
+
+ const int blockPos = curs.block().position();
+ const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
+
+ QTextLine line = currentTextLine(curs);
+ if (!line.isValid())
+ return;
+
+ const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
+
+ if (!curs.movePosition(QTextCursor::EndOfWord))
+ return;
+ const int wordEndPos = curs.position();
+
+ const QTextLine otherLine = currentTextLine(curs);
+ if (otherLine.textStart() != line.textStart()
+ || wordEndPos == wordStartPos)
+ return;
+
+ const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
+
+ if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
+ return;
+
+ // keep the already selected word even when moving to the left
+ // (#39164)
+ if (suggestedNewPosition < selectedWordOnDoubleClick.position())
+ cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
+ else
+ cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
+
+ const qreal differenceToStart = mouseXPosition - wordStartX;
+ const qreal differenceToEnd = wordEndX - mouseXPosition;
+
+ if (differenceToStart < differenceToEnd)
+ setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
+ else
+ setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
+
+ if (interactionFlags & Qt::TextSelectableByMouse) {
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+#endif
+ selectionChanged(true);
+ }
+}
+
+void QWidgetTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition)
+{
+ Q_Q(QWidgetTextControl);
+
+ // if inside the initial selected line keep that
+ if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
+ && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
+ q->setTextCursor(selectedBlockOnTrippleClick);
+ return;
+ }
+
+ if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
+ cursor.setPosition(selectedBlockOnTrippleClick.selectionEnd());
+ cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
+ } else {
+ cursor.setPosition(selectedBlockOnTrippleClick.selectionStart());
+ cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ }
+
+ if (interactionFlags & Qt::TextSelectableByMouse) {
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+#endif
+ selectionChanged(true);
+ }
+}
+
+void QWidgetTextControlPrivate::_q_deleteSelected()
+{
+ if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
+ return;
+ cursor.removeSelectedText();
+}
+
+void QWidgetTextControl::undo()
+{
+ Q_D(QWidgetTextControl);
+ d->repaintSelection();
+ const int oldCursorPos = d->cursor.position();
+ d->doc->undo(&d->cursor);
+ if (d->cursor.position() != oldCursorPos)
+ emit cursorPositionChanged();
+ emit microFocusChanged();
+ ensureCursorVisible();
+}
+
+void QWidgetTextControl::redo()
+{
+ Q_D(QWidgetTextControl);
+ d->repaintSelection();
+ const int oldCursorPos = d->cursor.position();
+ d->doc->redo(&d->cursor);
+ if (d->cursor.position() != oldCursorPos)
+ emit cursorPositionChanged();
+ emit microFocusChanged();
+ ensureCursorVisible();
+}
+
+QWidgetTextControl::QWidgetTextControl(QObject *parent)
+ : QObject(*new QWidgetTextControlPrivate, parent)
+{
+ Q_D(QWidgetTextControl);
+ d->init();
+}
+
+QWidgetTextControl::QWidgetTextControl(const QString &text, QObject *parent)
+ : QObject(*new QWidgetTextControlPrivate, parent)
+{
+ Q_D(QWidgetTextControl);
+ d->init(Qt::RichText, text);
+}
+
+QWidgetTextControl::QWidgetTextControl(QTextDocument *doc, QObject *parent)
+ : QObject(*new QWidgetTextControlPrivate, parent)
+{
+ Q_D(QWidgetTextControl);
+ d->init(Qt::RichText, QString(), doc);
+}
+
+QWidgetTextControl::~QWidgetTextControl()
+{
+}
+
+void QWidgetTextControl::setDocument(QTextDocument *document)
+{
+ Q_D(QWidgetTextControl);
+ if (d->doc == document)
+ return;
+
+ d->doc->disconnect(this);
+ d->doc->documentLayout()->disconnect(this);
+ d->doc->documentLayout()->setPaintDevice(0);
+
+ if (d->doc->parent() == this)
+ delete d->doc;
+
+ d->doc = 0;
+ d->setContent(Qt::RichText, QString(), document);
+}
+
+QTextDocument *QWidgetTextControl::document() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc;
+}
+
+void QWidgetTextControl::setTextCursor(const QTextCursor &cursor)
+{
+ Q_D(QWidgetTextControl);
+ d->cursorIsFocusIndicator = false;
+ const bool posChanged = cursor.position() != d->cursor.position();
+ const QTextCursor oldSelection = d->cursor;
+ d->cursor = cursor;
+ d->cursorOn = d->hasFocus && (d->interactionFlags & Qt::TextEditable);
+ d->_q_updateCurrentCharFormatAndSelection();
+ ensureCursorVisible();
+ d->repaintOldAndNewSelection(oldSelection);
+ if (posChanged)
+ emit cursorPositionChanged();
+}
+
+QTextCursor QWidgetTextControl::textCursor() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->cursor;
+}
+
+#ifndef QT_NO_CLIPBOARD
+
+void QWidgetTextControl::cut()
+{
+ Q_D(QWidgetTextControl);
+ if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
+ return;
+ copy();
+ d->cursor.removeSelectedText();
+}
+
+void QWidgetTextControl::copy()
+{
+ Q_D(QWidgetTextControl);
+ if (!d->cursor.hasSelection())
+ return;
+ QMimeData *data = createMimeDataFromSelection();
+ QApplication::clipboard()->setMimeData(data);
+}
+
+void QWidgetTextControl::paste(QClipboard::Mode mode)
+{
+ const QMimeData *md = QApplication::clipboard()->mimeData(mode);
+ if (md)
+ insertFromMimeData(md);
+}
+#endif
+
+void QWidgetTextControl::clear()
+{
+ Q_D(QWidgetTextControl);
+ // clears and sets empty content
+ d->extraSelections.clear();
+ d->setContent();
+}
+
+
+void QWidgetTextControl::selectAll()
+{
+ Q_D(QWidgetTextControl);
+ const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
+ d->cursor.select(QTextCursor::Document);
+ d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
+ d->cursorIsFocusIndicator = false;
+ emit updateRequest();
+}
+
+void QWidgetTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
+{
+ QMatrix m;
+ m.translate(coordinateOffset.x(), coordinateOffset.y());
+ processEvent(e, m, contextWidget);
+}
+
+void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
+{
+ Q_D(QWidgetTextControl);
+ if (d->interactionFlags == Qt::NoTextInteraction) {
+ e->ignore();
+ return;
+ }
+
+ d->contextWidget = contextWidget;
+
+ if (!d->contextWidget) {
+ switch (e->type()) {
+#ifndef QT_NO_GRAPHICSVIEW
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneContextMenu:
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverMove:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHelp:
+ case QEvent::GraphicsSceneDragEnter:
+ case QEvent::GraphicsSceneDragMove:
+ case QEvent::GraphicsSceneDragLeave:
+ case QEvent::GraphicsSceneDrop: {
+ QGraphicsSceneEvent *ev = static_cast<QGraphicsSceneEvent *>(e);
+ d->contextWidget = ev->widget();
+ break;
+ }
+#endif // QT_NO_GRAPHICSVIEW
+ default: break;
+ };
+ }
+
+ switch (e->type()) {
+ case QEvent::KeyPress:
+ d->keyPressEvent(static_cast<QKeyEvent *>(e));
+ break;
+ case QEvent::MouseButtonPress: {
+ QMouseEvent *ev = static_cast<QMouseEvent *>(e);
+ d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
+ ev->buttons(), ev->globalPos());
+ break; }
+ case QEvent::MouseMove: {
+ QMouseEvent *ev = static_cast<QMouseEvent *>(e);
+ d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
+ ev->buttons(), ev->globalPos());
+ break; }
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *ev = static_cast<QMouseEvent *>(e);
+ d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
+ ev->buttons(), ev->globalPos());
+ break; }
+ case QEvent::MouseButtonDblClick: {
+ QMouseEvent *ev = static_cast<QMouseEvent *>(e);
+ d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
+ ev->buttons(), ev->globalPos());
+ break; }
+ case QEvent::InputMethod:
+ d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
+ break;
+#ifndef QT_NO_CONTEXTMENU
+ case QEvent::ContextMenu: {
+ QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
+ d->contextMenuEvent(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
+ break; }
+#endif // QT_NO_CONTEXTMENU
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ d->focusEvent(static_cast<QFocusEvent *>(e));
+ break;
+
+ case QEvent::EnabledChange:
+ d->isEnabled = e->isAccepted();
+ break;
+
+#ifndef QT_NO_TOOLTIP
+ case QEvent::ToolTip: {
+ QHelpEvent *ev = static_cast<QHelpEvent *>(e);
+ d->showToolTip(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
+ break;
+ }
+#endif // QT_NO_TOOLTIP
+
+#ifndef QT_NO_DRAGANDDROP
+ case QEvent::DragEnter: {
+ QDragEnterEvent *ev = static_cast<QDragEnterEvent *>(e);
+ if (d->dragEnterEvent(e, ev->mimeData()))
+ ev->acceptProposedAction();
+ break;
+ }
+ case QEvent::DragLeave:
+ d->dragLeaveEvent();
+ break;
+ case QEvent::DragMove: {
+ QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
+ if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
+ ev->acceptProposedAction();
+ break;
+ }
+ case QEvent::Drop: {
+ QDropEvent *ev = static_cast<QDropEvent *>(e);
+ if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
+ ev->acceptProposedAction();
+ break;
+ }
+#endif
+
+#ifndef QT_NO_GRAPHICSVIEW
+ case QEvent::GraphicsSceneMousePress: {
+ QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
+ d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ ev->screenPos());
+ break; }
+ case QEvent::GraphicsSceneMouseMove: {
+ QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
+ d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ ev->screenPos());
+ break; }
+ case QEvent::GraphicsSceneMouseRelease: {
+ QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
+ d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ ev->screenPos());
+ break; }
+ case QEvent::GraphicsSceneMouseDoubleClick: {
+ QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
+ d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ ev->screenPos());
+ break; }
+ case QEvent::GraphicsSceneContextMenu: {
+ QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
+ d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
+ break; }
+
+ case QEvent::GraphicsSceneHoverMove: {
+ QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
+ d->mouseMoveEvent(ev, Qt::NoButton, matrix.map(ev->pos()), ev->modifiers(),Qt::NoButton,
+ ev->screenPos());
+ break; }
+
+ case QEvent::GraphicsSceneDragEnter: {
+ QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
+ if (d->dragEnterEvent(e, ev->mimeData()))
+ ev->acceptProposedAction();
+ break; }
+ case QEvent::GraphicsSceneDragLeave:
+ d->dragLeaveEvent();
+ break;
+ case QEvent::GraphicsSceneDragMove: {
+ QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
+ if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
+ ev->acceptProposedAction();
+ break; }
+ case QEvent::GraphicsSceneDrop: {
+ QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
+ if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
+ ev->accept();
+ break; }
+#endif // QT_NO_GRAPHICSVIEW
+#ifdef QT_KEYPAD_NAVIGATION
+ case QEvent::EnterEditFocus:
+ case QEvent::LeaveEditFocus:
+ if (QApplication::keypadNavigationEnabled())
+ d->editFocusEvent(e);
+ break;
+#endif
+ case QEvent::ShortcutOverride:
+ if (d->interactionFlags & Qt::TextEditable) {
+ QKeyEvent* ke = static_cast<QKeyEvent *>(e);
+ if (ke->modifiers() == Qt::NoModifier
+ || ke->modifiers() == Qt::ShiftModifier
+ || ke->modifiers() == Qt::KeypadModifier) {
+ if (ke->key() < Qt::Key_Escape) {
+ ke->accept();
+ } else {
+ switch (ke->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Delete:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Backspace:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Tab:
+ ke->accept();
+ default:
+ break;
+ }
+ }
+#ifndef QT_NO_SHORTCUT
+ } else if (ke == QKeySequence::Copy
+ || ke == QKeySequence::Paste
+ || ke == QKeySequence::Cut
+ || ke == QKeySequence::Redo
+ || ke == QKeySequence::Undo
+ || ke == QKeySequence::MoveToNextWord
+ || ke == QKeySequence::MoveToPreviousWord
+ || ke == QKeySequence::MoveToStartOfDocument
+ || ke == QKeySequence::MoveToEndOfDocument
+ || ke == QKeySequence::SelectNextWord
+ || ke == QKeySequence::SelectPreviousWord
+ || ke == QKeySequence::SelectStartOfLine
+ || ke == QKeySequence::SelectEndOfLine
+ || ke == QKeySequence::SelectStartOfBlock
+ || ke == QKeySequence::SelectEndOfBlock
+ || ke == QKeySequence::SelectStartOfDocument
+ || ke == QKeySequence::SelectEndOfDocument
+ || ke == QKeySequence::SelectAll
+ ) {
+ ke->accept();
+#endif
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool QWidgetTextControl::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+void QWidgetTextControl::timerEvent(QTimerEvent *e)
+{
+ Q_D(QWidgetTextControl);
+ if (e->timerId() == d->cursorBlinkTimer.timerId()) {
+ d->cursorOn = !d->cursorOn;
+
+ if (d->cursor.hasSelection())
+ d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
+ != 0);
+
+ d->repaintCursor();
+ } else if (e->timerId() == d->trippleClickTimer.timerId()) {
+ d->trippleClickTimer.stop();
+ }
+}
+
+void QWidgetTextControl::setPlainText(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->setContent(Qt::PlainText, text);
+}
+
+void QWidgetTextControl::setHtml(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->setContent(Qt::RichText, text);
+}
+
+void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
+{
+ Q_Q(QWidgetTextControl);
+#ifndef QT_NO_SHORTCUT
+ if (e == QKeySequence::SelectAll) {
+ e->accept();
+ q->selectAll();
+ return;
+ }
+#ifndef QT_NO_CLIPBOARD
+ else if (e == QKeySequence::Copy) {
+ e->accept();
+ q->copy();
+ return;
+ }
+#endif
+#endif // QT_NO_SHORTCUT
+
+ if (interactionFlags & Qt::TextSelectableByKeyboard
+ && cursorMoveKeyEvent(e))
+ goto accept;
+
+ if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
+ if ((e->key() == Qt::Key_Return
+ || e->key() == Qt::Key_Enter
+#ifdef QT_KEYPAD_NAVIGATION
+ || e->key() == Qt::Key_Select
+#endif
+ )
+ && cursor.hasSelection()) {
+
+ e->accept();
+ activateLinkUnderCursor();
+ return;
+ }
+ }
+
+ if (!(interactionFlags & Qt::TextEditable)) {
+ e->ignore();
+ return;
+ }
+
+ if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
+ QTextBlockFormat fmt;
+ fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
+ cursor.mergeBlockFormat(fmt);
+ goto accept;
+ }
+
+ // schedule a repaint of the region of the cursor, as when we move it we
+ // want to make sure the old cursor disappears (not noticeable when moving
+ // only a few pixels but noticeable when jumping between cells in tables for
+ // example)
+ repaintSelection();
+
+ if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~Qt::ShiftModifier)) {
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+ QTextList *list = cursor.currentList();
+ if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
+ list->remove(cursor.block());
+ } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
+ blockFmt.setIndent(blockFmt.indent() - 1);
+ cursor.setBlockFormat(blockFmt);
+ } else {
+ QTextCursor localCursor = cursor;
+ localCursor.deletePreviousChar();
+ }
+ goto accept;
+ }
+#ifndef QT_NO_SHORTCUT
+ else if (e == QKeySequence::InsertParagraphSeparator) {
+ cursor.insertBlock();
+ e->accept();
+ goto accept;
+ } else if (e == QKeySequence::InsertLineSeparator) {
+ cursor.insertText(QString(QChar::LineSeparator));
+ e->accept();
+ goto accept;
+ }
+#endif
+ if (false) {
+ }
+#ifndef QT_NO_SHORTCUT
+ else if (e == QKeySequence::Undo) {
+ q->undo();
+ }
+ else if (e == QKeySequence::Redo) {
+ q->redo();
+ }
+#ifndef QT_NO_CLIPBOARD
+ else if (e == QKeySequence::Cut) {
+ q->cut();
+ }
+ else if (e == QKeySequence::Paste) {
+ QClipboard::Mode mode = QClipboard::Clipboard;
+#ifdef Q_WS_X11
+ if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
+ mode = QClipboard::Selection;
+#endif
+ q->paste(mode);
+ }
+#endif
+ else if (e == QKeySequence::Delete) {
+ QTextCursor localCursor = cursor;
+ localCursor.deleteChar();
+ }
+ else if (e == QKeySequence::DeleteEndOfWord) {
+ if (!cursor.hasSelection())
+ cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
+ else if (e == QKeySequence::DeleteStartOfWord) {
+ if (!cursor.hasSelection())
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
+ else if (e == QKeySequence::DeleteEndOfLine) {
+ QTextBlock block = cursor.block();
+ if (cursor.position() == block.position() + block.length() - 2)
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ else
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
+#endif // QT_NO_SHORTCUT
+ else {
+ goto process;
+ }
+ goto accept;
+
+process:
+ {
+ QString text = e->text();
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
+ if (overwriteMode
+ // no need to call deleteChar() if we have a selection, insertText
+ // does it already
+ && !cursor.hasSelection()
+ && !cursor.atBlockEnd())
+ cursor.deleteChar();
+
+ cursor.insertText(text);
+ selectionChanged();
+ } else {
+ e->ignore();
+ return;
+ }
+ }
+
+ accept:
+
+ e->accept();
+ cursorOn = true;
+
+ q->ensureCursorVisible();
+
+ updateCurrentCharFormat();
+}
+
+QVariant QWidgetTextControl::loadResource(int type, const QUrl &name)
+{
+#ifdef QT_NO_TEXTEDIT
+ Q_UNUSED(type);
+ Q_UNUSED(name);
+#else
+ if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent())) {
+ QUrl resolvedName = textEdit->d_func()->resolveUrl(name);
+ return textEdit->loadResource(type, resolvedName);
+ }
+#endif
+ return QVariant();
+}
+
+void QWidgetTextControlPrivate::_q_updateBlock(const QTextBlock &block)
+{
+ Q_Q(QWidgetTextControl);
+ QRectF br = q->blockBoundingRect(block);
+ br.setRight(qreal(INT_MAX)); // the block might have shrunk
+ emit q->updateRequest(br);
+}
+
+QRectF QWidgetTextControlPrivate::rectForPosition(int position) const
+{
+ Q_Q(const QWidgetTextControl);
+ const QTextBlock block = doc->findBlock(position);
+ if (!block.isValid())
+ return QRectF();
+ const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
+ const QTextLayout *layout = block.layout();
+ const QPointF layoutPos = q->blockBoundingRect(block).topLeft();
+ int relativePos = position - block.position();
+ if (preeditCursor != 0) {
+ int preeditPos = layout->preeditAreaPosition();
+ if (relativePos == preeditPos)
+ relativePos += preeditCursor;
+ else if (relativePos > preeditPos)
+ relativePos += layout->preeditAreaText().length();
+ }
+ QTextLine line = layout->lineForTextPosition(relativePos);
+
+ int cursorWidth;
+ {
+ bool ok = false;
+#ifndef QT_NO_PROPERTIES
+ cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
+#endif
+ if (!ok)
+ cursorWidth = 1;
+ }
+
+ QRectF r;
+
+ if (line.isValid()) {
+ qreal x = line.cursorToX(relativePos);
+ qreal w = 0;
+ if (overwriteMode) {
+ if (relativePos < line.textLength() - line.textStart())
+ w = line.cursorToX(relativePos + 1) - x;
+ else
+ w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ }
+ r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
+ cursorWidth + w, line.height());
+ } else {
+ r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
+ }
+
+ return r;
+}
+
+static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
+{
+ return frame->firstPosition() < position;
+}
+
+static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame)
+{
+ return position < frame->lastPosition();
+}
+
+static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
+{
+ QRectF r;
+ QTextFrame *frame = cursor.currentFrame();
+ const QList<QTextFrame *> children = frame->childFrames();
+
+ const QList<QTextFrame *>::ConstIterator firstFrame = qLowerBound(children.constBegin(), children.constEnd(),
+ cursor.selectionStart(), firstFramePosLessThanCursorPos);
+ const QList<QTextFrame *>::ConstIterator lastFrame = qUpperBound(children.constBegin(), children.constEnd(),
+ cursor.selectionEnd(), cursorPosLessThanLastFramePos);
+ for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) {
+ if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow)
+ r |= frame->document()->documentLayout()->frameBoundingRect(*it);
+ }
+ return r;
+}
+
+QRectF QWidgetTextControl::selectionRect(const QTextCursor &cursor) const
+{
+ Q_D(const QWidgetTextControl);
+
+ QRectF r = d->rectForPosition(cursor.selectionStart());
+
+ if (cursor.hasComplexSelection() && cursor.currentTable()) {
+ QTextTable *table = cursor.currentTable();
+
+ r = d->doc->documentLayout()->frameBoundingRect(table);
+ /*
+ int firstRow, numRows, firstColumn, numColumns;
+ cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
+
+ const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
+ const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
+
+ const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
+
+ QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
+
+ for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
+ const QTextTableCell cell = table->cellAt(firstRow, col);
+ const qreal y = layout->blockBoundingRect(cell.firstCursorPosition().block()).top();
+
+ tableSelRect.setTop(qMin(tableSelRect.top(), y));
+ }
+
+ for (int row = firstRow; row < firstRow + numRows; ++row) {
+ const QTextTableCell cell = table->cellAt(row, firstColumn);
+ const qreal x = layout->blockBoundingRect(cell.firstCursorPosition().block()).left();
+
+ tableSelRect.setLeft(qMin(tableSelRect.left(), x));
+ }
+
+ for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
+ const QTextTableCell cell = table->cellAt(firstRow + numRows - 1, col);
+ const qreal y = layout->blockBoundingRect(cell.lastCursorPosition().block()).bottom();
+
+ tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
+ }
+
+ for (int row = firstRow; row < firstRow + numRows; ++row) {
+ const QTextTableCell cell = table->cellAt(row, firstColumn + numColumns - 1);
+ const qreal x = layout->blockBoundingRect(cell.lastCursorPosition().block()).right();
+
+ tableSelRect.setRight(qMax(tableSelRect.right(), x));
+ }
+
+ r = tableSelRect.toRect();
+ */
+ } else if (cursor.hasSelection()) {
+ const int position = cursor.selectionStart();
+ const int anchor = cursor.selectionEnd();
+ const QTextBlock posBlock = d->doc->findBlock(position);
+ const QTextBlock anchorBlock = d->doc->findBlock(anchor);
+ if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
+ const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
+ const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
+
+ const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
+ const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
+ const QTextLayout *layout = posBlock.layout();
+ r = QRectF();
+ for (int i = firstLine; i <= lastLine; ++i) {
+ r |= layout->lineAt(i).rect();
+ r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled
+ }
+ r.translate(blockBoundingRect(posBlock).topLeft());
+ } else {
+ QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
+ r |= anchorRect;
+ r |= boundingRectOfFloatsInSelection(cursor);
+ QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
+ r.setLeft(frameRect.left());
+ r.setRight(frameRect.right());
+ }
+ if (r.isValid())
+ r.adjust(-1, -1, 1, 1);
+ }
+
+ return r;
+}
+
+QRectF QWidgetTextControl::selectionRect() const
+{
+ Q_D(const QWidgetTextControl);
+ return selectionRect(d->cursor);
+}
+
+void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons, const QPoint &globalPos)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (sendMouseEventToInputContext(
+ e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
+ return;
+ }
+
+ if (interactionFlags & Qt::LinksAccessibleByMouse) {
+ anchorOnMousePress = q->anchorAt(pos);
+
+ if (cursorIsFocusIndicator) {
+ cursorIsFocusIndicator = false;
+ repaintSelection();
+ cursor.clearSelection();
+ }
+ }
+ if (!(button & Qt::LeftButton) ||
+ !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
+ e->ignore();
+ return;
+ }
+
+ cursorIsFocusIndicator = false;
+ const QTextCursor oldSelection = cursor;
+ const int oldCursorPos = cursor.position();
+
+ mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
+#ifndef QT_NO_DRAGANDDROP
+ mightStartDrag = false;
+#endif
+
+ if (trippleClickTimer.isActive()
+ && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
+
+ cursor.movePosition(QTextCursor::StartOfBlock);
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ selectedBlockOnTrippleClick = cursor;
+
+ anchorOnMousePress = QString();
+
+ trippleClickTimer.stop();
+ } else {
+ int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
+ if (cursorPos == -1) {
+ e->ignore();
+ return;
+ }
+
+ if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
+ if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
+ selectedWordOnDoubleClick = cursor;
+ selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
+ }
+
+ if (selectedBlockOnTrippleClick.hasSelection())
+ extendBlockwiseSelection(cursorPos);
+ else if (selectedWordOnDoubleClick.hasSelection())
+ extendWordwiseSelection(cursorPos, pos.x());
+ else if (!wordSelectionEnabled)
+ setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
+ } else {
+
+ if (dragEnabled
+ && cursor.hasSelection()
+ && !cursorIsFocusIndicator
+ && cursorPos >= cursor.selectionStart()
+ && cursorPos <= cursor.selectionEnd()
+ && q->hitTest(pos, Qt::ExactHit) != -1) {
+#ifndef QT_NO_DRAGANDDROP
+ mightStartDrag = true;
+ dragStartPos = pos.toPoint();
+#endif
+ return;
+ }
+
+ setCursorPosition(cursorPos);
+ }
+ }
+
+ if (interactionFlags & Qt::TextEditable) {
+ q->ensureCursorVisible();
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+ _q_updateCurrentCharFormatAndSelection();
+ } else {
+ if (cursor.position() != oldCursorPos) {
+ emit q->cursorPositionChanged();
+ emit q->microFocusChanged();
+ }
+ selectionChanged();
+ }
+ repaintOldAndNewSelection(oldSelection);
+ hadSelectionOnMousePress = cursor.hasSelection();
+}
+
+void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &mousePos, Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons, const QPoint &globalPos)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (sendMouseEventToInputContext(
+ e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos)) {
+ return;
+ }
+
+ if (interactionFlags & Qt::LinksAccessibleByMouse) {
+ QString anchor = q->anchorAt(mousePos);
+ if (anchor != highlightedAnchor) {
+ highlightedAnchor = anchor;
+ emit q->linkHovered(anchor);
+ }
+ }
+
+ if (!(buttons & Qt::LeftButton))
+ return;
+
+ const bool editable = interactionFlags & Qt::TextEditable;
+
+ if (!(mousePressed
+ || editable
+ || mightStartDrag
+ || selectedWordOnDoubleClick.hasSelection()
+ || selectedBlockOnTrippleClick.hasSelection()))
+ return;
+
+ const QTextCursor oldSelection = cursor;
+ const int oldCursorPos = cursor.position();
+
+ if (mightStartDrag) {
+ if ((mousePos.toPoint() - dragStartPos).manhattanLength() > QApplication::startDragDistance())
+ startDrag();
+ return;
+ }
+
+ if (!mousePressed)
+ return;
+
+ const qreal mouseX = qreal(mousePos.x());
+
+ int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
+ if (newCursorPos == -1)
+ return;
+
+ if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
+ selectedWordOnDoubleClick = cursor;
+ selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
+ }
+
+ if (selectedBlockOnTrippleClick.hasSelection())
+ extendBlockwiseSelection(newCursorPos);
+ else if (selectedWordOnDoubleClick.hasSelection())
+ extendWordwiseSelection(newCursorPos, mouseX);
+ else
+ setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
+
+ if (interactionFlags & Qt::TextEditable) {
+ // don't call ensureVisible for the visible cursor to avoid jumping
+ // scrollbars. the autoscrolling ensures smooth scrolling if necessary.
+ //q->ensureCursorVisible();
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+ _q_updateCurrentCharFormatAndSelection();
+#ifndef QT_NO_IM
+ if (contextWidget) {
+ if (QInputContext *ic = inputContext()) {
+ ic->update();
+ }
+ }
+#endif //QT_NO_IM
+ } else {
+ //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+ }
+ selectionChanged(true);
+ repaintOldAndNewSelection(oldSelection);
+}
+
+void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons, const QPoint &globalPos)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (sendMouseEventToInputContext(
+ e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
+ return;
+ }
+
+ const QTextCursor oldSelection = cursor;
+ const int oldCursorPos = cursor.position();
+
+#ifndef QT_NO_DRAGANDDROP
+ if (mightStartDrag && (button & Qt::LeftButton)) {
+ mousePressed = false;
+ setCursorPosition(pos);
+ cursor.clearSelection();
+ selectionChanged();
+ }
+#endif
+ if (mousePressed) {
+ mousePressed = false;
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+ selectionChanged(true);
+ } else if (button == Qt::MidButton
+ && (interactionFlags & Qt::TextEditable)
+ && QApplication::clipboard()->supportsSelection()) {
+ setCursorPosition(pos);
+ const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Selection);
+ if (md)
+ q->insertFromMimeData(md);
+#endif
+ }
+
+ repaintOldAndNewSelection(oldSelection);
+
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+
+ if (interactionFlags & Qt::LinksAccessibleByMouse) {
+ if (!(button & Qt::LeftButton))
+ return;
+
+ const QString anchor = q->anchorAt(pos);
+
+ if (anchor.isEmpty())
+ return;
+
+ if (!cursor.hasSelection()
+ || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
+
+ const int anchorPos = q->hitTest(pos, Qt::ExactHit);
+ if (anchorPos != -1) {
+ cursor.setPosition(anchorPos);
+
+ QString anchor = anchorOnMousePress;
+ anchorOnMousePress = QString();
+ activateLinkUnderCursor(anchor);
+ }
+ }
+ }
+}
+
+void QWidgetTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons, const QPoint &globalPos)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (sendMouseEventToInputContext(
+ e, QEvent::MouseButtonDblClick, button, pos, modifiers, buttons, globalPos)) {
+ return;
+ }
+
+ if (button != Qt::LeftButton
+ || !(interactionFlags & Qt::TextSelectableByMouse)) {
+ e->ignore();
+ return;
+ }
+
+#ifndef QT_NO_DRAGANDDROP
+ mightStartDrag = false;
+#endif
+ const QTextCursor oldSelection = cursor;
+ setCursorPosition(pos);
+ QTextLine line = currentTextLine(cursor);
+ bool doEmit = false;
+ if (line.isValid() && line.textLength()) {
+ cursor.select(QTextCursor::WordUnderCursor);
+ doEmit = true;
+ }
+ repaintOldAndNewSelection(oldSelection);
+
+ cursorIsFocusIndicator = false;
+ selectedWordOnDoubleClick = cursor;
+
+ trippleClickPoint = pos;
+ trippleClickTimer.start(QApplication::doubleClickInterval(), q);
+ if (doEmit) {
+ selectionChanged();
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+#endif
+ emit q->cursorPositionChanged();
+ }
+}
+
+bool QWidgetTextControlPrivate::sendMouseEventToInputContext(
+ QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos,
+ Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
+{
+#if !defined(QT_NO_IM)
+ Q_Q(QWidgetTextControl);
+
+ QTextLayout *layout = cursor.block().layout();
+ if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) {
+ QInputContext *ctx = inputContext();
+ int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
+
+ if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length()) {
+ cursorPos = -1;
+ // don't send move events outside the preedit area
+ if (eventType == QEvent::MouseMove)
+ return true;
+ }
+ if (ctx) {
+ QMouseEvent ev(eventType, contextWidget->mapFromGlobal(globalPos),
+ contextWidget->topLevelWidget()->mapFromGlobal(globalPos), globalPos,
+ button, buttons, modifiers);
+ ctx->mouseHandler(cursorPos, &ev);
+ e->setAccepted(ev.isAccepted());
+ }
+ if (!layout->preeditAreaText().isEmpty())
+ return true;
+ }
+#else
+ Q_UNUSED(e);
+ Q_UNUSED(eventType);
+ Q_UNUSED(button);
+ Q_UNUSED(pos);
+ Q_UNUSED(modifiers);
+ Q_UNUSED(buttons);
+ Q_UNUSED(globalPos);
+#endif
+ return false;
+}
+
+void QWidgetTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
+{
+#ifdef QT_NO_CONTEXTMENU
+ Q_UNUSED(screenPos);
+ Q_UNUSED(docPos);
+ Q_UNUSED(contextWidget);
+#else
+ Q_Q(QWidgetTextControl);
+ if (!hasFocus)
+ return;
+ QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
+ if (!menu)
+ return;
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+ menu->popup(screenPos);
+#endif
+}
+
+bool QWidgetTextControlPrivate::dragEnterEvent(QEvent *e, const QMimeData *mimeData)
+{
+ Q_Q(QWidgetTextControl);
+ if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
+ e->ignore();
+ return false;
+ }
+
+ dndFeedbackCursor = QTextCursor();
+
+ return true; // accept proposed action
+}
+
+void QWidgetTextControlPrivate::dragLeaveEvent()
+{
+ Q_Q(QWidgetTextControl);
+
+ const QRectF crect = q->cursorRect(dndFeedbackCursor);
+ dndFeedbackCursor = QTextCursor();
+
+ if (crect.isValid())
+ emit q->updateRequest(crect);
+}
+
+bool QWidgetTextControlPrivate::dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
+{
+ Q_Q(QWidgetTextControl);
+ if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
+ e->ignore();
+ return false;
+ }
+
+ const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
+ if (cursorPos != -1) {
+ QRectF crect = q->cursorRect(dndFeedbackCursor);
+ if (crect.isValid())
+ emit q->updateRequest(crect);
+
+ dndFeedbackCursor = cursor;
+ dndFeedbackCursor.setPosition(cursorPos);
+
+ crect = q->cursorRect(dndFeedbackCursor);
+ emit q->updateRequest(crect);
+ }
+
+ return true; // accept proposed action
+}
+
+bool QWidgetTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QObject *source)
+{
+ Q_Q(QWidgetTextControl);
+ dndFeedbackCursor = QTextCursor();
+
+ if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
+ return false;
+
+ repaintSelection();
+
+ QTextCursor insertionCursor = q->cursorForPosition(pos);
+ insertionCursor.beginEditBlock();
+
+ if (dropAction == Qt::MoveAction && source == contextWidget)
+ cursor.removeSelectedText();
+
+ cursor = insertionCursor;
+ q->insertFromMimeData(mimeData);
+ insertionCursor.endEditBlock();
+ q->ensureCursorVisible();
+ return true; // accept proposed action
+}
+
+void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_Q(QWidgetTextControl);
+ if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
+ e->ignore();
+ return;
+ }
+ bool isGettingInput = !e->commitString().isEmpty()
+ || e->preeditString() != cursor.block().layout()->preeditAreaText()
+ || e->replacementLength() > 0;
+
+ cursor.beginEditBlock();
+ if (isGettingInput) {
+ cursor.removeSelectedText();
+ }
+
+ // insert commit string
+ if (!e->commitString().isEmpty() || e->replacementLength()) {
+ QTextCursor c = cursor;
+ c.setPosition(c.position() + e->replacementStart());
+ c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
+ c.insertText(e->commitString());
+ }
+
+ for (int i = 0; i < e->attributes().size(); ++i) {
+ const QInputMethodEvent::Attribute &a = e->attributes().at(i);
+ if (a.type == QInputMethodEvent::Selection) {
+ QTextCursor oldCursor = cursor;
+ int blockStart = a.start + cursor.block().position();
+ cursor.setPosition(blockStart, QTextCursor::MoveAnchor);
+ cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
+ q->ensureCursorVisible();
+ repaintOldAndNewSelection(oldCursor);
+ }
+ }
+
+ QTextBlock block = cursor.block();
+ QTextLayout *layout = block.layout();
+ if (isGettingInput)
+ layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
+ QList<QTextLayout::FormatRange> overrides;
+ const int oldPreeditCursor = preeditCursor;
+ preeditCursor = e->preeditString().length();
+ hideCursor = false;
+ for (int i = 0; i < e->attributes().size(); ++i) {
+ const QInputMethodEvent::Attribute &a = e->attributes().at(i);
+ if (a.type == QInputMethodEvent::Cursor) {
+ preeditCursor = a.start;
+ hideCursor = !a.length;
+ } else if (a.type == QInputMethodEvent::TextFormat) {
+ QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
+ if (f.isValid()) {
+ QTextLayout::FormatRange o;
+ o.start = a.start + cursor.position() - block.position();
+ o.length = a.length;
+ o.format = f;
+ overrides.append(o);
+ }
+ }
+ }
+ layout->setAdditionalFormats(overrides);
+ cursor.endEditBlock();
+ if (cursor.d)
+ cursor.d->setX();
+ if (oldPreeditCursor != preeditCursor)
+ emit q->microFocusChanged();
+}
+
+QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QWidgetTextControl);
+ QTextBlock block = d->cursor.block();
+ switch(property) {
+ case Qt::ImCursorRectangle:
+ return cursorRect();
+ case Qt::ImFont:
+ return QVariant(d->cursor.charFormat().font());
+ case Qt::ImCursorPosition:
+ return QVariant(d->cursor.position() - block.position());
+ case Qt::ImSurroundingText:
+ return QVariant(block.text());
+ case Qt::ImCurrentSelection:
+ return QVariant(d->cursor.selectedText());
+ case Qt::ImMaximumTextLength:
+ return QVariant(); // No limit.
+ case Qt::ImAnchorPosition:
+ return QVariant(qBound(0, d->cursor.anchor() - block.position(), block.length()));
+ default:
+ return QVariant();
+ }
+}
+
+void QWidgetTextControl::setFocus(bool focus, Qt::FocusReason reason)
+{
+ QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
+ reason);
+ processEvent(&ev);
+}
+
+void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
+{
+ Q_Q(QWidgetTextControl);
+ emit q->updateRequest(q->selectionRect());
+ if (e->gotFocus()) {
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason
+#ifdef Q_OS_SYMBIAN
+ || e->reason() == Qt::ActiveWindowFocusReason
+#endif
+ ))) {
+#endif
+ cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard);
+ if (interactionFlags & Qt::TextEditable) {
+ setBlinkingCursorEnabled(true);
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ }
+#endif
+ } else {
+ setBlinkingCursorEnabled(false);
+
+ if (cursorIsFocusIndicator
+ && e->reason() != Qt::ActiveWindowFocusReason
+ && e->reason() != Qt::PopupFocusReason
+ && cursor.hasSelection()) {
+ cursor.clearSelection();
+ }
+ }
+ hasFocus = e->gotFocus();
+}
+
+QString QWidgetTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
+{
+ if (anchorCursor.hasSelection()) {
+ QTextCursor cursor = anchorCursor;
+ if (cursor.selectionStart() != cursor.position())
+ cursor.setPosition(cursor.selectionStart());
+ cursor.movePosition(QTextCursor::NextCharacter);
+ QTextCharFormat fmt = cursor.charFormat();
+ if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
+ return fmt.stringProperty(QTextFormat::AnchorHref);
+ }
+ return QString();
+}
+
+#ifdef QT_KEYPAD_NAVIGATION
+void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
+{
+ Q_Q(QWidgetTextControl);
+
+ if (QApplication::keypadNavigationEnabled()) {
+ if (e->type() == QEvent::EnterEditFocus && interactionFlags & Qt::TextEditable) {
+ const QTextCursor oldSelection = cursor;
+ const int oldCursorPos = cursor.position();
+ const bool moved = cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+ q->ensureCursorVisible();
+ if (moved) {
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
+ emit q->microFocusChanged();
+ }
+ selectionChanged();
+ repaintOldAndNewSelection(oldSelection);
+
+ setBlinkingCursorEnabled(true);
+ } else
+ setBlinkingCursorEnabled(false);
+ }
+
+ hasEditFocus = e->type() == QEvent::EnterEditFocus ? true : false;
+}
+#endif
+
+#ifndef QT_NO_CONTEXTMENU
+QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent)
+{
+ Q_D(QWidgetTextControl);
+
+ const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
+
+ d->linkToCopy = QString();
+ if (!pos.isNull())
+ d->linkToCopy = anchorAt(pos);
+
+ if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
+ return 0;
+
+ QMenu *menu = new QMenu(parent);
+ QAction *a;
+
+ if (d->interactionFlags & Qt::TextEditable) {
+ a = menu->addAction(tr("&Undo") + ACCEL_KEY(QKeySequence::Undo), this, SLOT(undo()));
+ a->setEnabled(d->doc->isUndoAvailable());
+ a = menu->addAction(tr("&Redo") + ACCEL_KEY(QKeySequence::Redo), this, SLOT(redo()));
+ a->setEnabled(d->doc->isRedoAvailable());
+ menu->addSeparator();
+
+ a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut()));
+ a->setEnabled(d->cursor.hasSelection());
+ }
+
+ if (showTextSelectionActions) {
+ a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy()));
+ a->setEnabled(d->cursor.hasSelection());
+ }
+
+ if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
+ || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
+
+ a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
+ a->setEnabled(!d->linkToCopy.isEmpty());
+ }
+
+ if (d->interactionFlags & Qt::TextEditable) {
+#if !defined(QT_NO_CLIPBOARD)
+ a = menu->addAction(tr("&Paste") + ACCEL_KEY(QKeySequence::Paste), this, SLOT(paste()));
+ a->setEnabled(canPaste());
+#endif
+ a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
+ a->setEnabled(d->cursor.hasSelection());
+ }
+
+
+ if (showTextSelectionActions) {
+ menu->addSeparator();
+ a = menu->addAction(tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll), this, SLOT(selectAll()));
+ a->setEnabled(!d->doc->isEmpty());
+ }
+
+#if !defined(QT_NO_IM)
+ if (d->contextWidget) {
+ QInputContext *qic = d->inputContext();
+ if (qic) {
+ QList<QAction *> imActions = qic->actions();
+ for (int i = 0; i < imActions.size(); ++i)
+ menu->addAction(imActions.at(i));
+ }
+ }
+#endif
+
+#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+ if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
+#else
+ if (d->interactionFlags & Qt::TextEditable) {
+#endif
+ menu->addSeparator();
+ QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
+ menu->addMenu(ctrlCharacterMenu);
+ }
+
+ return menu;
+}
+#endif // QT_NO_CONTEXTMENU
+
+QTextCursor QWidgetTextControl::cursorForPosition(const QPointF &pos) const
+{
+ Q_D(const QWidgetTextControl);
+ int cursorPos = hitTest(pos, Qt::FuzzyHit);
+ if (cursorPos == -1)
+ cursorPos = 0;
+ QTextCursor c(d->doc);
+ c.setPosition(cursorPos);
+ return c;
+}
+
+QRectF QWidgetTextControl::cursorRect(const QTextCursor &cursor) const
+{
+ Q_D(const QWidgetTextControl);
+ if (cursor.isNull())
+ return QRectF();
+
+ return d->rectForPosition(cursor.position());
+}
+
+QRectF QWidgetTextControl::cursorRect() const
+{
+ Q_D(const QWidgetTextControl);
+ return cursorRect(d->cursor);
+}
+
+QRectF QWidgetTextControlPrivate::cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
+{
+ if (cursor.isNull())
+ return QRectF();
+
+ return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
+}
+
+QString QWidgetTextControl::anchorAt(const QPointF &pos) const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->documentLayout()->anchorAt(pos);
+}
+
+QString QWidgetTextControl::anchorAtCursor() const
+{
+ Q_D(const QWidgetTextControl);
+
+ return d->anchorForCursor(d->cursor);
+}
+
+bool QWidgetTextControl::overwriteMode() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->overwriteMode;
+}
+
+void QWidgetTextControl::setOverwriteMode(bool overwrite)
+{
+ Q_D(QWidgetTextControl);
+ d->overwriteMode = overwrite;
+}
+
+int QWidgetTextControl::cursorWidth() const
+{
+#ifndef QT_NO_PROPERTIES
+ Q_D(const QWidgetTextControl);
+ return d->doc->documentLayout()->property("cursorWidth").toInt();
+#else
+ return 1;
+#endif
+}
+
+void QWidgetTextControl::setCursorWidth(int width)
+{
+ Q_D(QWidgetTextControl);
+#ifdef QT_NO_PROPERTIES
+ Q_UNUSED(width);
+#else
+ if (width == -1)
+ width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth);
+ d->doc->documentLayout()->setProperty("cursorWidth", width);
+#endif
+ d->repaintCursor();
+}
+
+bool QWidgetTextControl::acceptRichText() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->acceptRichText;
+}
+
+void QWidgetTextControl::setAcceptRichText(bool accept)
+{
+ Q_D(QWidgetTextControl);
+ d->acceptRichText = accept;
+}
+
+#ifndef QT_NO_TEXTEDIT
+
+void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
+{
+ Q_D(QWidgetTextControl);
+
+ QHash<int, int> hash;
+ for (int i = 0; i < d->extraSelections.count(); ++i) {
+ const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(i);
+ hash.insertMulti(esel.cursor.anchor(), i);
+ }
+
+ for (int i = 0; i < selections.count(); ++i) {
+ const QTextEdit::ExtraSelection &sel = selections.at(i);
+ QHash<int, int>::iterator it = hash.find(sel.cursor.anchor());
+ if (it != hash.end()) {
+ const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
+ if (esel.cursor.position() == sel.cursor.position()
+ && esel.format == sel.format) {
+ hash.erase(it);
+ continue;
+ }
+ }
+ QRectF r = selectionRect(sel.cursor);
+ if (sel.format.boolProperty(QTextFormat::FullWidthSelection)) {
+ r.setLeft(0);
+ r.setWidth(qreal(INT_MAX));
+ }
+ emit updateRequest(r);
+ }
+
+ for (QHash<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
+ const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
+ QRectF r = selectionRect(esel.cursor);
+ if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
+ r.setLeft(0);
+ r.setWidth(qreal(INT_MAX));
+ }
+ emit updateRequest(r);
+ }
+
+ d->extraSelections.resize(selections.count());
+ for (int i = 0; i < selections.count(); ++i) {
+ d->extraSelections[i].cursor = selections.at(i).cursor;
+ d->extraSelections[i].format = selections.at(i).format;
+ }
+}
+
+QList<QTextEdit::ExtraSelection> QWidgetTextControl::extraSelections() const
+{
+ Q_D(const QWidgetTextControl);
+ QList<QTextEdit::ExtraSelection> selections;
+ for (int i = 0; i < d->extraSelections.count(); ++i) {
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = d->extraSelections.at(i).cursor;
+ sel.format = d->extraSelections.at(i).format;
+ selections.append(sel);
+ }
+ return selections;
+}
+
+#endif // QT_NO_TEXTEDIT
+
+void QWidgetTextControl::setTextWidth(qreal width)
+{
+ Q_D(QWidgetTextControl);
+ d->doc->setTextWidth(width);
+}
+
+qreal QWidgetTextControl::textWidth() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->textWidth();
+}
+
+QSizeF QWidgetTextControl::size() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->size();
+}
+
+void QWidgetTextControl::setOpenExternalLinks(bool open)
+{
+ Q_D(QWidgetTextControl);
+ d->openExternalLinks = open;
+}
+
+bool QWidgetTextControl::openExternalLinks() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->openExternalLinks;
+}
+
+bool QWidgetTextControl::ignoreUnusedNavigationEvents() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->ignoreUnusedNavigationEvents;
+}
+
+void QWidgetTextControl::setIgnoreUnusedNavigationEvents(bool ignore)
+{
+ Q_D(QWidgetTextControl);
+ d->ignoreUnusedNavigationEvents = ignore;
+}
+
+void QWidgetTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
+{
+ Q_D(QWidgetTextControl);
+ const QTextCursor oldSelection = d->cursor;
+ const bool moved = d->cursor.movePosition(op, mode);
+ d->_q_updateCurrentCharFormatAndSelection();
+ ensureCursorVisible();
+ d->repaintOldAndNewSelection(oldSelection);
+ if (moved)
+ emit cursorPositionChanged();
+}
+
+bool QWidgetTextControl::canPaste() const
+{
+#ifndef QT_NO_CLIPBOARD
+ Q_D(const QWidgetTextControl);
+ if (d->interactionFlags & Qt::TextEditable) {
+ const QMimeData *md = QApplication::clipboard()->mimeData();
+ return md && canInsertFromMimeData(md);
+ }
+#endif
+ return false;
+}
+
+void QWidgetTextControl::setCursorIsFocusIndicator(bool b)
+{
+ Q_D(QWidgetTextControl);
+ d->cursorIsFocusIndicator = b;
+ d->repaintCursor();
+}
+
+bool QWidgetTextControl::cursorIsFocusIndicator() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->cursorIsFocusIndicator;
+}
+
+
+void QWidgetTextControl::setDragEnabled(bool enabled)
+{
+ Q_D(QWidgetTextControl);
+ d->dragEnabled = enabled;
+}
+
+bool QWidgetTextControl::isDragEnabled() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->dragEnabled;
+}
+
+void QWidgetTextControl::setWordSelectionEnabled(bool enabled)
+{
+ Q_D(QWidgetTextControl);
+ d->wordSelectionEnabled = enabled;
+}
+
+bool QWidgetTextControl::isWordSelectionEnabled() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->wordSelectionEnabled;
+}
+
+void QWidgetTextControl::print(QPagedPaintDevice *printer) const
+{
+ Q_D(const QWidgetTextControl);
+ if (!printer)
+ return;
+ QTextDocument *tempDoc = 0;
+ const QTextDocument *doc = d->doc;
+ if (QPagedPaintDevicePrivate::get(printer)->printSelectionOnly) {
+ if (!d->cursor.hasSelection())
+ return;
+ tempDoc = new QTextDocument(const_cast<QTextDocument *>(doc));
+ tempDoc->setMetaInformation(QTextDocument::DocumentTitle, doc->metaInformation(QTextDocument::DocumentTitle));
+ tempDoc->setPageSize(doc->pageSize());
+ tempDoc->setDefaultFont(doc->defaultFont());
+ tempDoc->setUseDesignMetrics(doc->useDesignMetrics());
+ QTextCursor(tempDoc).insertFragment(d->cursor.selection());
+ doc = tempDoc;
+
+ // copy the custom object handlers
+ doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
+ }
+ doc->print(printer);
+ delete tempDoc;
+}
+
+QMimeData *QWidgetTextControl::createMimeDataFromSelection() const
+{
+ Q_D(const QWidgetTextControl);
+ const QTextDocumentFragment fragment(d->cursor);
+ return new QTextEditMimeData(fragment);
+}
+
+bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
+{
+ Q_D(const QWidgetTextControl);
+ if (d->acceptRichText)
+ return (source->hasText() && !source->text().isEmpty())
+ || source->hasHtml()
+ || source->hasFormat(QLatin1String("application/x-qrichtext"))
+ || source->hasFormat(QLatin1String("application/x-qt-richtext"));
+ else
+ return source->hasText() && !source->text().isEmpty();
+}
+
+void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
+{
+ Q_D(QWidgetTextControl);
+ if (!(d->interactionFlags & Qt::TextEditable) || !source)
+ return;
+
+ bool hasData = false;
+ QTextDocumentFragment fragment;
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
+ // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
+ QString richtext = QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
+ richtext.prepend(QLatin1String("<meta name=\"qrichtext\" content=\"1\" />"));
+ fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
+ hasData = true;
+ } else if (source->hasHtml() && d->acceptRichText) {
+ fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
+ hasData = true;
+ } else {
+ QString text = source->text();
+ if (!text.isNull()) {
+ fragment = QTextDocumentFragment::fromPlainText(text);
+ hasData = true;
+ }
+ }
+#else
+ fragment = QTextDocumentFragment::fromPlainText(source->text());
+#endif // QT_NO_TEXTHTMLPARSER
+
+ if (hasData)
+ d->cursor.insertFragment(fragment);
+ ensureCursorVisible();
+}
+
+bool QWidgetTextControl::findNextPrevAnchor(const QTextCursor &startCursor, bool next, QTextCursor &newAnchor)
+{
+ Q_D(QWidgetTextControl);
+
+ int anchorStart = -1;
+ QString anchorHref;
+ int anchorEnd = -1;
+
+ if (next) {
+ const int startPos = startCursor.selectionEnd();
+
+ QTextBlock block = d->doc->findBlock(startPos);
+ QTextBlock::Iterator it = block.begin();
+
+ while (!it.atEnd() && it.fragment().position() < startPos)
+ ++it;
+
+ while (block.isValid()) {
+ anchorStart = -1;
+
+ // find next anchor
+ for (; !it.atEnd(); ++it) {
+ const QTextFragment fragment = it.fragment();
+ const QTextCharFormat fmt = fragment.charFormat();
+
+ if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
+ anchorStart = fragment.position();
+ anchorHref = fmt.anchorHref();
+ break;
+ }
+ }
+
+ if (anchorStart != -1) {
+ anchorEnd = -1;
+
+ // find next non-anchor fragment
+ for (; !it.atEnd(); ++it) {
+ const QTextFragment fragment = it.fragment();
+ const QTextCharFormat fmt = fragment.charFormat();
+
+ if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
+ anchorEnd = fragment.position();
+ break;
+ }
+ }
+
+ if (anchorEnd == -1)
+ anchorEnd = block.position() + block.length() - 1;
+
+ // make found selection
+ break;
+ }
+
+ block = block.next();
+ it = block.begin();
+ }
+ } else {
+ int startPos = startCursor.selectionStart();
+ if (startPos > 0)
+ --startPos;
+
+ QTextBlock block = d->doc->findBlock(startPos);
+ QTextBlock::Iterator blockStart = block.begin();
+ QTextBlock::Iterator it = block.end();
+
+ if (startPos == block.position()) {
+ it = block.begin();
+ } else {
+ do {
+ if (it == blockStart) {
+ it = QTextBlock::Iterator();
+ block = QTextBlock();
+ } else {
+ --it;
+ }
+ } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
+ }
+
+ while (block.isValid()) {
+ anchorStart = -1;
+
+ if (!it.atEnd()) {
+ do {
+ const QTextFragment fragment = it.fragment();
+ const QTextCharFormat fmt = fragment.charFormat();
+
+ if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
+ anchorStart = fragment.position() + fragment.length();
+ anchorHref = fmt.anchorHref();
+ break;
+ }
+
+ if (it == blockStart)
+ it = QTextBlock::Iterator();
+ else
+ --it;
+ } while (!it.atEnd());
+ }
+
+ if (anchorStart != -1 && !it.atEnd()) {
+ anchorEnd = -1;
+
+ do {
+ const QTextFragment fragment = it.fragment();
+ const QTextCharFormat fmt = fragment.charFormat();
+
+ if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
+ anchorEnd = fragment.position() + fragment.length();
+ break;
+ }
+
+ if (it == blockStart)
+ it = QTextBlock::Iterator();
+ else
+ --it;
+ } while (!it.atEnd());
+
+ if (anchorEnd == -1)
+ anchorEnd = qMax(0, block.position());
+
+ break;
+ }
+
+ block = block.previous();
+ it = block.end();
+ if (it != block.begin())
+ --it;
+ blockStart = block.begin();
+ }
+
+ }
+
+ if (anchorStart != -1 && anchorEnd != -1) {
+ newAnchor = d->cursor;
+ newAnchor.setPosition(anchorStart);
+ newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
+ return true;
+ }
+
+ return false;
+}
+
+void QWidgetTextControlPrivate::activateLinkUnderCursor(QString href)
+{
+ QTextCursor oldCursor = cursor;
+
+ if (href.isEmpty()) {
+ QTextCursor tmp = cursor;
+ if (tmp.selectionStart() != tmp.position())
+ tmp.setPosition(tmp.selectionStart());
+ tmp.movePosition(QTextCursor::NextCharacter);
+ href = tmp.charFormat().anchorHref();
+ }
+ if (href.isEmpty())
+ return;
+
+ if (!cursor.hasSelection()) {
+ QTextBlock block = cursor.block();
+ const int cursorPos = cursor.position();
+
+ QTextBlock::Iterator it = block.begin();
+ QTextBlock::Iterator linkFragment;
+
+ for (; !it.atEnd(); ++it) {
+ QTextFragment fragment = it.fragment();
+ const int fragmentPos = fragment.position();
+ if (fragmentPos <= cursorPos &&
+ fragmentPos + fragment.length() > cursorPos) {
+ linkFragment = it;
+ break;
+ }
+ }
+
+ if (!linkFragment.atEnd()) {
+ it = linkFragment;
+ cursor.setPosition(it.fragment().position());
+ if (it != block.begin()) {
+ do {
+ --it;
+ QTextFragment fragment = it.fragment();
+ if (fragment.charFormat().anchorHref() != href)
+ break;
+ cursor.setPosition(fragment.position());
+ } while (it != block.begin());
+ }
+
+ for (it = linkFragment; !it.atEnd(); ++it) {
+ QTextFragment fragment = it.fragment();
+ if (fragment.charFormat().anchorHref() != href)
+ break;
+ cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
+ }
+ }
+ }
+
+ if (hasFocus) {
+ cursorIsFocusIndicator = true;
+ } else {
+ cursorIsFocusIndicator = false;
+ cursor.clearSelection();
+ }
+ repaintOldAndNewSelection(oldCursor);
+
+#ifndef QT_NO_DESKTOPSERVICES
+ if (openExternalLinks)
+ QDesktopServices::openUrl(href);
+ else
+#endif
+ emit q_func()->linkActivated(href);
+}
+
+#ifndef QT_NO_TOOLTIP
+void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
+{
+ const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
+ if (toolTip.isEmpty())
+ return;
+ QToolTip::showText(globalPos, toolTip, contextWidget);
+}
+#endif // QT_NO_TOOLTIP
+
+bool QWidgetTextControl::setFocusToNextOrPreviousAnchor(bool next)
+{
+ Q_D(QWidgetTextControl);
+
+ if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
+ return false;
+
+ QRectF crect = selectionRect();
+ emit updateRequest(crect);
+
+ // If we don't have a current anchor, we start from the start/end
+ if (!d->cursor.hasSelection()) {
+ d->cursor = QTextCursor(d->doc);
+ if (next)
+ d->cursor.movePosition(QTextCursor::Start);
+ else
+ d->cursor.movePosition(QTextCursor::End);
+ }
+
+ QTextCursor newAnchor;
+ if (findNextPrevAnchor(d->cursor, next, newAnchor)) {
+ d->cursor = newAnchor;
+ d->cursorIsFocusIndicator = true;
+ } else {
+ d->cursor.clearSelection();
+ }
+
+ if (d->cursor.hasSelection()) {
+ crect = selectionRect();
+ emit updateRequest(crect);
+ emit visibilityRequest(crect);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QWidgetTextControl::setFocusToAnchor(const QTextCursor &newCursor)
+{
+ Q_D(QWidgetTextControl);
+
+ if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
+ return false;
+
+ // Verify that this is an anchor.
+ const QString anchorHref = d->anchorForCursor(newCursor);
+ if (anchorHref.isEmpty())
+ return false;
+
+ // and process it
+ QRectF crect = selectionRect();
+ emit updateRequest(crect);
+
+ d->cursor.setPosition(newCursor.selectionStart());
+ d->cursor.setPosition(newCursor.selectionEnd(), QTextCursor::KeepAnchor);
+ d->cursorIsFocusIndicator = true;
+
+ crect = selectionRect();
+ emit updateRequest(crect);
+ emit visibilityRequest(crect);
+ return true;
+}
+
+void QWidgetTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QWidgetTextControl);
+ if (flags == d->interactionFlags)
+ return;
+ d->interactionFlags = flags;
+
+ if (d->hasFocus)
+ d->setBlinkingCursorEnabled(flags & Qt::TextEditable);
+}
+
+Qt::TextInteractionFlags QWidgetTextControl::textInteractionFlags() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->interactionFlags;
+}
+
+void QWidgetTextControl::mergeCurrentCharFormat(const QTextCharFormat &modifier)
+{
+ Q_D(QWidgetTextControl);
+ d->cursor.mergeCharFormat(modifier);
+ d->updateCurrentCharFormat();
+}
+
+void QWidgetTextControl::setCurrentCharFormat(const QTextCharFormat &format)
+{
+ Q_D(QWidgetTextControl);
+ d->cursor.setCharFormat(format);
+ d->updateCurrentCharFormat();
+}
+
+QTextCharFormat QWidgetTextControl::currentCharFormat() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->cursor.charFormat();
+}
+
+void QWidgetTextControl::insertPlainText(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->cursor.insertText(text);
+}
+
+#ifndef QT_NO_TEXTHTMLPARSER
+void QWidgetTextControl::insertHtml(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->cursor.insertHtml(text);
+}
+#endif // QT_NO_TEXTHTMLPARSER
+
+QPointF QWidgetTextControl::anchorPosition(const QString &name) const
+{
+ Q_D(const QWidgetTextControl);
+ if (name.isEmpty())
+ return QPointF();
+
+ QRectF r;
+ for (QTextBlock block = d->doc->begin(); block.isValid(); block = block.next()) {
+ QTextCharFormat format = block.charFormat();
+ if (format.isAnchor() && format.anchorNames().contains(name)) {
+ r = d->rectForPosition(block.position());
+ break;
+ }
+
+ for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
+ QTextFragment fragment = it.fragment();
+ format = fragment.charFormat();
+ if (format.isAnchor() && format.anchorNames().contains(name)) {
+ r = d->rectForPosition(fragment.position());
+ block = QTextBlock();
+ break;
+ }
+ }
+ }
+ if (!r.isValid())
+ return QPointF();
+ return QPointF(0, r.top());
+}
+
+void QWidgetTextControl::adjustSize()
+{
+ Q_D(QWidgetTextControl);
+ d->doc->adjustSize();
+}
+
+bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags options)
+{
+ Q_D(QWidgetTextControl);
+ QTextCursor search = d->doc->find(exp, d->cursor, options);
+ if (search.isNull())
+ return false;
+
+ setTextCursor(search);
+ return true;
+}
+
+
+
+void QWidgetTextControlPrivate::append(const QString &text, Qt::TextFormat format)
+{
+ QTextCursor tmp(doc);
+ tmp.beginEditBlock();
+ tmp.movePosition(QTextCursor::End);
+
+ if (!doc->isEmpty())
+ tmp.insertBlock(cursor.blockFormat(), cursor.charFormat());
+ else
+ tmp.setCharFormat(cursor.charFormat());
+
+ // preserve the char format
+ QTextCharFormat oldCharFormat = cursor.charFormat();
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (format == Qt::RichText || (format == Qt::AutoText && Qt::mightBeRichText(text))) {
+ tmp.insertHtml(text);
+ } else {
+ tmp.insertText(text);
+ }
+#else
+ tmp.insertText(text);
+#endif // QT_NO_TEXTHTMLPARSER
+ if (!cursor.hasSelection())
+ cursor.setCharFormat(oldCharFormat);
+
+ tmp.endEditBlock();
+}
+
+void QWidgetTextControl::append(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->append(text, Qt::AutoText);
+}
+
+void QWidgetTextControl::appendHtml(const QString &html)
+{
+ Q_D(QWidgetTextControl);
+ d->append(html, Qt::RichText);
+}
+
+void QWidgetTextControl::appendPlainText(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->append(text, Qt::PlainText);
+}
+
+
+void QWidgetTextControl::ensureCursorVisible()
+{
+ Q_D(QWidgetTextControl);
+ QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
+ emit visibilityRequest(crect);
+ emit microFocusChanged();
+}
+
+QPalette QWidgetTextControl::palette() const
+{
+ Q_D(const QWidgetTextControl);
+ return d->palette;
+}
+
+void QWidgetTextControl::setPalette(const QPalette &pal)
+{
+ Q_D(QWidgetTextControl);
+ d->palette = pal;
+}
+
+QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QWidget *widget) const
+{
+ Q_D(const QWidgetTextControl);
+
+ QAbstractTextDocumentLayout::PaintContext ctx;
+
+ ctx.selections = d->extraSelections;
+ ctx.palette = d->palette;
+ if (d->cursorOn && d->isEnabled) {
+ if (d->hideCursor)
+ ctx.cursorPosition = -1;
+ else if (d->preeditCursor != 0)
+ ctx.cursorPosition = - (d->preeditCursor + 2);
+ else
+ ctx.cursorPosition = d->cursor.position();
+ }
+
+ if (!d->dndFeedbackCursor.isNull())
+ ctx.cursorPosition = d->dndFeedbackCursor.position();
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled() || d->hasEditFocus)
+#endif
+ if (d->cursor.hasSelection()) {
+ QAbstractTextDocumentLayout::Selection selection;
+ selection.cursor = d->cursor;
+ if (d->cursorIsFocusIndicator) {
+ QStyleOption opt;
+ opt.palette = ctx.palette;
+ QStyleHintReturnVariant ret;
+ QStyle *style = QApplication::style();
+ if (widget)
+ style = widget->style();
+ style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
+ selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
+ } else {
+ QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
+ selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
+ selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
+ QStyleOption opt;
+ QStyle *style = QApplication::style();
+ if (widget) {
+ opt.initFrom(widget);
+ style = widget->style();
+ }
+ if (style->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, widget))
+ selection.format.setProperty(QTextFormat::FullWidthSelection, true);
+ }
+ ctx.selections.append(selection);
+ }
+
+ return ctx;
+}
+
+void QWidgetTextControl::drawContents(QPainter *p, const QRectF &rect, QWidget *widget)
+{
+ Q_D(QWidgetTextControl);
+ p->save();
+ QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext(widget);
+ if (rect.isValid())
+ p->setClipRect(rect, Qt::IntersectClip);
+ ctx.clip = rect;
+
+ d->doc->documentLayout()->draw(p, ctx);
+ p->restore();
+}
+
+void QWidgetTextControlPrivate::_q_copyLink()
+{
+#ifndef QT_NO_CLIPBOARD
+ QMimeData *md = new QMimeData;
+ md->setText(linkToCopy);
+ QApplication::clipboard()->setMimeData(md);
+#endif
+}
+
+QInputContext *QWidgetTextControlPrivate::inputContext()
+{
+ QInputContext *ctx = contextWidget->inputContext();
+ if (!ctx && contextWidget->parentWidget())
+ ctx = contextWidget->parentWidget()->inputContext();
+ return ctx;
+}
+
+int QWidgetTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->documentLayout()->hitTest(point, accuracy);
+}
+
+QRectF QWidgetTextControl::blockBoundingRect(const QTextBlock &block) const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->documentLayout()->blockBoundingRect(block);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+#define NUM_CONTROL_CHARACTERS 10
+const struct QUnicodeControlCharacter {
+ const char *text;
+ ushort character;
+} qt_controlCharacters[NUM_CONTROL_CHARACTERS] = {
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRM Left-to-right mark"), 0x200e },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLM Right-to-left mark"), 0x200f },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWJ Zero width joiner"), 0x200d },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWNJ Zero width non-joiner"), 0x200c },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWSP Zero width space"), 0x200b },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRE Start of left-to-right embedding"), 0x202a },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLE Start of right-to-left embedding"), 0x202b },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRO Start of left-to-right override"), 0x202d },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLO Start of right-to-left override"), 0x202e },
+ { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "PDF Pop directional formatting"), 0x202c },
+};
+
+QUnicodeControlCharacterMenu::QUnicodeControlCharacterMenu(QObject *_editWidget, QWidget *parent)
+ : QMenu(parent), editWidget(_editWidget)
+{
+ setTitle(tr("Insert Unicode control character"));
+ for (int i = 0; i < NUM_CONTROL_CHARACTERS; ++i) {
+ addAction(tr(qt_controlCharacters[i].text), this, SLOT(menuActionTriggered()));
+ }
+}
+
+void QUnicodeControlCharacterMenu::menuActionTriggered()
+{
+ QAction *a = qobject_cast<QAction *>(sender());
+ int idx = actions().indexOf(a);
+ if (idx < 0 || idx >= NUM_CONTROL_CHARACTERS)
+ return;
+ QChar c(qt_controlCharacters[idx].character);
+ QString str(c);
+
+#ifndef QT_NO_TEXTEDIT
+ if (QTextEdit *edit = qobject_cast<QTextEdit *>(editWidget)) {
+ edit->insertPlainText(str);
+ return;
+ }
+#endif
+ if (QWidgetTextControl *control = qobject_cast<QWidgetTextControl *>(editWidget)) {
+ control->insertPlainText(str);
+ }
+#ifndef QT_NO_LINEEDIT
+ if (QLineEdit *edit = qobject_cast<QLineEdit *>(editWidget)) {
+ edit->insert(str);
+ return;
+ }
+#endif
+}
+#endif // QT_NO_CONTEXTMENU
+
+QStringList QTextEditMimeData::formats() const
+{
+ if (!fragment.isEmpty())
+ return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html")
+#ifndef QT_NO_TEXTODFWRITER
+ << QString::fromLatin1("application/vnd.oasis.opendocument.text")
+#endif
+ ;
+ else
+ return QMimeData::formats();
+}
+
+QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
+{
+ if (!fragment.isEmpty())
+ setup();
+ return QMimeData::retrieveData(mimeType, type);
+}
+
+void QTextEditMimeData::setup() const
+{
+ QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
+#ifndef QT_NO_TEXTHTMLPARSER
+ that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
+#endif
+#ifndef QT_NO_TEXTODFWRITER
+ {
+ QBuffer buffer;
+ QTextDocumentWriter writer(&buffer, "ODF");
+ writer.write(fragment);
+ buffer.close();
+ that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
+ }
+#endif
+ that->setText(fragment.toPlainText());
+ fragment = QTextDocumentFragment();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgettextcontrol_p.cpp"
+
+#endif // QT_NO_TEXTCONTROL
diff --git a/src/widgets/widgets/qwidgettextcontrol_p.h b/src/widgets/widgets/qwidgettextcontrol_p.h
new file mode 100644
index 0000000000..67ae0596b3
--- /dev/null
+++ b/src/widgets/widgets/qwidgettextcontrol_p.h
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETTEXTCONTROL_P_H
+#define QWIDGETTEXTCONTROL_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/qtextdocument.h>
+#include <QtGui/qtextoption.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qtextformat.h>
+#include <QtWidgets/qtextedit.h>
+#include <QtWidgets/qmenu.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qabstracttextdocumentlayout.h>
+#include <QtGui/qtextdocumentfragment.h>
+#include <QtGui/qclipboard.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QStyleSheet;
+class QTextDocument;
+class QMenu;
+class QWidgetTextControlPrivate;
+class QMimeData;
+class QAbstractScrollArea;
+class QEvent;
+class QTimerEvent;
+
+class Q_WIDGETS_EXPORT QWidgetTextControl : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWidgetTextControl)
+#ifndef QT_NO_TEXTHTMLPARSER
+ Q_PROPERTY(QString html READ toHtml WRITE setHtml NOTIFY textChanged USER true)
+#endif
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
+ Q_PROPERTY(bool acceptRichText READ acceptRichText WRITE setAcceptRichText)
+ Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
+ Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags)
+ Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)
+ Q_PROPERTY(bool ignoreUnusedNavigationEvents READ ignoreUnusedNavigationEvents WRITE setIgnoreUnusedNavigationEvents)
+public:
+ explicit QWidgetTextControl(QObject *parent = 0);
+ explicit QWidgetTextControl(const QString &text, QObject *parent = 0);
+ explicit QWidgetTextControl(QTextDocument *doc, QObject *parent = 0);
+ virtual ~QWidgetTextControl();
+
+ void setDocument(QTextDocument *document);
+ QTextDocument *document() const;
+
+ void setTextCursor(const QTextCursor &cursor);
+ QTextCursor textCursor() const;
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ void mergeCurrentCharFormat(const QTextCharFormat &modifier);
+
+ void setCurrentCharFormat(const QTextCharFormat &format);
+ QTextCharFormat currentCharFormat() const;
+
+ bool find(const QString &exp, QTextDocument::FindFlags options = 0);
+
+ inline QString toPlainText() const
+ { return document()->toPlainText(); }
+#ifndef QT_NO_TEXTHTMLPARSER
+ inline QString toHtml() const
+ { return document()->toHtml(); }
+#endif
+
+ virtual void ensureCursorVisible();
+
+ virtual QVariant loadResource(int type, const QUrl &name);
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *createStandardContextMenu(const QPointF &pos, QWidget *parent);
+#endif
+
+ QTextCursor cursorForPosition(const QPointF &pos) const;
+ QRectF cursorRect(const QTextCursor &cursor) const;
+ QRectF cursorRect() const;
+ QRectF selectionRect(const QTextCursor &cursor) const;
+ QRectF selectionRect() const;
+
+ QString anchorAt(const QPointF &pos) const;
+ QPointF anchorPosition(const QString &name) const;
+
+ QString anchorAtCursor() const;
+
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
+
+ int cursorWidth() const;
+ void setCursorWidth(int width);
+
+ bool acceptRichText() const;
+ void setAcceptRichText(bool accept);
+
+#ifndef QT_NO_TEXTEDIT
+ void setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections);
+ QList<QTextEdit::ExtraSelection> extraSelections() const;
+#endif
+
+ void setTextWidth(qreal width);
+ qreal textWidth() const;
+ QSizeF size() const;
+
+ void setOpenExternalLinks(bool open);
+ bool openExternalLinks() const;
+
+ void setIgnoreUnusedNavigationEvents(bool ignore);
+ bool ignoreUnusedNavigationEvents() const;
+
+ void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+
+ bool canPaste() const;
+
+ void setCursorIsFocusIndicator(bool b);
+ bool cursorIsFocusIndicator() const;
+
+ void setDragEnabled(bool enabled);
+ bool isDragEnabled() const;
+
+ bool isWordSelectionEnabled() const;
+ void setWordSelectionEnabled(bool enabled);
+
+ void print(QPagedPaintDevice *printer) const;
+
+ virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
+ virtual QRectF blockBoundingRect(const QTextBlock &block) const;
+ QAbstractTextDocumentLayout::PaintContext getPaintContext(QWidget *widget) const;
+
+public Q_SLOTS:
+ void setPlainText(const QString &text);
+ void setHtml(const QString &text);
+
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste(QClipboard::Mode mode = QClipboard::Clipboard);
+#endif
+
+ void undo();
+ void redo();
+
+ void clear();
+ void selectAll();
+
+ void insertPlainText(const QString &text);
+#ifndef QT_NO_TEXTHTMLPARSER
+ void insertHtml(const QString &text);
+#endif
+
+ void append(const QString &text);
+ void appendHtml(const QString &html);
+ void appendPlainText(const QString &text);
+
+ void adjustSize();
+
+Q_SIGNALS:
+ void textChanged();
+ void undoAvailable(bool b);
+ void redoAvailable(bool b);
+ void currentCharFormatChanged(const QTextCharFormat &format);
+ void copyAvailable(bool b);
+ void selectionChanged();
+ void cursorPositionChanged();
+
+ // control signals
+ void updateRequest(const QRectF &rect = QRectF());
+ void documentSizeChanged(const QSizeF &);
+ void blockCountChanged(int newBlockCount);
+ void visibilityRequest(const QRectF &rect);
+ void microFocusChanged();
+ void linkActivated(const QString &link);
+ void linkHovered(const QString &);
+ void modificationChanged(bool m);
+
+public:
+ // control properties
+ QPalette palette() const;
+ void setPalette(const QPalette &pal);
+
+ virtual void processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget = 0);
+ void processEvent(QEvent *e, const QPointF &coordinateOffset = QPointF(), QWidget *contextWidget = 0);
+
+ // control methods
+ void drawContents(QPainter *painter, const QRectF &rect = QRectF(), QWidget *widget = 0);
+
+ void setFocus(bool focus, Qt::FocusReason = Qt::OtherFocusReason);
+
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ virtual QMimeData *createMimeDataFromSelection() const;
+ virtual bool canInsertFromMimeData(const QMimeData *source) const;
+ virtual void insertFromMimeData(const QMimeData *source);
+
+ bool setFocusToAnchor(const QTextCursor &newCursor);
+ bool setFocusToNextOrPreviousAnchor(bool next);
+ bool findNextPrevAnchor(const QTextCursor& from, bool next, QTextCursor& newAnchor);
+
+protected:
+ virtual void timerEvent(QTimerEvent *e);
+
+ virtual bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QWidgetTextControl)
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentCharFormatAndSelection())
+ Q_PRIVATE_SLOT(d_func(), void _q_emitCursorPosChanged(const QTextCursor &))
+ Q_PRIVATE_SLOT(d_func(), void _q_deleteSelected())
+ Q_PRIVATE_SLOT(d_func(), void _q_copyLink())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateBlock(const QTextBlock &))
+ Q_PRIVATE_SLOT(d_func(), void _q_documentLayoutChanged())
+};
+
+
+#ifndef QT_NO_CONTEXTMENU
+class QUnicodeControlCharacterMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ QUnicodeControlCharacterMenu(QObject *editWidget, QWidget *parent);
+
+private Q_SLOTS:
+ void menuActionTriggered();
+
+private:
+ QObject *editWidget;
+};
+#endif // QT_NO_CONTEXTMENU
+
+
+// also used by QLabel
+class QTextEditMimeData : public QMimeData
+{
+public:
+ inline QTextEditMimeData(const QTextDocumentFragment &aFragment) : fragment(aFragment) {}
+
+ virtual QStringList formats() const;
+protected:
+ virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const;
+private:
+ void setup() const;
+
+ mutable QTextDocumentFragment fragment;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QWidgetTextControl_H
diff --git a/src/widgets/widgets/qwidgettextcontrol_p_p.h b/src/widgets/widgets/qwidgettextcontrol_p_p.h
new file mode 100644
index 0000000000..7cc3026dec
--- /dev/null
+++ b/src/widgets/widgets/qwidgettextcontrol_p_p.h
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETTEXTCONTROL_P_P_H
+#define QWIDGETTEXTCONTROL_P_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/qtextdocumentfragment.h"
+#include "QtWidgets/qscrollbar.h"
+#include "QtGui/qtextcursor.h"
+#include "QtGui/qtextformat.h"
+#include "QtWidgets/qmenu.h"
+#include "QtGui/qabstracttextdocumentlayout.h"
+#include "QtCore/qbasictimer.h"
+#include "QtCore/qpointer.h"
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QMimeData;
+class QAbstractScrollArea;
+class QInputContext;
+
+class QWidgetTextControlPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QWidgetTextControl)
+public:
+ QWidgetTextControlPrivate();
+
+ bool cursorMoveKeyEvent(QKeyEvent *e);
+
+ void updateCurrentCharFormat();
+
+ void indent();
+ void outdent();
+
+ void gotoNextTableCell();
+ void gotoPreviousTableCell();
+
+ void createAutoBulletList();
+
+ void init(Qt::TextFormat format = Qt::RichText, const QString &text = QString(),
+ QTextDocument *document = 0);
+ void setContent(Qt::TextFormat format = Qt::RichText, const QString &text = QString(),
+ QTextDocument *document = 0);
+ void startDrag();
+
+ void paste(const QMimeData *source);
+
+ void setCursorPosition(const QPointF &pos);
+ void setCursorPosition(int pos, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+
+ void repaintCursor();
+ inline void repaintSelection()
+ { repaintOldAndNewSelection(QTextCursor()); }
+ void repaintOldAndNewSelection(const QTextCursor &oldSelection);
+
+ void selectionChanged(bool forceEmitSelectionChanged = false);
+
+ void _q_updateCurrentCharFormatAndSelection();
+
+#ifndef QT_NO_CLIPBOARD
+ void setClipboardSelection();
+#endif
+
+ void _q_emitCursorPosChanged(const QTextCursor &someCursor);
+
+ void setBlinkingCursorEnabled(bool enable);
+
+ void extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition);
+ void extendBlockwiseSelection(int suggestedNewPosition);
+
+ void _q_deleteSelected();
+
+ void _q_setCursorAfterUndoRedo(int undoPosition, int charsAdded, int charsRemoved);
+
+ QRectF cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const;
+ QRectF rectForPosition(int position) const;
+ QRectF selectionRect(const QTextCursor &cursor) const;
+ inline QRectF selectionRect() const
+ { return selectionRect(this->cursor); }
+
+ QString anchorForCursor(const QTextCursor &anchor) const;
+
+ void keyPressEvent(QKeyEvent *e);
+ void mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos,
+ Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons,
+ const QPoint &globalPos);
+ void mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos,
+ Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons,
+ const QPoint &globalPos);
+ void mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos,
+ Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons,
+ const QPoint &globalPos);
+ void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos,
+ Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons,
+ const QPoint &globalPos);
+ bool sendMouseEventToInputContext(QEvent *e, QEvent::Type eventType, Qt::MouseButton button,
+ const QPointF &pos,
+ Qt::KeyboardModifiers modifiers,
+ Qt::MouseButtons buttons,
+ const QPoint &globalPos);
+ void contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget);
+ void focusEvent(QFocusEvent *e);
+#ifdef QT_KEYPAD_NAVIGATION
+ void editFocusEvent(QEvent *e);
+#endif
+ bool dragEnterEvent(QEvent *e, const QMimeData *mimeData);
+ void dragLeaveEvent();
+ bool dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos);
+ bool dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QObject *source);
+
+ void inputMethodEvent(QInputMethodEvent *);
+
+ void activateLinkUnderCursor(QString href = QString());
+
+#ifndef QT_NO_TOOLTIP
+ void showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget);
+#endif
+
+ void append(const QString &text, Qt::TextFormat format = Qt::AutoText);
+
+ QInputContext *inputContext();
+
+ QTextDocument *doc;
+ bool cursorOn;
+ QTextCursor cursor;
+ bool cursorIsFocusIndicator;
+ QTextCharFormat lastCharFormat;
+
+ QTextCursor dndFeedbackCursor;
+
+ Qt::TextInteractionFlags interactionFlags;
+
+ QBasicTimer cursorBlinkTimer;
+ QBasicTimer trippleClickTimer;
+ QPointF trippleClickPoint;
+
+ bool dragEnabled;
+
+ bool mousePressed;
+
+ bool mightStartDrag;
+ QPoint dragStartPos;
+ QPointer<QWidget> contextWidget;
+
+ bool lastSelectionState;
+
+ bool ignoreAutomaticScrollbarAdjustement;
+
+ QTextCursor selectedWordOnDoubleClick;
+ QTextCursor selectedBlockOnTrippleClick;
+
+ bool overwriteMode;
+ bool acceptRichText;
+
+ int preeditCursor;
+ bool hideCursor; // used to hide the cursor in the preedit area
+
+ QVector<QAbstractTextDocumentLayout::Selection> extraSelections;
+
+ QPalette palette;
+ bool hasFocus;
+#ifdef QT_KEYPAD_NAVIGATION
+ bool hasEditFocus;
+#endif
+ bool isEnabled;
+
+ QString highlightedAnchor; // Anchor below cursor
+ QString anchorOnMousePress;
+ bool hadSelectionOnMousePress;
+
+ bool ignoreUnusedNavigationEvents;
+ bool openExternalLinks;
+
+ bool wordSelectionEnabled;
+
+ QString linkToCopy;
+ void _q_copyLink();
+ void _q_updateBlock(const QTextBlock &);
+ void _q_documentLayoutChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWidgetTextControl_P_H
diff --git a/src/widgets/widgets/qworkspace.cpp b/src/widgets/widgets/qworkspace.cpp
new file mode 100644
index 0000000000..9516bcaa7d
--- /dev/null
+++ b/src/widgets/widgets/qworkspace.cpp
@@ -0,0 +1,3376 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qworkspace.h"
+#ifndef QT_NO_WORKSPACE
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qcursor.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "qhash.h"
+#include "qicon.h"
+#include "qimage.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qmenubar.h"
+#include "qmenu.h"
+#include "qpainter.h"
+#include "qpointer.h"
+#include "qscrollbar.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qelapsedtimer.h"
+#include "qtooltip.h"
+#include "qdebug.h"
+#include <private/qwidget_p.h>
+#include <private/qwidgetresizehandler_p.h>
+#include <private/qlayoutengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWorkspaceTitleBarPrivate;
+
+
+/**************************************************************
+* QMDIControl
+*
+* Used for displaying MDI controls in a maximized MDI window
+*
+*/
+class QMDIControl : public QWidget
+{
+ Q_OBJECT
+signals:
+ void _q_minimize();
+ void _q_restore();
+ void _q_close();
+
+public:
+ QMDIControl(QWidget *widget);
+
+private:
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void leaveEvent(QEvent *event);
+ bool event(QEvent *event);
+ void initStyleOption(QStyleOptionComplex *option) const;
+ QStyle::SubControl activeControl; //control locked by pressing and holding the mouse
+ QStyle::SubControl hoverControl; //previously active hover control, used for tracking repaints
+};
+
+bool QMDIControl::event(QEvent *event)
+{
+ if (event->type() == QEvent::ToolTip) {
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+#ifndef QT_NO_TOOLTIP
+ QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
+ helpEvent->pos(), this);
+ if (ctrl == QStyle::SC_MdiCloseButton)
+ QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Close"), this);
+ else if (ctrl == QStyle::SC_MdiMinButton)
+ QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize"), this);
+ else if (ctrl == QStyle::SC_MdiNormalButton)
+ QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down"), this);
+ else
+ QToolTip::hideText();
+#endif // QT_NO_TOOLTIP
+ }
+ return QWidget::event(event);
+}
+
+void QMDIControl::initStyleOption(QStyleOptionComplex *option) const
+{
+ option->initFrom(this);
+ option->subControls = QStyle::SC_All;
+ option->activeSubControls = QStyle::SC_None;
+}
+
+QMDIControl::QMDIControl(QWidget *widget)
+ : QWidget(widget), activeControl(QStyle::SC_None),
+ hoverControl(QStyle::SC_None)
+{
+ setObjectName(QLatin1String("qt_maxcontrols"));
+ setFocusPolicy(Qt::NoFocus);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setMouseTracking(true);
+}
+
+QSize QMDIControl::sizeHint() const
+{
+ ensurePolished();
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ QSize size(48, 16);
+ return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, this);
+}
+
+void QMDIControl::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
+ event->pos(), this);
+ activeControl = ctrl;
+ update();
+}
+
+void QMDIControl::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ event->ignore();
+ return;
+ }
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
+ event->pos(), this);
+ if (under_mouse == activeControl) {
+ switch (activeControl) {
+ case QStyle::SC_MdiCloseButton:
+ emit _q_close();
+ break;
+ case QStyle::SC_MdiNormalButton:
+ emit _q_restore();
+ break;
+ case QStyle::SC_MdiMinButton:
+ emit _q_minimize();
+ break;
+ default:
+ break;
+ }
+ }
+ activeControl = QStyle::SC_None;
+ update();
+}
+
+void QMDIControl::leaveEvent(QEvent * /*event*/)
+{
+ hoverControl = QStyle::SC_None;
+ update();
+}
+
+void QMDIControl::mouseMoveEvent(QMouseEvent *event)
+{
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
+ event->pos(), this);
+ //test if hover state changes
+ if (hoverControl != under_mouse) {
+ hoverControl = under_mouse;
+ update();
+ }
+}
+
+void QMDIControl::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOptionComplex opt;
+ initStyleOption(&opt);
+ if (activeControl == hoverControl) {
+ opt.activeSubControls = activeControl;
+ opt.state |= QStyle::State_Sunken;
+ } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
+ opt.activeSubControls = hoverControl;
+ opt.state |= QStyle::State_MouseOver;
+ }
+ style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &p, this);
+}
+
+class QWorkspaceTitleBar : public QWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWorkspaceTitleBar)
+ Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise)
+ Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
+
+public:
+ QWorkspaceTitleBar (QWidget *w, QWidget *parent, Qt::WindowFlags f = 0);
+ ~QWorkspaceTitleBar();
+
+ bool isActive() const;
+ bool usesActiveColor() const;
+
+ bool isMovable() const;
+ void setMovable(bool);
+
+ bool autoRaise() const;
+ void setAutoRaise(bool);
+
+ QWidget *window() const;
+ bool isTool() const;
+
+ QSize sizeHint() const;
+ void initStyleOption(QStyleOptionTitleBar *option) const;
+
+public slots:
+ void setActive(bool);
+
+signals:
+ void doActivate();
+ void doNormal();
+ void doClose();
+ void doMaximize();
+ void doMinimize();
+ void doShade();
+ void showOperationMenu();
+ void popupOperationMenu(const QPoint&);
+ void doubleClicked();
+
+protected:
+ bool event(QEvent *);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *);
+#endif
+ void mousePressEvent(QMouseEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void enterEvent(QEvent *e);
+ void leaveEvent(QEvent *e);
+ void paintEvent(QPaintEvent *p);
+
+private:
+ Q_DISABLE_COPY(QWorkspaceTitleBar)
+};
+
+
+class QWorkspaceTitleBarPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QWorkspaceTitleBar)
+public:
+ QWorkspaceTitleBarPrivate()
+ :
+ lastControl(QStyle::SC_None),
+#ifndef QT_NO_TOOLTIP
+ toolTip(0),
+#endif
+ act(0), window(0), movable(1), pressed(0), autoraise(0), moving(0)
+ {
+ }
+
+ Qt::WindowFlags flags;
+ QStyle::SubControl buttonDown;
+ QStyle::SubControl lastControl;
+ QPoint moveOffset;
+#ifndef QT_NO_TOOLTIP
+ QToolTip *toolTip;
+#endif
+ bool act :1;
+ QPointer<QWidget> window;
+ bool movable :1;
+ bool pressed :1;
+ bool autoraise :1;
+ bool moving : 1;
+
+ int titleBarState() const;
+ void readColors();
+};
+
+inline int QWorkspaceTitleBarPrivate::titleBarState() const
+{
+ Q_Q(const QWorkspaceTitleBar);
+ uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
+ state |= uint((act && q->isActiveWindow()) ? QStyle::State_Active : QStyle::State_None);
+ return (int)state;
+}
+
+void QWorkspaceTitleBar::initStyleOption(QStyleOptionTitleBar *option) const
+{
+ Q_D(const QWorkspaceTitleBar);
+ option->initFrom(this);
+ //################
+ if (d->window && (d->flags & Qt::WindowTitleHint)) {
+ option->text = d->window->windowTitle();
+ QIcon icon = d->window->windowIcon();
+ QSize s = icon.actualSize(QSize(64, 64));
+ option->icon = icon.pixmap(s);
+ }
+ option->subControls = QStyle::SC_All;
+ option->activeSubControls = QStyle::SC_None;
+ option->titleBarState = d->titleBarState();
+ option->titleBarFlags = d->flags;
+ option->state &= ~QStyle::State_MouseOver;
+}
+
+QWorkspaceTitleBar::QWorkspaceTitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f)
+ : QWidget(*new QWorkspaceTitleBarPrivate, parent, Qt::FramelessWindowHint)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (f == 0 && w)
+ f = w->windowFlags();
+ d->flags = f;
+ d->window = w;
+ d->buttonDown = QStyle::SC_None;
+ d->act = 0;
+ if (w) {
+ if (w->maximumSize() != QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))
+ d->flags &= ~Qt::WindowMaximizeButtonHint;
+ setWindowTitle(w->windowTitle());
+ }
+
+ d->readColors();
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+ setMouseTracking(true);
+ setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this));
+}
+
+QWorkspaceTitleBar::~QWorkspaceTitleBar()
+{
+}
+
+
+#ifdef Q_WS_WIN
+static inline QRgb colorref2qrgb(COLORREF col)
+{
+ return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
+}
+#endif
+
+void QWorkspaceTitleBarPrivate::readColors()
+{
+ Q_Q(QWorkspaceTitleBar);
+ QPalette pal = q->palette();
+
+ bool colorsInitialized = false;
+
+#ifdef Q_WS_WIN // ask system properties on windows
+#ifndef SPI_GETGRADIENTCAPTIONS
+#define SPI_GETGRADIENTCAPTIONS 0x1008
+#endif
+#ifndef COLOR_GRADIENTACTIVECAPTION
+#define COLOR_GRADIENTACTIVECAPTION 27
+#endif
+#ifndef COLOR_GRADIENTINACTIVECAPTION
+#define COLOR_GRADIENTINACTIVECAPTION 28
+#endif
+ if (QApplication::desktopSettingsAware()) {
+ pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
+ pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
+ pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
+ pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
+
+ colorsInitialized = true;
+ BOOL gradient = false;
+ SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
+
+ if (gradient) {
+ pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
+ pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
+ } else {
+ pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight));
+ pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight));
+ }
+ }
+#endif // Q_WS_WIN
+ if (!colorsInitialized) {
+ pal.setColor(QPalette::Active, QPalette::Highlight,
+ pal.color(QPalette::Active, QPalette::Highlight));
+ pal.setColor(QPalette::Active, QPalette::Base,
+ pal.color(QPalette::Active, QPalette::Highlight));
+ pal.setColor(QPalette::Inactive, QPalette::Highlight,
+ pal.color(QPalette::Inactive, QPalette::Dark));
+ pal.setColor(QPalette::Inactive, QPalette::Base,
+ pal.color(QPalette::Inactive, QPalette::Dark));
+ pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ pal.color(QPalette::Inactive, QPalette::Window));
+ }
+
+ q->setPalette(pal);
+ q->setActive(act);
+}
+
+void QWorkspaceTitleBar::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (!d->act)
+ emit doActivate();
+ if (e->button() == Qt::LeftButton) {
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
+ && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
+ // propagate border events to the QWidgetResizeHandler
+ e->ignore();
+ return;
+ }
+
+ d->pressed = true;
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
+ e->pos(), this);
+ switch (ctrl) {
+ case QStyle::SC_TitleBarSysMenu:
+ if (d->flags & Qt::WindowSystemMenuHint) {
+ d->buttonDown = QStyle::SC_None;
+ static QElapsedTimer *t = 0;
+ static QWorkspaceTitleBar *tc = 0;
+ if (!t)
+ t = new QElapsedTimer;
+ if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
+ emit showOperationMenu();
+ t->start();
+ tc = this;
+ } else {
+ tc = 0;
+ emit doClose();
+ return;
+ }
+ }
+ break;
+
+ case QStyle::SC_TitleBarShadeButton:
+ case QStyle::SC_TitleBarUnshadeButton:
+ if (d->flags & Qt::WindowShadeButtonHint)
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarNormalButton:
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarMinButton:
+ if (d->flags & Qt::WindowMinimizeButtonHint)
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarMaxButton:
+ if (d->flags & Qt::WindowMaximizeButtonHint)
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarCloseButton:
+ if (d->flags & Qt::WindowSystemMenuHint)
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarLabel:
+ d->buttonDown = ctrl;
+ d->moveOffset = mapToParent(e->pos());
+ break;
+
+ default:
+ break;
+ }
+ update();
+ } else {
+ d->pressed = false;
+ }
+}
+
+#ifndef QT_NO_CONTEXTMENU
+void QWorkspaceTitleBar::contextMenuEvent(QContextMenuEvent *e)
+{
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(),
+ this);
+ if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) {
+ e->accept();
+ emit popupOperationMenu(e->globalPos());
+ } else {
+ e->ignore();
+ }
+}
+#endif // QT_NO_CONTEXTMENU
+
+void QWorkspaceTitleBar::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (!d->window) {
+ // could have been deleted as part of a double click event on the sysmenu
+ return;
+ }
+ if (e->button() == Qt::LeftButton && d->pressed) {
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
+ && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
+ // propagate border events to the QWidgetResizeHandler
+ e->ignore();
+ d->buttonDown = QStyle::SC_None;
+ d->pressed = false;
+ return;
+ }
+ e->accept();
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
+ e->pos(), this);
+
+ if (d->pressed) {
+ update();
+ d->pressed = false;
+ d->moving = false;
+ }
+ if (ctrl == d->buttonDown) {
+ d->buttonDown = QStyle::SC_None;
+ switch(ctrl) {
+ case QStyle::SC_TitleBarShadeButton:
+ case QStyle::SC_TitleBarUnshadeButton:
+ if(d->flags & Qt::WindowShadeButtonHint)
+ emit doShade();
+ break;
+
+ case QStyle::SC_TitleBarNormalButton:
+ if(d->flags & Qt::WindowMinMaxButtonsHint)
+ emit doNormal();
+ break;
+
+ case QStyle::SC_TitleBarMinButton:
+ if(d->flags & Qt::WindowMinimizeButtonHint) {
+ if (d->window && d->window->isMinimized())
+ emit doNormal();
+ else
+ emit doMinimize();
+ }
+ break;
+
+ case QStyle::SC_TitleBarMaxButton:
+ if(d->flags & Qt::WindowMaximizeButtonHint) {
+ if(d->window && d->window->isMaximized())
+ emit doNormal();
+ else
+ emit doMaximize();
+ }
+ break;
+
+ case QStyle::SC_TitleBarCloseButton:
+ if(d->flags & Qt::WindowSystemMenuHint) {
+ d->buttonDown = QStyle::SC_None;
+ emit doClose();
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else {
+ e->ignore();
+ }
+}
+
+void QWorkspaceTitleBar::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QWorkspaceTitleBar);
+ e->ignore();
+ if ((e->buttons() & Qt::LeftButton) && style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
+ && !rect().adjusted(5, 5, -5, 0).contains(e->pos()) && !d->pressed) {
+ // propagate border events to the QWidgetResizeHandler
+ return;
+ }
+
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
+ e->pos(), this);
+ if(under_mouse != d->lastControl) {
+ d->lastControl = under_mouse;
+ update();
+ }
+
+ switch (d->buttonDown) {
+ case QStyle::SC_None:
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ break;
+ case QStyle::SC_TitleBarLabel:
+ if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) {
+ if (d->moving || (d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) {
+ d->moving = true;
+ QPoint p = mapFromGlobal(e->globalPos());
+
+ QWidget *parent = d->window ? d->window->parentWidget() : 0;
+ if(parent && parent->inherits("QWorkspaceChild")) {
+ QWidget *workspace = parent->parentWidget();
+ p = workspace->mapFromGlobal(e->globalPos());
+ if (!workspace->rect().contains(p)) {
+ if (p.x() < 0)
+ p.rx() = 0;
+ if (p.y() < 0)
+ p.ry() = 0;
+ if (p.x() > workspace->width())
+ p.rx() = workspace->width();
+ if (p.y() > workspace->height())
+ p.ry() = workspace->height();
+ }
+ }
+
+ QPoint pp = p - d->moveOffset;
+ if (!parentWidget()->isMaximized())
+ parentWidget()->move(pp);
+ }
+ }
+ e->accept();
+ break;
+ default:
+ break;
+ }
+}
+
+bool QWorkspaceTitleBar::isTool() const
+{
+ Q_D(const QWorkspaceTitleBar);
+ return (d->flags & Qt::WindowType_Mask) == Qt::Tool;
+}
+
+// from qwidget.cpp
+extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
+
+void QWorkspaceTitleBar::paintEvent(QPaintEvent *)
+{
+ Q_D(QWorkspaceTitleBar);
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ opt.subControls = QStyle::SC_TitleBarLabel;
+ opt.activeSubControls = d->buttonDown;
+
+ if (d->window && (d->flags & Qt::WindowTitleHint)) {
+ QString title = qt_setWindowTitle_helperHelper(opt.text, d->window);
+ int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel,
+ this).width();
+ opt.text = fontMetrics().elidedText(title, Qt::ElideRight, maxw);
+ }
+
+ if (d->flags & Qt::WindowSystemMenuHint) {
+ opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
+ if (d->window && (d->flags & Qt::WindowShadeButtonHint)) {
+ if (d->window->isMinimized())
+ opt.subControls |= QStyle::SC_TitleBarUnshadeButton;
+ else
+ opt.subControls |= QStyle::SC_TitleBarShadeButton;
+ }
+ if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) {
+ if(d->window && d->window->isMinimized())
+ opt.subControls |= QStyle::SC_TitleBarNormalButton;
+ else
+ opt.subControls |= QStyle::SC_TitleBarMinButton;
+ }
+ if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized())
+ opt.subControls |= QStyle::SC_TitleBarMaxButton;
+ }
+
+ QStyle::SubControl under_mouse = QStyle::SC_None;
+ under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
+ mapFromGlobal(QCursor::pos()), this);
+ if ((d->buttonDown == under_mouse) && d->pressed) {
+ opt.state |= QStyle::State_Sunken;
+ } else if( autoRaise() && under_mouse != QStyle::SC_None && !d->pressed) {
+ opt.activeSubControls = under_mouse;
+ opt.state |= QStyle::State_MouseOver;
+ }
+ opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive);
+
+ QPainter p(this);
+ style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this);
+}
+
+void QWorkspaceTitleBar::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (e->button() != Qt::LeftButton) {
+ e->ignore();
+ return;
+ }
+ e->accept();
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) {
+ case QStyle::SC_TitleBarLabel:
+ emit doubleClicked();
+ break;
+
+ case QStyle::SC_TitleBarSysMenu:
+ if (d->flags & Qt::WindowSystemMenuHint)
+ emit doClose();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void QWorkspaceTitleBar::leaveEvent(QEvent *)
+{
+ Q_D(QWorkspaceTitleBar);
+ d->lastControl = QStyle::SC_None;
+ if(autoRaise() && !d->pressed)
+ update();
+}
+
+void QWorkspaceTitleBar::enterEvent(QEvent *)
+{
+ Q_D(QWorkspaceTitleBar);
+ if(autoRaise() && !d->pressed)
+ update();
+ QEvent e(QEvent::Leave);
+ QApplication::sendEvent(parentWidget(), &e);
+}
+
+void QWorkspaceTitleBar::setActive(bool active)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (d->act == active)
+ return ;
+
+ d->act = active;
+ update();
+}
+
+bool QWorkspaceTitleBar::isActive() const
+{
+ Q_D(const QWorkspaceTitleBar);
+ return d->act;
+}
+
+bool QWorkspaceTitleBar::usesActiveColor() const
+{
+ return (isActive() && isActiveWindow()) ||
+ (!window() && QWidget::window()->isActiveWindow());
+}
+
+QWidget *QWorkspaceTitleBar::window() const
+{
+ Q_D(const QWorkspaceTitleBar);
+ return d->window;
+}
+
+bool QWorkspaceTitleBar::event(QEvent *e)
+{
+ Q_D(QWorkspaceTitleBar);
+ if (e->type() == QEvent::ApplicationPaletteChange) {
+ d->readColors();
+ } else if (e->type() == QEvent::WindowActivate
+ || e->type() == QEvent::WindowDeactivate) {
+ if (d->act)
+ update();
+ }
+ return QWidget::event(e);
+}
+
+void QWorkspaceTitleBar::setMovable(bool b)
+{
+ Q_D(QWorkspaceTitleBar);
+ d->movable = b;
+}
+
+bool QWorkspaceTitleBar::isMovable() const
+{
+ Q_D(const QWorkspaceTitleBar);
+ return d->movable;
+}
+
+void QWorkspaceTitleBar::setAutoRaise(bool b)
+{
+ Q_D(QWorkspaceTitleBar);
+ d->autoraise = b;
+}
+
+bool QWorkspaceTitleBar::autoRaise() const
+{
+ Q_D(const QWorkspaceTitleBar);
+ return d->autoraise;
+}
+
+QSize QWorkspaceTitleBar::sizeHint() const
+{
+ ensurePolished();
+ QStyleOptionTitleBar opt;
+ initStyleOption(&opt);
+ QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt,
+ QStyle::SC_TitleBarSysMenu, this);
+ return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
+}
+
+/*!
+ \class QWorkspace
+ \obsolete
+ \brief The QWorkspace widget provides a workspace window that can be
+ used in an MDI application.
+
+ This class is deprecated. Use QMdiArea instead.
+
+ Multiple Document Interface (MDI) applications are typically
+ composed of a main window containing a menu bar, a toolbar, and
+ a central QWorkspace widget. The workspace itself is used to display
+ a number of child windows, each of which is a widget.
+
+ The workspace itself is an ordinary Qt widget. It has a standard
+ constructor that takes a parent widget.
+ Workspaces can be placed in any layout, but are typically given
+ as the central widget in a QMainWindow:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qworkspace.cpp 0
+
+ Child windows (MDI windows) are standard Qt widgets that are
+ inserted into the workspace with addWindow(). As with top-level
+ widgets, you can call functions such as show(), hide(),
+ showMaximized(), and setWindowTitle() on a child window to change
+ its appearance within the workspace. You can also provide widget
+ flags to determine the layout of the decoration or the behavior of
+ the widget itself.
+
+ To change or retrieve the geometry of a child window, you must
+ operate on its parentWidget(). The parentWidget() provides
+ access to the decorated frame that contains the child window
+ widget. When a child window is maximised, its decorated frame
+ is hidden. If the top-level widget contains a menu bar, it will display
+ the maximised window's operations menu to the left of the menu
+ entries, and the window's controls to the right.
+
+ A child window becomes active when it gets the keyboard focus,
+ or when setFocus() is called. The user can activate a window by moving
+ focus in the usual ways, for example by clicking a window or by pressing
+ Tab. The workspace emits a signal windowActivated() when the active
+ window changes, and the function activeWindow() returns a pointer to the
+ active child window, or 0 if no window is active.
+
+ The convenience function windowList() returns a list of all child
+ windows. This information could be used in a popup menu
+ containing a list of windows, for example. This feature is also
+ available as part of the \l{Window Menu} Solution.
+
+ QWorkspace provides two built-in layout strategies for child
+ windows: cascade() and tile(). Both are slots so you can easily
+ connect menu entries to them.
+
+ \table
+ \row \o \inlineimage mdi-cascade.png
+ \o \inlineimage mdi-tile.png
+ \endtable
+
+ If you want your users to be able to work with child windows
+ larger than the visible workspace area, set the scrollBarsEnabled
+ property to true.
+
+ \sa QDockWidget, {MDI Example}
+*/
+
+
+class QWorkspaceChild : public QWidget
+{
+ Q_OBJECT
+
+ friend class QWorkspacePrivate;
+ friend class QWorkspace;
+ friend class QWorkspaceTitleBar;
+
+public:
+ QWorkspaceChild(QWidget* window, QWorkspace* parent=0, Qt::WindowFlags flags = 0);
+ ~QWorkspaceChild();
+
+ void setActive(bool);
+ bool isActive() const;
+
+ void adjustToFullscreen();
+
+ QWidget* windowWidget() const;
+ QWidget* iconWidget() const;
+
+ void doResize();
+ void doMove();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QSize baseSize() const;
+
+ int frameWidth() const;
+
+ void show();
+
+ bool isWindowOrIconVisible() const;
+
+signals:
+ void showOperationMenu();
+ void popupOperationMenu(const QPoint&);
+
+public slots:
+ void activate();
+ void showMinimized();
+ void showMaximized();
+ void showNormal();
+ void showShaded();
+ void internalRaise();
+ void titleBarDoubleClicked();
+
+protected:
+ void enterEvent(QEvent *);
+ void leaveEvent(QEvent *);
+ void childEvent(QChildEvent*);
+ void resizeEvent(QResizeEvent *);
+ void moveEvent(QMoveEvent *);
+ bool eventFilter(QObject *, QEvent *);
+
+ void paintEvent(QPaintEvent *);
+ void changeEvent(QEvent *);
+
+private:
+ void updateMask();
+
+ Q_DISABLE_COPY(QWorkspaceChild)
+
+ QWidget *childWidget;
+ QWidgetResizeHandler *widgetResizeHandler;
+ QWorkspaceTitleBar *titlebar;
+ QPointer<QWorkspaceTitleBar> iconw;
+ QSize windowSize;
+ QSize shadeRestore;
+ QSize shadeRestoreMin;
+ bool act :1;
+ bool shademode :1;
+};
+
+int QWorkspaceChild::frameWidth() const
+{
+ return contentsRect().left();
+}
+
+
+
+class QWorkspacePrivate : public QWidgetPrivate {
+ Q_DECLARE_PUBLIC(QWorkspace)
+public:
+ QWorkspaceChild* active;
+ QList<QWorkspaceChild *> windows;
+ QList<QWorkspaceChild *> focus;
+ QList<QWidget *> icons;
+ QWorkspaceChild* maxWindow;
+ QRect maxRestore;
+ QPointer<QMDIControl> maxcontrols;
+ QPointer<QMenuBar> maxmenubar;
+ QHash<int, const char*> shortcutMap;
+
+ int px;
+ int py;
+ QWidget *becomeActive;
+ QPointer<QLabel> maxtools;
+ QString topTitle;
+
+ QMenu *popup, *toolPopup;
+ enum WSActs { RestoreAct, MoveAct, ResizeAct, MinimizeAct, MaximizeAct, CloseAct, StaysOnTopAct, ShadeAct, NCountAct };
+ QAction *actions[NCountAct];
+
+ QScrollBar *vbar, *hbar;
+ QWidget *corner;
+ int yoffset, xoffset;
+ QBrush background;
+
+ void init();
+ void insertIcon(QWidget* w);
+ void removeIcon(QWidget* w);
+ void place(QWidget*);
+
+ QWorkspaceChild* findChild(QWidget* w);
+ void showMaximizeControls();
+ void hideMaximizeControls();
+ void activateWindow(QWidget* w, bool change_focus = true);
+ void hideChild(QWorkspaceChild *c);
+ void showWindow(QWidget* w);
+ void maximizeWindow(QWidget* w);
+ void minimizeWindow(QWidget* w);
+ void normalizeWindow(QWidget* w);
+
+ QRect updateWorkspace();
+
+private:
+ void _q_normalizeActiveWindow();
+ void _q_minimizeActiveWindow();
+ void _q_showOperationMenu();
+ void _q_popupOperationMenu(const QPoint&);
+ void _q_operationMenuActivated(QAction *);
+ void _q_scrollBarChanged();
+ void _q_updateActions();
+ bool inTitleChange;
+};
+
+static bool isChildOf(QWidget * child, QWidget * parent)
+{
+ if (!parent || !child)
+ return false;
+ QWidget * w = child;
+ while(w && w != parent)
+ w = w->parentWidget();
+ return w != 0;
+}
+
+/*!
+ Constructs a workspace with the given \a parent.
+*/
+QWorkspace::QWorkspace(QWidget *parent)
+ : QWidget(*new QWorkspacePrivate, parent, 0)
+{
+ Q_D(QWorkspace);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QWorkspace::QWorkspace(QWidget *parent, const char *name)
+ : QWidget(*new QWorkspacePrivate, parent, 0)
+{
+ Q_D(QWorkspace);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+#endif // QT3_SUPPORT
+
+/*!
+ \internal
+*/
+void
+QWorkspacePrivate::init()
+{
+ Q_Q(QWorkspace);
+
+ maxcontrols = 0;
+ active = 0;
+ maxWindow = 0;
+ maxtools = 0;
+ px = 0;
+ py = 0;
+ becomeActive = 0;
+ popup = new QMenu(q);
+ toolPopup = new QMenu(q);
+ popup->setObjectName(QLatin1String("qt_internal_mdi_popup"));
+ toolPopup->setObjectName(QLatin1String("qt_internal_mdi_tool_popup"));
+
+ actions[QWorkspacePrivate::RestoreAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, q)),
+ QWorkspace::tr("&Restore"), q);
+ actions[QWorkspacePrivate::MoveAct] = new QAction(QWorkspace::tr("&Move"), q);
+ actions[QWorkspacePrivate::ResizeAct] = new QAction(QWorkspace::tr("&Size"), q);
+ actions[QWorkspacePrivate::MinimizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMinButton, 0, q)),
+ QWorkspace::tr("Mi&nimize"), q);
+ actions[QWorkspacePrivate::MaximizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, q)),
+ QWorkspace::tr("Ma&ximize"), q);
+ actions[QWorkspacePrivate::CloseAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, q)),
+ QWorkspace::tr("&Close")
+#ifndef QT_NO_SHORTCUT
+ +QLatin1Char('\t')+(QString)QKeySequence(Qt::CTRL+Qt::Key_F4)
+#endif
+ ,q);
+ QObject::connect(actions[QWorkspacePrivate::CloseAct], SIGNAL(triggered()), q, SLOT(closeActiveWindow()));
+ actions[QWorkspacePrivate::StaysOnTopAct] = new QAction(QWorkspace::tr("Stay on &Top"), q);
+ actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(true);
+ actions[QWorkspacePrivate::ShadeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)),
+ QWorkspace::tr("Sh&ade"), q);
+
+ QObject::connect(popup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
+ QObject::connect(popup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
+ popup->addAction(actions[QWorkspacePrivate::RestoreAct]);
+ popup->addAction(actions[QWorkspacePrivate::MoveAct]);
+ popup->addAction(actions[QWorkspacePrivate::ResizeAct]);
+ popup->addAction(actions[QWorkspacePrivate::MinimizeAct]);
+ popup->addAction(actions[QWorkspacePrivate::MaximizeAct]);
+ popup->addSeparator();
+ popup->addAction(actions[QWorkspacePrivate::CloseAct]);
+
+ QObject::connect(toolPopup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
+ QObject::connect(toolPopup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
+ toolPopup->addAction(actions[QWorkspacePrivate::MoveAct]);
+ toolPopup->addAction(actions[QWorkspacePrivate::ResizeAct]);
+ toolPopup->addAction(actions[QWorkspacePrivate::StaysOnTopAct]);
+ toolPopup->addSeparator();
+ toolPopup->addAction(actions[QWorkspacePrivate::ShadeAct]);
+ toolPopup->addAction(actions[QWorkspacePrivate::CloseAct]);
+
+#ifndef QT_NO_SHORTCUT
+ // Set up shortcut bindings (id -> slot), most used first
+ QList <QKeySequence> shortcuts = QKeySequence::keyBindings(QKeySequence::NextChild);
+ foreach (const QKeySequence &seq, shortcuts)
+ shortcutMap.insert(q->grabShortcut(seq), "activateNextWindow");
+
+ shortcuts = QKeySequence::keyBindings(QKeySequence::PreviousChild);
+ foreach (const QKeySequence &seq, shortcuts)
+ shortcutMap.insert(q->grabShortcut(seq), "activatePreviousWindow");
+
+ shortcuts = QKeySequence::keyBindings(QKeySequence::Close);
+ foreach (const QKeySequence &seq, shortcuts)
+ shortcutMap.insert(q->grabShortcut(seq), "closeActiveWindow");
+
+ shortcutMap.insert(q->grabShortcut(QKeySequence(QLatin1String("ALT+-"))), "_q_showOperationMenu");
+#endif // QT_NO_SHORTCUT
+
+ q->setBackgroundRole(QPalette::Dark);
+ q->setAutoFillBackground(true);
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ hbar = vbar = 0;
+ corner = 0;
+ xoffset = yoffset = 0;
+
+ q->window()->installEventFilter(q);
+
+ inTitleChange = false;
+ updateWorkspace();
+}
+
+/*!
+ Destroys the workspace and frees any allocated resources.
+*/
+
+QWorkspace::~QWorkspace()
+{
+}
+
+/*! \reimp */
+QSize QWorkspace::sizeHint() const
+{
+ QSize s(QApplication::desktop()->size());
+ return QSize(s.width()*2/3, s.height()*2/3);
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Sets the background color to \a c.
+ Use setBackground() instead.
+*/
+void QWorkspace::setPaletteBackgroundColor(const QColor & c)
+{
+ setBackground(c);
+}
+
+/*!
+ Sets the background pixmap to \a pm.
+ Use setBackground() instead.
+*/
+void QWorkspace::setPaletteBackgroundPixmap(const QPixmap & pm)
+{
+ setBackground(pm);
+}
+#endif // QT3_SUPPORT
+
+/*!
+ \property QWorkspace::background
+ \brief the workspace's background
+*/
+QBrush QWorkspace::background() const
+{
+ Q_D(const QWorkspace);
+ if (d->background.style() == Qt::NoBrush)
+ return palette().dark();
+ return d->background;
+}
+
+void QWorkspace::setBackground(const QBrush &background)
+{
+ Q_D(QWorkspace);
+ d->background = background;
+ setAttribute(Qt::WA_OpaquePaintEvent, background.style() == Qt::NoBrush);
+ update();
+}
+
+/*!
+ Adds widget \a w as new sub window to the workspace. If \a flags
+ are non-zero, they will override the flags set on the widget.
+
+ Returns the widget used for the window frame.
+
+ To remove the widget \a w from the workspace, simply call
+ setParent() with the new parent (or 0 to make it a stand-alone
+ window).
+*/
+QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags)
+{
+ Q_D(QWorkspace);
+ if (!w)
+ return 0;
+
+ w->setAutoFillBackground(true);
+
+ QWidgetPrivate::adjustFlags(flags);
+
+#if 0
+ bool wasMaximized = w->isMaximized();
+ bool wasMinimized = w->isMinimized();
+#endif
+ bool hasSize = w->testAttribute(Qt::WA_Resized);
+ int x = w->x();
+ int y = w->y();
+ bool hasPos = w->testAttribute(Qt::WA_Moved);
+ if (!hasSize && w->sizeHint().isValid())
+ w->adjustSize();
+
+ QWorkspaceChild* child = new QWorkspaceChild(w, this, flags);
+ child->setObjectName(QLatin1String("qt_workspacechild"));
+ child->installEventFilter(this);
+
+ connect(child, SIGNAL(popupOperationMenu(QPoint)),
+ this, SLOT(_q_popupOperationMenu(QPoint)));
+ connect(child, SIGNAL(showOperationMenu()),
+ this, SLOT(_q_showOperationMenu()));
+ d->windows.append(child);
+ if (child->isVisibleTo(this))
+ d->focus.append(child);
+ child->internalRaise();
+
+ if (!hasPos)
+ d->place(child);
+ if (!hasSize)
+ child->adjustSize();
+ if (hasPos)
+ child->move(x, y);
+
+ return child;
+
+#if 0
+ if (wasMaximized)
+ w->showMaximized();
+ else if (wasMinimized)
+ w->showMinimized();
+ else if (!hasBeenHidden)
+ d->activateWindow(w);
+
+ d->updateWorkspace();
+ return child;
+#endif
+}
+
+/*! \reimp */
+void QWorkspace::childEvent(QChildEvent * e)
+{
+ Q_D(QWorkspace);
+ if (e->removed()) {
+ if (d->windows.removeAll(static_cast<QWorkspaceChild*>(e->child()))) {
+ d->focus.removeAll(static_cast<QWorkspaceChild*>(e->child()));
+ if (d->maxWindow == e->child())
+ d->maxWindow = 0;
+ d->updateWorkspace();
+ }
+ }
+}
+
+/*! \reimp */
+#ifndef QT_NO_WHEELEVENT
+void QWorkspace::wheelEvent(QWheelEvent *e)
+{
+ Q_D(QWorkspace);
+ if (!scrollBarsEnabled())
+ return;
+ // the scroll bars are children of the workspace, so if we receive
+ // a wheel event we redirect to the scroll bars using a direct event
+ // call, /not/ using sendEvent() because if the scroll bar ignores the
+ // event QApplication::sendEvent() will propagate the event to the parent widget,
+ // which is us, who /just/ sent it.
+ if (d->vbar && d->vbar->isVisible() && !(e->modifiers() & Qt::AltModifier))
+ d->vbar->event(e);
+ else if (d->hbar && d->hbar->isVisible())
+ d->hbar->event(e);
+}
+#endif
+
+void QWorkspacePrivate::activateWindow(QWidget* w, bool change_focus)
+{
+ Q_Q(QWorkspace);
+ if (!w) {
+ active = 0;
+ emit q->windowActivated(0);
+ return;
+ }
+ if (!q->isVisible()) {
+ becomeActive = w;
+ return;
+ }
+
+ if (active && active->windowWidget() == w) {
+ if (!isChildOf(q->focusWidget(), w)) // child window does not have focus
+ active->setActive(true);
+ return;
+ }
+
+ active = 0;
+ // First deactivate all other workspace clients
+ QList<QWorkspaceChild *>::Iterator it(windows.begin());
+ while (it != windows.end()) {
+ QWorkspaceChild* c = *it;
+ ++it;
+ if (c->windowWidget() == w)
+ active = c;
+ else
+ c->setActive(false);
+ }
+
+ if (!active)
+ return;
+
+ // Then activate the new one, so the focus is stored correctly
+ active->setActive(true);
+
+ if (!active)
+ return;
+
+ if (maxWindow && maxWindow != active && active->windowWidget() &&
+ (active->windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
+ active->showMaximized();
+
+ active->internalRaise();
+
+ if (change_focus) {
+ int from = focus.indexOf(active);
+ if (from >= 0)
+ focus.move(from, focus.size() - 1);
+ }
+
+ updateWorkspace();
+ emit q->windowActivated(w);
+}
+
+
+/*!
+ Returns a pointer to the widget corresponding to the active child
+ window, or 0 if no window is active.
+
+ \sa setActiveWindow()
+*/
+QWidget* QWorkspace::activeWindow() const
+{
+ Q_D(const QWorkspace);
+ return d->active? d->active->windowWidget() : 0;
+}
+
+/*!
+ Makes the child window that contains \a w the active child window.
+
+ \sa activeWindow()
+*/
+void QWorkspace::setActiveWindow(QWidget *w)
+{
+ Q_D(QWorkspace);
+ d->activateWindow(w, true);
+ if (w && w->isMinimized())
+ w->setWindowState(w->windowState() & ~Qt::WindowMinimized);
+}
+
+void QWorkspacePrivate::place(QWidget *w)
+{
+ Q_Q(QWorkspace);
+
+ QList<QWidget *> widgets;
+ for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it)
+ if (*it != w)
+ widgets.append(*it);
+
+ int overlap, minOverlap = 0;
+ int possible;
+
+ QRect r1(0, 0, 0, 0);
+ QRect r2(0, 0, 0, 0);
+ QRect maxRect = q->rect();
+ int x = maxRect.left(), y = maxRect.top();
+ QPoint wpos(maxRect.left(), maxRect.top());
+
+ bool firstPass = true;
+
+ do {
+ if (y + w->height() > maxRect.bottom()) {
+ overlap = -1;
+ } else if(x + w->width() > maxRect.right()) {
+ overlap = -2;
+ } else {
+ overlap = 0;
+
+ r1.setRect(x, y, w->width(), w->height());
+
+ QWidget *l;
+ QList<QWidget *>::Iterator it(widgets.begin());
+ while (it != widgets.end()) {
+ l = *it;
+ ++it;
+
+ if (maxWindow == l)
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
+ else
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
+ QRect(l->x(), l->y(), l->width(), l->height()));
+
+ if (r2.intersects(r1)) {
+ r2.setCoords(qMax(r1.left(), r2.left()),
+ qMax(r1.top(), r2.top()),
+ qMin(r1.right(), r2.right()),
+ qMin(r1.bottom(), r2.bottom())
+ );
+
+ overlap += (r2.right() - r2.left()) *
+ (r2.bottom() - r2.top());
+ }
+ }
+ }
+
+ if (overlap == 0) {
+ wpos = QPoint(x, y);
+ break;
+ }
+
+ if (firstPass) {
+ firstPass = false;
+ minOverlap = overlap;
+ } else if (overlap >= 0 && overlap < minOverlap) {
+ minOverlap = overlap;
+ wpos = QPoint(x, y);
+ }
+
+ if (overlap > 0) {
+ possible = maxRect.right();
+ if (possible - w->width() > x) possible -= w->width();
+
+ QWidget *l;
+ QList<QWidget *>::Iterator it(widgets.begin());
+ while (it != widgets.end()) {
+ l = *it;
+ ++it;
+ if (maxWindow == l)
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
+ else
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
+ QRect(l->x(), l->y(), l->width(), l->height()));
+
+ if((y < r2.bottom()) && (r2.top() < w->height() + y)) {
+ if(r2.right() > x)
+ possible = possible < r2.right() ?
+ possible : r2.right();
+
+ if(r2.left() - w->width() > x)
+ possible = possible < r2.left() - w->width() ?
+ possible : r2.left() - w->width();
+ }
+ }
+
+ x = possible;
+ } else if (overlap == -2) {
+ x = maxRect.left();
+ possible = maxRect.bottom();
+
+ if (possible - w->height() > y) possible -= w->height();
+
+ QWidget *l;
+ QList<QWidget *>::Iterator it(widgets.begin());
+ while (it != widgets.end()) {
+ l = *it;
+ ++it;
+ if (maxWindow == l)
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
+ else
+ r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
+ QRect(l->x(), l->y(), l->width(), l->height()));
+
+ if(r2.bottom() > y)
+ possible = possible < r2.bottom() ?
+ possible : r2.bottom();
+
+ if(r2.top() - w->height() > y)
+ possible = possible < r2.top() - w->height() ?
+ possible : r2.top() - w->height();
+ }
+
+ y = possible;
+ }
+ }
+ while(overlap != 0 && overlap != -1);
+
+ QRect resultRect = w->geometry();
+ resultRect.moveTo(wpos);
+ w->setGeometry(QStyle::visualRect(q->layoutDirection(), maxRect, resultRect));
+ updateWorkspace();
+}
+
+
+void QWorkspacePrivate::insertIcon(QWidget* w)
+{
+ Q_Q(QWorkspace);
+ if (!w || icons.contains(w))
+ return;
+ icons.append(w);
+ if (w->parentWidget() != q) {
+ w->setParent(q, 0);
+ w->move(0,0);
+ }
+ QRect cr = updateWorkspace();
+ int x = 0;
+ int y = cr.height() - w->height();
+
+ QList<QWidget *>::Iterator it(icons.begin());
+ while (it != icons.end()) {
+ QWidget* i = *it;
+ ++it;
+ if (x > 0 && x + i->width() > cr.width()){
+ x = 0;
+ y -= i->height();
+ }
+
+ if (i != w &&
+ i->geometry().intersects(QRect(x, y, w->width(), w->height())))
+ x += i->width();
+ }
+ w->move(x, y);
+
+ if (q->isVisibleTo(q->parentWidget())) {
+ w->show();
+ w->lower();
+ }
+ updateWorkspace();
+}
+
+
+void QWorkspacePrivate::removeIcon(QWidget* w)
+{
+ if (icons.removeAll(w))
+ w->hide();
+}
+
+
+/*! \reimp */
+void QWorkspace::resizeEvent(QResizeEvent *)
+{
+ Q_D(QWorkspace);
+ if (d->maxWindow) {
+ d->maxWindow->adjustToFullscreen();
+ if (d->maxWindow->windowWidget())
+ d->maxWindow->windowWidget()->overrideWindowState(Qt::WindowMaximized);
+ }
+ d->updateWorkspace();
+}
+
+/*! \reimp */
+void QWorkspace::showEvent(QShowEvent *e)
+{
+ Q_D(QWorkspace);
+ if (d->maxWindow)
+ d->showMaximizeControls();
+ QWidget::showEvent(e);
+ if (d->becomeActive) {
+ d->activateWindow(d->becomeActive);
+ d->becomeActive = 0;
+ } else if (d->windows.count() > 0 && !d->active) {
+ d->activateWindow(d->windows.first()->windowWidget());
+ }
+
+// // force a frame repaint - this is a workaround for what seems to be a bug
+// // introduced when changing the QWidget::show() implementation. Might be
+// // a windows bug as well though.
+// for (int i = 0; i < d->windows.count(); ++i) {
+// QWorkspaceChild* c = d->windows.at(i);
+// c->update(c->rect());
+// }
+
+ d->updateWorkspace();
+}
+
+/*! \reimp */
+void QWorkspace::hideEvent(QHideEvent *)
+{
+ Q_D(QWorkspace);
+ if (!isVisible())
+ d->hideMaximizeControls();
+}
+
+/*! \reimp */
+void QWorkspace::paintEvent(QPaintEvent *)
+{
+ Q_D(QWorkspace);
+
+ if (d->background.style() != Qt::NoBrush) {
+ QPainter p(this);
+ p.fillRect(0, 0, width(), height(), d->background);
+ }
+}
+
+void QWorkspacePrivate::minimizeWindow(QWidget* w)
+{
+ QWorkspaceChild* c = findChild(w);
+
+ if (!w || !(w->windowFlags() & Qt::WindowMinimizeButtonHint))
+ return;
+
+ if (c) {
+ bool wasMax = false;
+ if (c == maxWindow) {
+ wasMax = true;
+ maxWindow = 0;
+ hideMaximizeControls();
+ for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
+ QWorkspaceChild* c = *it;
+ if (c->titlebar)
+ c->titlebar->setMovable(true);
+ c->widgetResizeHandler->setActive(true);
+ }
+ }
+ c->hide();
+ if (wasMax)
+ c->setGeometry(maxRestore);
+ if (!focus.contains(c))
+ focus.append(c);
+ insertIcon(c->iconWidget());
+
+ if (!maxWindow)
+ activateWindow(w);
+
+ updateWorkspace();
+
+ w->overrideWindowState(Qt::WindowMinimized);
+ c->overrideWindowState(Qt::WindowMinimized);
+ }
+}
+
+void QWorkspacePrivate::normalizeWindow(QWidget* w)
+{
+ Q_Q(QWorkspace);
+ QWorkspaceChild* c = findChild(w);
+ if (!w)
+ return;
+ if (c) {
+ w->overrideWindowState(Qt::WindowNoState);
+ hideMaximizeControls();
+ if (!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q) || !maxWindow) {
+ if (w->minimumSize() != w->maximumSize())
+ c->widgetResizeHandler->setActive(true);
+ if (c->titlebar)
+ c->titlebar->setMovable(true);
+ }
+ w->overrideWindowState(Qt::WindowNoState);
+ c->overrideWindowState(Qt::WindowNoState);
+
+ if (c == maxWindow) {
+ c->setGeometry(maxRestore);
+ maxWindow = 0;
+ } else {
+ if (c->iconw)
+ removeIcon(c->iconw->parentWidget());
+ c->show();
+ }
+
+ hideMaximizeControls();
+ for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
+ QWorkspaceChild* c = *it;
+ if (c->titlebar)
+ c->titlebar->setMovable(true);
+ if (c->childWidget && c->childWidget->minimumSize() != c->childWidget->maximumSize())
+ c->widgetResizeHandler->setActive(true);
+ }
+ activateWindow(w, true);
+ updateWorkspace();
+ }
+}
+
+void QWorkspacePrivate::maximizeWindow(QWidget* w)
+{
+ Q_Q(QWorkspace);
+ QWorkspaceChild* c = findChild(w);
+
+ if (!w || !(w->windowFlags() & Qt::WindowMaximizeButtonHint))
+ return;
+
+ if (!c || c == maxWindow)
+ return;
+
+ bool updatesEnabled = q->updatesEnabled();
+ q->setUpdatesEnabled(false);
+
+ if (c->iconw && icons.contains(c->iconw->parentWidget()))
+ normalizeWindow(w);
+ QRect r(c->geometry());
+ QWorkspaceChild *oldMaxWindow = maxWindow;
+ maxWindow = c;
+
+ showMaximizeControls();
+
+ c->adjustToFullscreen();
+ c->show();
+ c->internalRaise();
+ if (oldMaxWindow != c) {
+ if (oldMaxWindow) {
+ oldMaxWindow->setGeometry(maxRestore);
+ oldMaxWindow->overrideWindowState(Qt::WindowNoState);
+ if(oldMaxWindow->windowWidget())
+ oldMaxWindow->windowWidget()->overrideWindowState(Qt::WindowNoState);
+ }
+ maxRestore = r;
+ }
+
+ activateWindow(w);
+
+ if(!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
+ if (!active && becomeActive) {
+ active = (QWorkspaceChild*)becomeActive->parentWidget();
+ active->setActive(true);
+ becomeActive = 0;
+ emit q->windowActivated(active->windowWidget());
+ }
+ c->widgetResizeHandler->setActive(false);
+ if (c->titlebar)
+ c->titlebar->setMovable(false);
+ }
+ updateWorkspace();
+
+ w->overrideWindowState(Qt::WindowMaximized);
+ c->overrideWindowState(Qt::WindowMaximized);
+ q->setUpdatesEnabled(updatesEnabled);
+}
+
+void QWorkspacePrivate::showWindow(QWidget* w)
+{
+ if (w->isMinimized() && (w->windowFlags() & Qt::WindowMinimizeButtonHint))
+ minimizeWindow(w);
+ else if ((maxWindow || w->isMaximized()) && w->windowFlags() & Qt::WindowMaximizeButtonHint)
+ maximizeWindow(w);
+ else if (w->windowFlags() & Qt::WindowMaximizeButtonHint)
+ normalizeWindow(w);
+ else
+ w->parentWidget()->show();
+ if (maxWindow)
+ maxWindow->internalRaise();
+ updateWorkspace();
+}
+
+
+QWorkspaceChild* QWorkspacePrivate::findChild(QWidget* w)
+{
+ QList<QWorkspaceChild *>::Iterator it(windows.begin());
+ while (it != windows.end()) {
+ QWorkspaceChild* c = *it;
+ ++it;
+ if (c->windowWidget() == w)
+ return c;
+ }
+ return 0;
+}
+
+/*!
+ Returns a list of all visible or minimized child windows. If \a
+ order is CreationOrder (the default), the windows are listed in
+ the order in which they were inserted into the workspace. If \a
+ order is StackingOrder, the windows are listed in their stacking
+ order, with the topmost window as the last item in the list.
+*/
+QWidgetList QWorkspace::windowList(WindowOrder order) const
+{
+ Q_D(const QWorkspace);
+ QWidgetList windows;
+ if (order == StackingOrder) {
+ QObjectList cl = children();
+ for (int i = 0; i < cl.size(); ++i) {
+ QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(cl.at(i));
+ if (c && c->isWindowOrIconVisible())
+ windows.append(c->windowWidget());
+ }
+ } else {
+ QList<QWorkspaceChild *>::ConstIterator it(d->windows.begin());
+ while (it != d->windows.end()) {
+ QWorkspaceChild* c = *it;
+ ++it;
+ if (c && c->isWindowOrIconVisible())
+ windows.append(c->windowWidget());
+ }
+ }
+ return windows;
+}
+
+
+/*! \reimp */
+bool QWorkspace::event(QEvent *e)
+{
+#ifndef QT_NO_SHORTCUT
+ Q_D(QWorkspace);
+ if (e->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ const char *theSlot = d->shortcutMap.value(se->shortcutId(), 0);
+ if (theSlot)
+ QMetaObject::invokeMethod(this, theSlot);
+ } else
+#endif
+ if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut){
+ return true;
+ }
+ return QWidget::event(e);
+}
+
+/*! \reimp */
+bool QWorkspace::eventFilter(QObject *o, QEvent * e)
+{
+ Q_D(QWorkspace);
+ static QElapsedTimer* t = 0;
+ static QWorkspace* tc = 0;
+ if (o == d->maxtools) {
+ switch (e->type()) {
+ case QEvent::MouseButtonPress:
+ {
+ QMenuBar* b = (QMenuBar*)o->parent();
+ if (!t)
+ t = new QElapsedTimer;
+ if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
+ if (isRightToLeft()) {
+ QPoint p = b->mapToGlobal(QPoint(b->x() + b->width(), b->y() + b->height()));
+ p.rx() -= d->popup->sizeHint().width();
+ d->_q_popupOperationMenu(p);
+ } else {
+ d->_q_popupOperationMenu(b->mapToGlobal(QPoint(b->x(), b->y() + b->height())));
+ }
+ t->start();
+ tc = this;
+ } else {
+ tc = 0;
+ closeActiveWindow();
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return QWidget::eventFilter(o, e);
+ }
+ switch (e->type()) {
+ case QEvent::HideToParent:
+ break;
+ case QEvent::ShowToParent:
+ if (QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(o))
+ if (!d->focus.contains(c))
+ d->focus.append(c);
+ d->updateWorkspace();
+ break;
+ case QEvent::WindowTitleChange:
+ if (!d->inTitleChange) {
+ if (o == window())
+ d->topTitle = window()->windowTitle();
+ if (d->maxWindow && d->maxWindow->windowWidget() && d->topTitle.size()) {
+ d->inTitleChange = true;
+ window()->setWindowTitle(tr("%1 - [%2]")
+ .arg(d->topTitle).arg(d->maxWindow->windowWidget()->windowTitle()));
+ d->inTitleChange = false;
+ }
+ }
+ break;
+
+ case QEvent::ModifiedChange:
+ if (o == d->maxWindow)
+ window()->setWindowModified(d->maxWindow->isWindowModified());
+ break;
+
+ case QEvent::Close:
+ if (o == window())
+ {
+ QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
+ while (it != d->windows.end()) {
+ QWorkspaceChild* c = *it;
+ ++it;
+ if (c->shademode)
+ c->showShaded();
+ }
+ } else if (qobject_cast<QWorkspaceChild*>(o)) {
+ d->popup->hide();
+ }
+ d->updateWorkspace();
+ break;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+static QMenuBar *findMenuBar(QWidget *w)
+{
+ // don't search recursively to avoid finding a menu bar of a
+ // mainwindow that happens to be a workspace window (like
+ // a mainwindow in designer)
+ QList<QObject *> children = w->children();
+ for (int i = 0; i < children.count(); ++i) {
+ QMenuBar *bar = qobject_cast<QMenuBar *>(children.at(i));
+ if (bar)
+ return bar;
+ }
+ return 0;
+}
+
+void QWorkspacePrivate::showMaximizeControls()
+{
+ Q_Q(QWorkspace);
+ Q_ASSERT(maxWindow);
+
+ // merge windowtitle and modified state
+ if (!topTitle.size())
+ topTitle = q->window()->windowTitle();
+
+ if (maxWindow->windowWidget()) {
+ QString docTitle = maxWindow->windowWidget()->windowTitle();
+ if (topTitle.size() && docTitle.size()) {
+ inTitleChange = true;
+ q->window()->setWindowTitle(QWorkspace::tr("%1 - [%2]").arg(topTitle).arg(docTitle));
+ inTitleChange = false;
+ }
+ q->window()->setWindowModified(maxWindow->windowWidget()->isWindowModified());
+ }
+
+ if (!q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
+ QMenuBar* b = 0;
+
+ // Do a breadth-first search first on every parent,
+ QWidget* w = q->parentWidget();
+ while (w) {
+ b = findMenuBar(w);
+ if (b)
+ break;
+ w = w->parentWidget();
+ }
+
+ // last attempt.
+ if (!b)
+ b = findMenuBar(q->window());
+
+ if (!b)
+ return;
+
+ if (!maxcontrols) {
+ maxmenubar = b;
+ maxcontrols = new QMDIControl(b);
+ QObject::connect(maxcontrols, SIGNAL(_q_minimize()),
+ q, SLOT(_q_minimizeActiveWindow()));
+ QObject::connect(maxcontrols, SIGNAL(_q_restore()),
+ q, SLOT(_q_normalizeActiveWindow()));
+ QObject::connect(maxcontrols, SIGNAL(_q_close()),
+ q, SLOT(closeActiveWindow()));
+ }
+
+ b->setCornerWidget(maxcontrols);
+ if (b->isVisible())
+ maxcontrols->show();
+ if (!active && becomeActive) {
+ active = (QWorkspaceChild*)becomeActive->parentWidget();
+ active->setActive(true);
+ becomeActive = 0;
+ emit q->windowActivated(active->windowWidget());
+ }
+ if (active) {
+ if (!maxtools) {
+ maxtools = new QLabel(q->window());
+ maxtools->setObjectName(QLatin1String("qt_maxtools"));
+ maxtools->installEventFilter(q);
+ }
+ if (active->windowWidget() && !active->windowWidget()->windowIcon().isNull()) {
+ QIcon icon = active->windowWidget()->windowIcon();
+ int iconSize = maxcontrols->size().height();
+ maxtools->setPixmap(icon.pixmap(QSize(iconSize, iconSize)));
+ } else {
+ QPixmap pm = q->style()->standardPixmap(QStyle::SP_TitleBarMenuButton, 0, q);
+ if (pm.isNull()) {
+ pm = QPixmap(14,14);
+ pm.fill(Qt::black);
+ }
+ maxtools->setPixmap(pm);
+ }
+ b->setCornerWidget(maxtools, Qt::TopLeftCorner);
+ if (b->isVisible())
+ maxtools->show();
+ }
+ }
+}
+
+
+void QWorkspacePrivate::hideMaximizeControls()
+{
+ Q_Q(QWorkspace);
+ if (maxmenubar && !q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
+ if (maxmenubar) {
+ maxmenubar->setCornerWidget(0, Qt::TopLeftCorner);
+ maxmenubar->setCornerWidget(0, Qt::TopRightCorner);
+ }
+ if (maxcontrols) {
+ maxcontrols->deleteLater();
+ maxcontrols = 0;
+ }
+ if (maxtools) {
+ maxtools->deleteLater();
+ maxtools = 0;
+ }
+ }
+
+ //unmerge the title bar/modification state
+ if (topTitle.size()) {
+ inTitleChange = true;
+ q->window()->setWindowTitle(topTitle);
+ inTitleChange = false;
+ }
+ q->window()->setWindowModified(false);
+}
+
+/*!
+ Closes the child window that is currently active.
+
+ \sa closeAllWindows()
+*/
+void QWorkspace::closeActiveWindow()
+{
+ Q_D(QWorkspace);
+ if (d->maxWindow && d->maxWindow->windowWidget())
+ d->maxWindow->windowWidget()->close();
+ else if (d->active && d->active->windowWidget())
+ d->active->windowWidget()->close();
+ d->updateWorkspace();
+}
+
+/*!
+ Closes all child windows.
+
+ If any child window fails to accept the close event, the remaining windows
+ will remain open.
+
+ \sa closeActiveWindow()
+*/
+void QWorkspace::closeAllWindows()
+{
+ Q_D(QWorkspace);
+ bool did_close = true;
+ QList<QWorkspaceChild *>::const_iterator it = d->windows.constBegin();
+ while (it != d->windows.constEnd() && did_close) {
+ QWorkspaceChild *c = *it;
+ ++it;
+ if (c->windowWidget() && !c->windowWidget()->isHidden())
+ did_close = c->windowWidget()->close();
+ }
+}
+
+void QWorkspacePrivate::_q_normalizeActiveWindow()
+{
+ if (maxWindow)
+ maxWindow->showNormal();
+ else if (active)
+ active->showNormal();
+}
+
+void QWorkspacePrivate::_q_minimizeActiveWindow()
+{
+ if (maxWindow)
+ maxWindow->showMinimized();
+ else if (active)
+ active->showMinimized();
+}
+
+void QWorkspacePrivate::_q_showOperationMenu()
+{
+ Q_Q(QWorkspace);
+ if (!active || !active->windowWidget())
+ return;
+ Q_ASSERT((active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint));
+ QPoint p;
+ QMenu *popup = (active->titlebar && active->titlebar->isTool()) ? toolPopup : this->popup;
+ if (q->isRightToLeft()) {
+ p = QPoint(active->windowWidget()->mapToGlobal(QPoint(active->windowWidget()->width(),0)));
+ p.rx() -= popup->sizeHint().width();
+ } else {
+ p = QPoint(active->windowWidget()->mapToGlobal(QPoint(0,0)));
+ }
+ if (!active->isVisible()) {
+ p = active->iconWidget()->mapToGlobal(QPoint(0,0));
+ p.ry() -= popup->sizeHint().height();
+ }
+ _q_popupOperationMenu(p);
+}
+
+void QWorkspacePrivate::_q_popupOperationMenu(const QPoint& p)
+{
+ if (!active || !active->windowWidget() || !(active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint))
+ return;
+ if (active->titlebar && active->titlebar->isTool())
+ toolPopup->popup(p);
+ else
+ popup->popup(p);
+}
+
+void QWorkspacePrivate::_q_updateActions()
+{
+ Q_Q(QWorkspace);
+ for (int i = 1; i < NCountAct-1; i++) {
+ bool enable = active != 0;
+ actions[i]->setEnabled(enable);
+ }
+
+ if (!active || !active->windowWidget())
+ return;
+
+ QWidget *windowWidget = active->windowWidget();
+ bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize();
+ actions[QWorkspacePrivate::ResizeAct]->setEnabled(canResize);
+ actions[QWorkspacePrivate::MinimizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMinimizeButtonHint));
+ actions[QWorkspacePrivate::MaximizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMaximizeButtonHint) && canResize);
+
+ if (active == maxWindow) {
+ actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
+ actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
+ actions[QWorkspacePrivate::MaximizeAct]->setEnabled(false);
+ actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
+ } else if (active->isVisible()){
+ actions[QWorkspacePrivate::RestoreAct]->setEnabled(false);
+ } else {
+ actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
+ actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
+ actions[QWorkspacePrivate::MinimizeAct]->setEnabled(false);
+ actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
+ }
+ if (active->shademode) {
+ actions[QWorkspacePrivate::ShadeAct]->setIcon(
+ QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarUnshadeButton, 0, q)));
+ actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("&Unshade"));
+ } else {
+ actions[QWorkspacePrivate::ShadeAct]->setIcon(
+ QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)));
+ actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("Sh&ade"));
+ }
+ actions[QWorkspacePrivate::StaysOnTopAct]->setEnabled(!active->shademode && canResize);
+ actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(
+ (active->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint));
+}
+
+void QWorkspacePrivate::_q_operationMenuActivated(QAction *action)
+{
+ if (!active)
+ return;
+ if(action == actions[QWorkspacePrivate::RestoreAct]) {
+ active->showNormal();
+ } else if(action == actions[QWorkspacePrivate::MoveAct]) {
+ active->doMove();
+ } else if(action == actions[QWorkspacePrivate::ResizeAct]) {
+ if (active->shademode)
+ active->showShaded();
+ active->doResize();
+ } else if(action == actions[QWorkspacePrivate::MinimizeAct]) {
+ active->showMinimized();
+ } else if(action == actions[QWorkspacePrivate::MaximizeAct]) {
+ active->showMaximized();
+ } else if(action == actions[QWorkspacePrivate::ShadeAct]) {
+ active->showShaded();
+ } else if(action == actions[QWorkspacePrivate::StaysOnTopAct]) {
+ if(QWidget* w = active->windowWidget()) {
+ if ((w->windowFlags() & Qt::WindowStaysOnTopHint)) {
+ w->overrideWindowFlags(w->windowFlags() & ~Qt::WindowStaysOnTopHint);
+ } else {
+ w->overrideWindowFlags(w->windowFlags() | Qt::WindowStaysOnTopHint);
+ w->parentWidget()->raise();
+ }
+ }
+ }
+}
+
+
+void QWorkspacePrivate::hideChild(QWorkspaceChild *c)
+{
+ Q_Q(QWorkspace);
+
+// bool updatesEnabled = q->updatesEnabled();
+// q->setUpdatesEnabled(false);
+ focus.removeAll(c);
+ QRect restore;
+ if (maxWindow == c)
+ restore = maxRestore;
+ if (active == c) {
+ q->setFocus();
+ q->activatePreviousWindow();
+ }
+ if (active == c)
+ activateWindow(0);
+ if (maxWindow == c) {
+ hideMaximizeControls();
+ maxWindow = 0;
+ }
+ c->hide();
+ if (!restore.isEmpty())
+ c->setGeometry(restore);
+// q->setUpdatesEnabled(updatesEnabled);
+}
+
+/*!
+ Gives the input focus to the next window in the list of child
+ windows.
+
+ \sa activatePreviousWindow()
+*/
+void QWorkspace::activateNextWindow()
+{
+ Q_D(QWorkspace);
+
+ if (d->focus.isEmpty())
+ return;
+ if (!d->active) {
+ if (d->focus.first())
+ d->activateWindow(d->focus.first()->windowWidget(), false);
+ return;
+ }
+
+ int a = d->focus.indexOf(d->active) + 1;
+
+ a = a % d->focus.count();
+
+ if (d->focus.at(a))
+ d->activateWindow(d->focus.at(a)->windowWidget(), false);
+ else
+ d->activateWindow(0);
+}
+
+/*!
+ Gives the input focus to the previous window in the list of child
+ windows.
+
+ \sa activateNextWindow()
+*/
+void QWorkspace::activatePreviousWindow()
+{
+ Q_D(QWorkspace);
+
+ if (d->focus.isEmpty())
+ return;
+ if (!d->active) {
+ if (d->focus.last())
+ d->activateWindow(d->focus.first()->windowWidget(), false);
+ else
+ d->activateWindow(0);
+ return;
+ }
+
+ int a = d->focus.indexOf(d->active) - 1;
+ if (a < 0)
+ a = d->focus.count()-1;
+
+ if (d->focus.at(a))
+ d->activateWindow(d->focus.at(a)->windowWidget(), false);
+ else
+ d->activateWindow(0);
+}
+
+
+/*!
+ \fn void QWorkspace::windowActivated(QWidget* w)
+
+ This signal is emitted when the child window \a w becomes active.
+ Note that \a w can be 0, and that more than one signal may be
+ emitted for a single activation event.
+
+ \sa activeWindow(), windowList()
+*/
+
+/*!
+ Arranges all the child windows in a cascade pattern.
+
+ \sa tile(), arrangeIcons()
+*/
+void QWorkspace::cascade()
+{
+ Q_D(QWorkspace);
+ blockSignals(true);
+ if (d->maxWindow)
+ d->maxWindow->showNormal();
+
+ if (d->vbar) {
+ d->vbar->blockSignals(true);
+ d->vbar->setValue(0);
+ d->vbar->blockSignals(false);
+ d->hbar->blockSignals(true);
+ d->hbar->setValue(0);
+ d->hbar->blockSignals(false);
+ d->_q_scrollBarChanged();
+ }
+
+ const int xoffset = 13;
+ const int yoffset = 20;
+
+ // make a list of all relevant mdi clients
+ QList<QWorkspaceChild *> widgets;
+ QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
+ QWorkspaceChild* wc = 0;
+
+ for (it = d->focus.begin(); it != d->focus.end(); ++it) {
+ wc = *it;
+ if (wc->windowWidget()->isVisibleTo(this) && !(wc->titlebar && wc->titlebar->isTool()))
+ widgets.append(wc);
+ }
+
+ int x = 0;
+ int y = 0;
+
+ it = widgets.begin();
+ while (it != widgets.end()) {
+ QWorkspaceChild *child = *it;
+ ++it;
+
+ QSize prefSize = child->windowWidget()->sizeHint().expandedTo(qSmartMinSize(child->windowWidget()));
+ if (!prefSize.isValid())
+ prefSize = child->windowWidget()->size();
+ prefSize = prefSize.expandedTo(qSmartMinSize(child->windowWidget()));
+ if (prefSize.isValid())
+ prefSize += QSize(child->baseSize().width(), child->baseSize().height());
+
+ int w = prefSize.width();
+ int h = prefSize.height();
+
+ child->showNormal();
+ if (y + h > height())
+ y = 0;
+ if (x + w > width())
+ x = 0;
+ child->setGeometry(x, y, w, h);
+ x += xoffset;
+ y += yoffset;
+ child->internalRaise();
+ }
+ d->updateWorkspace();
+ blockSignals(false);
+}
+
+/*!
+ Arranges all child windows in a tile pattern.
+
+ \sa cascade(), arrangeIcons()
+*/
+void QWorkspace::tile()
+{
+ Q_D(QWorkspace);
+ blockSignals(true);
+ QWidget *oldActive = d->active ? d->active->windowWidget() : 0;
+ if (d->maxWindow)
+ d->maxWindow->showNormal();
+
+ if (d->vbar) {
+ d->vbar->blockSignals(true);
+ d->vbar->setValue(0);
+ d->vbar->blockSignals(false);
+ d->hbar->blockSignals(true);
+ d->hbar->setValue(0);
+ d->hbar->blockSignals(false);
+ d->_q_scrollBarChanged();
+ }
+
+ int rows = 1;
+ int cols = 1;
+ int n = 0;
+ QWorkspaceChild* c;
+
+ QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
+ while (it != d->windows.end()) {
+ c = *it;
+ ++it;
+ if (!c->windowWidget()->isHidden()
+ && !(c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)
+ && !c->iconw)
+ n++;
+ }
+
+ while (rows * cols < n) {
+ if (cols <= rows)
+ cols++;
+ else
+ rows++;
+ }
+ int add = cols * rows - n;
+ bool* used = new bool[cols*rows];
+ for (int i = 0; i < rows*cols; i++)
+ used[i] = false;
+
+ int row = 0;
+ int col = 0;
+ int w = width() / cols;
+ int h = height() / rows;
+
+ it = d->windows.begin();
+ while (it != d->windows.end()) {
+ c = *it;
+ ++it;
+ if (c->iconw || c->windowWidget()->isHidden() || (c->titlebar && c->titlebar->isTool()))
+ continue;
+ if (!row && !col) {
+ w -= c->baseSize().width();
+ h -= c->baseSize().height();
+ }
+ if ((c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
+ QPoint p = c->pos();
+ if (p.x()+c->width() < 0)
+ p.setX(0);
+ if (p.x() > width())
+ p.setX(width() - c->width());
+ if (p.y() + 10 < 0)
+ p.setY(0);
+ if (p.y() > height())
+ p.setY(height() - c->height());
+
+ if (p != c->pos())
+ c->QWidget::move(p);
+ } else {
+ c->showNormal();
+ used[row*cols+col] = true;
+ QSize sz(w, h);
+ QSize bsize(c->baseSize());
+ sz = sz.expandedTo(c->windowWidget()->minimumSize()).boundedTo(c->windowWidget()->maximumSize());
+ sz += bsize;
+
+ if ( add ) {
+ if (sz.height() == h + bsize.height()) // no relevant constrains
+ sz.rheight() *= 2;
+ used[(row+1)*cols+col] = true;
+ add--;
+ }
+
+ c->setGeometry(col*w + col*bsize.width(), row*h + row*bsize.height(), sz.width(), sz.height());
+
+ while(row < rows && col < cols && used[row*cols+col]) {
+ col++;
+ if (col == cols) {
+ col = 0;
+ row++;
+ }
+ }
+ }
+ }
+ delete [] used;
+
+ d->activateWindow(oldActive);
+ d->updateWorkspace();
+ blockSignals(false);
+}
+
+/*!
+ Arranges all iconified windows at the bottom of the workspace.
+
+ \sa cascade(), tile()
+*/
+void QWorkspace::arrangeIcons()
+{
+ Q_D(QWorkspace);
+
+ QRect cr = d->updateWorkspace();
+ int x = 0;
+ int y = -1;
+
+ QList<QWidget *>::Iterator it(d->icons.begin());
+ while (it != d->icons.end()) {
+ QWidget* i = *it;
+ if (y == -1)
+ y = cr.height() - i->height();
+ if (x > 0 && x + i->width() > cr.width()) {
+ x = 0;
+ y -= i->height();
+ }
+ i->move(x, y);
+ x += i->width();
+ ++it;
+ }
+ d->updateWorkspace();
+}
+
+
+QWorkspaceChild::QWorkspaceChild(QWidget* window, QWorkspace *parent, Qt::WindowFlags flags)
+ : QWidget(parent,
+ Qt::FramelessWindowHint | Qt::SubWindow)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ setAttribute(Qt::WA_NoMousePropagation);
+ setMouseTracking(true);
+ act = false;
+ iconw = 0;
+ shademode = false;
+ titlebar = 0;
+ setAutoFillBackground(true);
+
+ setBackgroundRole(QPalette::Window);
+ if (window) {
+ flags |= (window->windowFlags() & Qt::MSWindowsOwnDC);
+ if (flags)
+ window->setParent(this, flags & ~Qt::WindowType_Mask);
+ else
+ window->setParent(this);
+ }
+
+ if (window && (flags & (Qt::WindowTitleHint
+ | Qt::WindowSystemMenuHint
+ | Qt::WindowMinimizeButtonHint
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowContextHelpButtonHint))) {
+ titlebar = new QWorkspaceTitleBar(window, this, flags);
+ connect(titlebar, SIGNAL(doActivate()),
+ this, SLOT(activate()));
+ connect(titlebar, SIGNAL(doClose()),
+ window, SLOT(close()));
+ connect(titlebar, SIGNAL(doMinimize()),
+ this, SLOT(showMinimized()));
+ connect(titlebar, SIGNAL(doNormal()),
+ this, SLOT(showNormal()));
+ connect(titlebar, SIGNAL(doMaximize()),
+ this, SLOT(showMaximized()));
+ connect(titlebar, SIGNAL(popupOperationMenu(QPoint)),
+ this, SIGNAL(popupOperationMenu(QPoint)));
+ connect(titlebar, SIGNAL(showOperationMenu()),
+ this, SIGNAL(showOperationMenu()));
+ connect(titlebar, SIGNAL(doShade()),
+ this, SLOT(showShaded()));
+ connect(titlebar, SIGNAL(doubleClicked()),
+ this, SLOT(titleBarDoubleClicked()));
+ }
+
+ setMinimumSize(128, 0);
+ int fw = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
+ setContentsMargins(fw, fw, fw, fw);
+
+ childWidget = window;
+ if (!childWidget)
+ return;
+
+ setWindowTitle(childWidget->windowTitle());
+
+ QPoint p;
+ QSize s;
+ QSize cs;
+
+ bool hasBeenResized = childWidget->testAttribute(Qt::WA_Resized);
+
+ if (!hasBeenResized)
+ cs = childWidget->sizeHint().expandedTo(childWidget->minimumSizeHint()).expandedTo(childWidget->minimumSize()).boundedTo(childWidget->maximumSize());
+ else
+ cs = childWidget->size();
+
+ windowSize = cs;
+
+ int th = titlebar ? titlebar->sizeHint().height() : 0;
+ if (titlebar) {
+ if (!childWidget->windowIcon().isNull())
+ titlebar->setWindowIcon(childWidget->windowIcon());
+
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ th -= contentsRect().y();
+
+ p = QPoint(contentsRect().x(),
+ th + contentsRect().y());
+ s = QSize(cs.width() + 2*frameWidth(),
+ cs.height() + 2*frameWidth() + th);
+ } else {
+ p = QPoint(contentsRect().x(), contentsRect().y());
+ s = QSize(cs.width() + 2*frameWidth(),
+ cs.height() + 2*frameWidth());
+ }
+
+ childWidget->move(p);
+ resize(s);
+
+ childWidget->installEventFilter(this);
+
+ widgetResizeHandler = new QWidgetResizeHandler(this, window);
+ widgetResizeHandler->setSizeProtection(!parent->scrollBarsEnabled());
+ widgetResizeHandler->setFrameWidth(frameWidth());
+ connect(widgetResizeHandler, SIGNAL(activate()),
+ this, SLOT(activate()));
+ if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ widgetResizeHandler->setExtraHeight(th + contentsRect().y() - 2*frameWidth());
+ else
+ widgetResizeHandler->setExtraHeight(th + contentsRect().y() - frameWidth());
+ if (childWidget->minimumSize() == childWidget->maximumSize())
+ widgetResizeHandler->setActive(QWidgetResizeHandler::Resize, false);
+ setBaseSize(baseSize());
+}
+
+QWorkspaceChild::~QWorkspaceChild()
+{
+ QWorkspace *workspace = qobject_cast<QWorkspace*>(parentWidget());
+ if (iconw) {
+ if (workspace)
+ workspace->d_func()->removeIcon(iconw->parentWidget());
+ delete iconw->parentWidget();
+ }
+
+ if (workspace) {
+ workspace->d_func()->focus.removeAll(this);
+ if (workspace->d_func()->active == this)
+ workspace->activatePreviousWindow();
+ if (workspace->d_func()->active == this)
+ workspace->d_func()->activateWindow(0);
+ if (workspace->d_func()->maxWindow == this) {
+ workspace->d_func()->hideMaximizeControls();
+ workspace->d_func()->maxWindow = 0;
+ }
+ }
+}
+
+void QWorkspaceChild::moveEvent(QMoveEvent *)
+{
+ ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();
+}
+
+void QWorkspaceChild::resizeEvent(QResizeEvent *)
+{
+ bool wasMax = isMaximized();
+ QRect r = contentsRect();
+ QRect cr;
+
+ updateMask();
+
+ if (titlebar) {
+ int th = titlebar->sizeHint().height();
+ QRect tbrect(0, 0, width(), th);
+ if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ tbrect = QRect(r.x(), r.y(), r.width(), th);
+ titlebar->setGeometry(tbrect);
+
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ th -= frameWidth();
+ cr = QRect(r.x(), r.y() + th + (shademode ? (frameWidth() * 3) : 0),
+ r.width(), r.height() - th);
+ } else {
+ cr = r;
+ }
+
+ if (!childWidget)
+ return;
+
+ bool doContentsResize = (windowSize == childWidget->size()
+ || !(childWidget->testAttribute(Qt::WA_Resized) && childWidget->testAttribute(Qt::WA_PendingResizeEvent))
+ ||childWidget->isMaximized());
+
+ windowSize = cr.size();
+ childWidget->move(cr.topLeft());
+ if (doContentsResize)
+ childWidget->resize(cr.size());
+ ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();
+
+ if (wasMax) {
+ overrideWindowState(Qt::WindowMaximized);
+ childWidget->overrideWindowState(Qt::WindowMaximized);
+ }
+}
+
+QSize QWorkspaceChild::baseSize() const
+{
+ int th = titlebar ? titlebar->sizeHint().height() : 0;
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ th -= frameWidth();
+ return QSize(2*frameWidth(), 2*frameWidth() + th);
+}
+
+QSize QWorkspaceChild::sizeHint() const
+{
+ if (!childWidget)
+ return QWidget::sizeHint() + baseSize();
+
+ QSize prefSize = windowWidget()->sizeHint().expandedTo(windowWidget()->minimumSizeHint());
+ prefSize = prefSize.expandedTo(windowWidget()->minimumSize()).boundedTo(windowWidget()->maximumSize());
+ prefSize += baseSize();
+
+ return prefSize;
+}
+
+QSize QWorkspaceChild::minimumSizeHint() const
+{
+ if (!childWidget)
+ return QWidget::minimumSizeHint() + baseSize();
+ QSize s = childWidget->minimumSize();
+ if (s.isEmpty())
+ s = childWidget->minimumSizeHint();
+ return s + baseSize();
+}
+
+void QWorkspaceChild::activate()
+{
+ ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
+}
+
+bool QWorkspaceChild::eventFilter(QObject * o, QEvent * e)
+{
+ if (!isActive()
+ && (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::FocusIn)) {
+ if (iconw) {
+ ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
+ if (iconw) {
+ ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
+ delete iconw->parentWidget();
+ iconw = 0;
+ }
+ }
+ activate();
+ }
+
+ // for all widgets except the window, that's the only thing we
+ // process, and if we have no childWidget we skip totally
+ if (o != childWidget || childWidget == 0)
+ return false;
+
+ switch (e->type()) {
+ case QEvent::ShowToParent:
+ if (((QWorkspace*)parentWidget())->d_func()->focus.indexOf(this) < 0)
+ ((QWorkspace*)parentWidget())->d_func()->focus.append(this);
+
+ if (windowWidget() && (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
+ internalRaise();
+ show();
+ }
+ ((QWorkspace*)parentWidget())->d_func()->showWindow(windowWidget());
+ break;
+ case QEvent::WindowStateChange: {
+ if (static_cast<QWindowStateChangeEvent*>(e)->isOverride())
+ break;
+ Qt::WindowStates state = windowWidget()->windowState();
+
+ if (state & Qt::WindowMinimized) {
+ ((QWorkspace*)parentWidget())->d_func()->minimizeWindow(windowWidget());
+ } else if (state & Qt::WindowMaximized) {
+ if (windowWidget()->maximumSize().isValid() &&
+ (windowWidget()->maximumWidth() < parentWidget()->width() ||
+ windowWidget()->maximumHeight() < parentWidget()->height())) {
+ windowWidget()->resize(windowWidget()->maximumSize());
+ windowWidget()->overrideWindowState(Qt::WindowNoState);
+ if (titlebar)
+ titlebar->update();
+ break;
+ }
+ if ((windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
+ ((QWorkspace*)parentWidget())->d_func()->maximizeWindow(windowWidget());
+ else
+ ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
+ } else {
+ ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
+ if (iconw) {
+ ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
+ delete iconw->parentWidget();
+ }
+ }
+ } break;
+ case QEvent::HideToParent:
+ {
+ QWidget * w = iconw;
+ if (w && (w = w->parentWidget())) {
+ ((QWorkspace*)parentWidget())->d_func()->removeIcon(w);
+ delete w;
+ }
+ ((QWorkspace*)parentWidget())->d_func()->hideChild(this);
+ } break;
+ case QEvent::WindowIconChange:
+ {
+ QWorkspace* ws = (QWorkspace*)parentWidget();
+ if (ws->d_func()->maxtools && ws->d_func()->maxWindow == this) {
+ int iconSize = ws->d_func()->maxtools->size().height();
+ ws->d_func()->maxtools->setPixmap(childWidget->windowIcon().pixmap(QSize(iconSize, iconSize)));
+ }
+ }
+ // fall through
+ case QEvent::WindowTitleChange:
+ setWindowTitle(windowWidget()->windowTitle());
+ if (titlebar)
+ titlebar->update();
+ if (iconw)
+ iconw->update();
+ break;
+ case QEvent::ModifiedChange:
+ setWindowModified(windowWidget()->isWindowModified());
+ if (titlebar)
+ titlebar->update();
+ if (iconw)
+ iconw->update();
+ break;
+ case QEvent::Resize:
+ {
+ QResizeEvent* re = (QResizeEvent*)e;
+ if (re->size() != windowSize && !shademode) {
+ resize(re->size() + baseSize());
+ childWidget->update(); //workaround
+ }
+ }
+ break;
+
+ case QEvent::WindowDeactivate:
+ if (titlebar && titlebar->isActive()) {
+ update();
+ }
+ break;
+
+ case QEvent::WindowActivate:
+ if (titlebar && titlebar->isActive()) {
+ update();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return QWidget::eventFilter(o, e);
+}
+
+void QWorkspaceChild::childEvent(QChildEvent* e)
+{
+ if (e->type() == QEvent::ChildRemoved && e->child() == childWidget) {
+ childWidget = 0;
+ if (iconw) {
+ ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
+ delete iconw->parentWidget();
+ }
+ close();
+ }
+}
+
+
+void QWorkspaceChild::doResize()
+{
+ widgetResizeHandler->doResize();
+}
+
+void QWorkspaceChild::doMove()
+{
+ widgetResizeHandler->doMove();
+}
+
+void QWorkspaceChild::enterEvent(QEvent *)
+{
+}
+
+void QWorkspaceChild::leaveEvent(QEvent *)
+{
+#ifndef QT_NO_CURSOR
+ if (!widgetResizeHandler->isButtonDown())
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+void QWorkspaceChild::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOptionFrame opt;
+ opt.rect = rect();
+ opt.palette = palette();
+ opt.state = QStyle::State_None;
+ opt.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
+ opt.midLineWidth = 1;
+
+ if (titlebar && titlebar->isActive() && isActiveWindow())
+ opt.state |= QStyle::State_Active;
+
+ style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &p, this);
+}
+
+void QWorkspaceChild::changeEvent(QEvent *ev)
+{
+ if(ev->type() == QEvent::StyleChange) {
+ resizeEvent(0);
+ if (iconw) {
+ QFrame *frame = qobject_cast<QFrame*>(iconw->parentWidget());
+ Q_ASSERT(frame);
+ if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
+ frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
+ frame->resize(196+2*frame->frameWidth(), 20 + 2*frame->frameWidth());
+ } else {
+ frame->resize(196, 20);
+ }
+ }
+ updateMask();
+ }
+ QWidget::changeEvent(ev);
+}
+
+void QWorkspaceChild::setActive(bool b)
+{
+ if (!childWidget)
+ return;
+
+ bool hasFocus = isChildOf(window()->focusWidget(), this);
+ if (act == b && (act == hasFocus))
+ return;
+
+ act = b;
+
+ if (titlebar)
+ titlebar->setActive(act);
+ if (iconw)
+ iconw->setActive(act);
+ update();
+
+ QList<QWidget*> wl = childWidget->findChildren<QWidget*>();
+ if (act) {
+ for (int i = 0; i < wl.size(); ++i) {
+ QWidget *w = wl.at(i);
+ w->removeEventFilter(this);
+ }
+ if (!hasFocus) {
+ QWidget *lastfocusw = childWidget->focusWidget();
+ if (lastfocusw && lastfocusw->focusPolicy() != Qt::NoFocus) {
+ lastfocusw->setFocus();
+ } else if (childWidget->focusPolicy() != Qt::NoFocus) {
+ childWidget->setFocus();
+ } else {
+ // find something, anything, that accepts focus, and use that.
+ for (int i = 0; i < wl.size(); ++i) {
+ QWidget *w = wl.at(i);
+ if(w->focusPolicy() != Qt::NoFocus) {
+ w->setFocus();
+ hasFocus = true;
+ break;
+ }
+ }
+ if (!hasFocus)
+ setFocus();
+ }
+ }
+ } else {
+ for (int i = 0; i < wl.size(); ++i) {
+ QWidget *w = wl.at(i);
+ w->removeEventFilter(this);
+ w->installEventFilter(this);
+ }
+ }
+}
+
+bool QWorkspaceChild::isActive() const
+{
+ return act;
+}
+
+QWidget* QWorkspaceChild::windowWidget() const
+{
+ return childWidget;
+}
+
+bool QWorkspaceChild::isWindowOrIconVisible() const
+{
+ return childWidget && (!isHidden() || (iconw && !iconw->isHidden()));
+}
+
+void QWorkspaceChild::updateMask()
+{
+ QStyleOptionTitleBar titleBarOptions;
+ titleBarOptions.rect = rect();
+ titleBarOptions.titleBarFlags = windowFlags();
+ titleBarOptions.titleBarState = windowState();
+
+ QStyleHintReturnMask frameMask;
+ if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, this, &frameMask)) {
+ setMask(frameMask.region);
+ } else if (!mask().isEmpty()) {
+ clearMask();
+ }
+
+ if (iconw) {
+ QFrame *frame = qobject_cast<QFrame *>(iconw->parentWidget());
+ Q_ASSERT(frame);
+
+ titleBarOptions.rect = frame->rect();
+ titleBarOptions.titleBarFlags = frame->windowFlags();
+ titleBarOptions.titleBarState = frame->windowState() | Qt::WindowMinimized;
+ if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, frame, &frameMask)) {
+ frame->setMask(frameMask.region);
+ } else if (!frame->mask().isEmpty()) {
+ frame->clearMask();
+ }
+ }
+}
+
+QWidget* QWorkspaceChild::iconWidget() const
+{
+ if (!iconw) {
+ QWorkspaceChild* that = (QWorkspaceChild*) this;
+
+ QFrame* frame = new QFrame(that, Qt::Window);
+ QVBoxLayout *vbox = new QVBoxLayout(frame);
+ vbox->setMargin(0);
+ QWorkspaceTitleBar *tb = new QWorkspaceTitleBar(windowWidget(), frame);
+ vbox->addWidget(tb);
+ tb->setObjectName(QLatin1String("_workspacechild_icon_"));
+ QStyleOptionTitleBar opt;
+ tb->initStyleOption(&opt);
+ int th = style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, tb);
+ int iconSize = style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this);
+ if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
+ frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
+ frame->resize(iconSize+2*frame->frameWidth(), th+2*frame->frameWidth());
+ } else {
+ frame->resize(iconSize, th);
+ }
+
+ that->iconw = tb;
+ that->updateMask();
+ iconw->setActive(isActive());
+
+ connect(iconw, SIGNAL(doActivate()),
+ this, SLOT(activate()));
+ connect(iconw, SIGNAL(doClose()),
+ windowWidget(), SLOT(close()));
+ connect(iconw, SIGNAL(doNormal()),
+ this, SLOT(showNormal()));
+ connect(iconw, SIGNAL(doMaximize()),
+ this, SLOT(showMaximized()));
+ connect(iconw, SIGNAL(popupOperationMenu(QPoint)),
+ this, SIGNAL(popupOperationMenu(QPoint)));
+ connect(iconw, SIGNAL(showOperationMenu()),
+ this, SIGNAL(showOperationMenu()));
+ connect(iconw, SIGNAL(doubleClicked()),
+ this, SLOT(titleBarDoubleClicked()));
+ }
+ if (windowWidget()) {
+ iconw->setWindowTitle(windowWidget()->windowTitle());
+ }
+ return iconw->parentWidget();
+}
+
+void QWorkspaceChild::showMinimized()
+{
+ windowWidget()->setWindowState(Qt::WindowMinimized | (windowWidget()->windowState() & ~Qt::WindowMaximized));
+}
+
+void QWorkspaceChild::showMaximized()
+{
+ windowWidget()->setWindowState(Qt::WindowMaximized | (windowWidget()->windowState() & ~Qt::WindowMinimized));
+}
+
+void QWorkspaceChild::showNormal()
+{
+ windowWidget()->setWindowState(windowWidget()->windowState() & ~(Qt::WindowMinimized|Qt::WindowMaximized));
+}
+
+void QWorkspaceChild::showShaded()
+{
+ if (!titlebar)
+ return;
+ ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
+ QWidget* w = windowWidget();
+ if (shademode) {
+ w->overrideWindowState(Qt::WindowNoState);
+ overrideWindowState(Qt::WindowNoState);
+
+ shademode = false;
+ resize(shadeRestore.expandedTo(minimumSizeHint()));
+ setMinimumSize(shadeRestoreMin);
+ style()->polish(this);
+ } else {
+ shadeRestore = size();
+ shadeRestoreMin = minimumSize();
+ setMinimumHeight(0);
+ shademode = true;
+ w->overrideWindowState(Qt::WindowMinimized);
+ overrideWindowState(Qt::WindowMinimized);
+
+ if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
+ resize(width(), titlebar->height());
+ else
+ resize(width(), titlebar->height() + 2*frameWidth() + 1);
+ style()->polish(this);
+ }
+ titlebar->update();
+}
+
+void QWorkspaceChild::titleBarDoubleClicked()
+{
+ if (!windowWidget())
+ return;
+ if (iconw)
+ showNormal();
+ else if (windowWidget()->windowFlags() & Qt::WindowShadeButtonHint)
+ showShaded();
+ else if (windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint)
+ showMaximized();
+}
+
+void QWorkspaceChild::adjustToFullscreen()
+{
+ if (!childWidget)
+ return;
+
+ if(!((QWorkspace*)parentWidget())->d_func()->maxmenubar || style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
+ setGeometry(parentWidget()->rect());
+ } else {
+ int fw = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
+ bool noBorder = style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar);
+ int th = titlebar ? titlebar->sizeHint().height() : 0;
+ int w = parentWidget()->width() + 2*fw;
+ int h = parentWidget()->height() + (noBorder ? fw : 2*fw) + th;
+ w = qMax(w, childWidget->minimumWidth());
+ h = qMax(h, childWidget->minimumHeight());
+ setGeometry(-fw, (noBorder ? 0 : -fw) - th, w, h);
+ }
+ childWidget->overrideWindowState(Qt::WindowMaximized);
+ overrideWindowState(Qt::WindowMaximized);
+}
+
+void QWorkspaceChild::internalRaise()
+{
+
+ QWidget *stackUnderWidget = 0;
+ if (!windowWidget() || (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint) == 0) {
+
+ QList<QWorkspaceChild *>::Iterator it(((QWorkspace*)parent())->d_func()->windows.begin());
+ while (it != ((QWorkspace*)parent())->d_func()->windows.end()) {
+ QWorkspaceChild* c = *it;
+ ++it;
+ if (c->windowWidget() &&
+ !c->windowWidget()->isHidden() &&
+ (c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
+ if (stackUnderWidget)
+ c->stackUnder(stackUnderWidget);
+ else
+ c->raise();
+ stackUnderWidget = c;
+ }
+ }
+ }
+
+ if (stackUnderWidget) {
+ if (iconw)
+ iconw->parentWidget()->stackUnder(stackUnderWidget);
+ stackUnder(stackUnderWidget);
+ } else {
+ if (iconw)
+ iconw->parentWidget()->raise();
+ raise();
+ }
+
+}
+
+void QWorkspaceChild::show()
+{
+ if (childWidget && childWidget->isHidden())
+ childWidget->show();
+ QWidget::show();
+}
+
+bool QWorkspace::scrollBarsEnabled() const
+{
+ Q_D(const QWorkspace);
+ return d->vbar != 0;
+}
+
+/*!
+ \property QWorkspace::scrollBarsEnabled
+ \brief whether the workspace provides scroll bars
+
+ If this property is true, the workspace will provide scroll bars if any
+ of the child windows extend beyond the edges of the visible
+ workspace. The workspace area will automatically increase to
+ contain child windows if they are resized beyond the right or
+ bottom edges of the visible area.
+
+ If this property is false (the default), resizing child windows
+ out of the visible area of the workspace is not permitted, although
+ it is still possible to position them partially outside the visible area.
+*/
+void QWorkspace::setScrollBarsEnabled(bool enable)
+{
+ Q_D(QWorkspace);
+ if ((d->vbar != 0) == enable)
+ return;
+
+ d->xoffset = d->yoffset = 0;
+ if (enable) {
+ d->vbar = new QScrollBar(Qt::Vertical, this);
+ d->vbar->setObjectName(QLatin1String("vertical scrollbar"));
+ connect(d->vbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
+ d->hbar = new QScrollBar(Qt::Horizontal, this);
+ d->hbar->setObjectName(QLatin1String("horizontal scrollbar"));
+ connect(d->hbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
+ d->corner = new QWidget(this);
+ d->corner->setBackgroundRole(QPalette::Window);
+ d->corner->setObjectName(QLatin1String("qt_corner"));
+ d->updateWorkspace();
+ } else {
+ delete d->vbar;
+ delete d->hbar;
+ delete d->corner;
+ d->vbar = d->hbar = 0;
+ d->corner = 0;
+ }
+
+ QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
+ while (it != d->windows.end()) {
+ QWorkspaceChild *child = *it;
+ ++it;
+ child->widgetResizeHandler->setSizeProtection(!enable);
+ }
+}
+
+QRect QWorkspacePrivate::updateWorkspace()
+{
+ Q_Q(QWorkspace);
+ QRect cr(q->rect());
+
+ if (q->scrollBarsEnabled() && !maxWindow) {
+ corner->raise();
+ vbar->raise();
+ hbar->raise();
+ if (maxWindow)
+ maxWindow->internalRaise();
+
+ QRect r(0, 0, 0, 0);
+ QList<QWorkspaceChild *>::Iterator it(windows.begin());
+ while (it != windows.end()) {
+ QWorkspaceChild *child = *it;
+ ++it;
+ if (!child->isHidden())
+ r = r.unite(child->geometry());
+ }
+ vbar->blockSignals(true);
+ hbar->blockSignals(true);
+
+ int hsbExt = hbar->sizeHint().height();
+ int vsbExt = vbar->sizeHint().width();
+
+
+ bool showv = yoffset || yoffset + r.bottom() - q->height() + 1 > 0 || yoffset + r.top() < 0;
+ bool showh = xoffset || xoffset + r.right() - q->width() + 1 > 0 || xoffset + r.left() < 0;
+
+ if (showh && !showv)
+ showv = yoffset + r.bottom() - q->height() + hsbExt + 1 > 0;
+ if (showv && !showh)
+ showh = xoffset + r.right() - q->width() + vsbExt + 1 > 0;
+
+ if (!showh)
+ hsbExt = 0;
+ if (!showv)
+ vsbExt = 0;
+
+ if (showv) {
+ vbar->setSingleStep(qMax(q->height() / 12, 30));
+ vbar->setPageStep(q->height() - hsbExt);
+ vbar->setMinimum(qMin(0, yoffset + qMin(0, r.top())));
+ vbar->setMaximum(qMax(0, yoffset + qMax(0, r.bottom() - q->height() + hsbExt + 1)));
+ vbar->setGeometry(q->width() - vsbExt, 0, vsbExt, q->height() - hsbExt);
+ vbar->setValue(yoffset);
+ vbar->show();
+ } else {
+ vbar->hide();
+ }
+
+ if (showh) {
+ hbar->setSingleStep(qMax(q->width() / 12, 30));
+ hbar->setPageStep(q->width() - vsbExt);
+ hbar->setMinimum(qMin(0, xoffset + qMin(0, r.left())));
+ hbar->setMaximum(qMax(0, xoffset + qMax(0, r.right() - q->width() + vsbExt + 1)));
+ hbar->setGeometry(0, q->height() - hsbExt, q->width() - vsbExt, hsbExt);
+ hbar->setValue(xoffset);
+ hbar->show();
+ } else {
+ hbar->hide();
+ }
+
+ if (showh && showv) {
+ corner->setGeometry(q->width() - vsbExt, q->height() - hsbExt, vsbExt, hsbExt);
+ corner->show();
+ } else {
+ corner->hide();
+ }
+
+ vbar->blockSignals(false);
+ hbar->blockSignals(false);
+
+ cr.setRect(0, 0, q->width() - vsbExt, q->height() - hsbExt);
+ }
+
+ QList<QWidget *>::Iterator ii(icons.begin());
+ while (ii != icons.end()) {
+ QWidget* w = *ii;
+ ++ii;
+ int x = w->x();
+ int y = w->y();
+ bool m = false;
+ if (x+w->width() > cr.width()) {
+ m = true;
+ x = cr.width() - w->width();
+ }
+ if (y+w->height() > cr.height()) {
+ y = cr.height() - w->height();
+ m = true;
+ }
+ if (m) {
+ if (QWorkspaceChild *child = qobject_cast<QWorkspaceChild*>(w))
+ child->move(x, y);
+ else
+ w->move(x, y);
+ }
+ }
+
+ return cr;
+
+}
+
+void QWorkspacePrivate::_q_scrollBarChanged()
+{
+ int ver = yoffset - vbar->value();
+ int hor = xoffset - hbar->value();
+ yoffset = vbar->value();
+ xoffset = hbar->value();
+
+ QList<QWorkspaceChild *>::Iterator it(windows.begin());
+ while (it != windows.end()) {
+ QWorkspaceChild *child = *it;
+ ++it;
+ // we do not use move() due to the reimplementation in QWorkspaceChild
+ child->setGeometry(child->x() + hor, child->y() + ver, child->width(), child->height());
+ }
+ updateWorkspace();
+}
+
+/*!
+ \enum QWorkspace::WindowOrder
+
+ Specifies the order in which child windows are returned from windowList().
+
+ \value CreationOrder The windows are returned in the order of their creation
+ \value StackingOrder The windows are returned in the order of their stacking
+*/
+
+/*!\reimp */
+void QWorkspace::changeEvent(QEvent *ev)
+{
+ Q_D(QWorkspace);
+ if(ev->type() == QEvent::StyleChange) {
+ if (isVisible() && d->maxWindow && d->maxmenubar) {
+ if(style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
+ d->hideMaximizeControls(); //hide any visible maximized controls
+ d->showMaximizeControls(); //updates the modification state as well
+ }
+ }
+ }
+ QWidget::changeEvent(ev);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qworkspace.cpp"
+
+#include "qworkspace.moc"
+
+#endif // QT_NO_WORKSPACE
diff --git a/src/widgets/widgets/qworkspace.h b/src/widgets/widgets/qworkspace.h
new file mode 100644
index 0000000000..a251242542
--- /dev/null
+++ b/src/widgets/widgets/qworkspace.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWORKSPACE_H
+#define QWORKSPACE_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_WORKSPACE
+
+class QAction;
+class QWorkspaceChild;
+class QShowEvent;
+class QWorkspacePrivate;
+
+class Q_WIDGETS_EXPORT QWorkspace : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(bool scrollBarsEnabled READ scrollBarsEnabled WRITE setScrollBarsEnabled)
+ Q_PROPERTY(QBrush background READ background WRITE setBackground)
+
+public:
+ explicit QWorkspace(QWidget* parent=0);
+ ~QWorkspace();
+
+ enum WindowOrder { CreationOrder, StackingOrder };
+
+ QWidget* activeWindow() const;
+ QWidgetList windowList(WindowOrder order = CreationOrder) const;
+
+ QWidget * addWindow(QWidget *w, Qt::WindowFlags flags = 0);
+
+ QSize sizeHint() const;
+
+ bool scrollBarsEnabled() const;
+ void setScrollBarsEnabled(bool enable);
+
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QWorkspace(QWidget* parent, const char* name);
+ QT3_SUPPORT void setPaletteBackgroundColor(const QColor &);
+ QT3_SUPPORT void setPaletteBackgroundPixmap(const QPixmap &);
+#endif
+
+ void setBackground(const QBrush &background);
+ QBrush background() const;
+
+Q_SIGNALS:
+ void windowActivated(QWidget* w);
+
+public Q_SLOTS:
+ void setActiveWindow(QWidget *w);
+ void cascade();
+ void tile();
+ void arrangeIcons();
+ void closeActiveWindow();
+ void closeAllWindows();
+ void activateNextWindow();
+ void activatePreviousWindow();
+
+protected:
+ bool event(QEvent *e);
+ void paintEvent(QPaintEvent *e);
+ void changeEvent(QEvent *);
+ void childEvent(QChildEvent *);
+ void resizeEvent(QResizeEvent *);
+ bool eventFilter(QObject *, QEvent *);
+ void showEvent(QShowEvent *e);
+ void hideEvent(QHideEvent *e);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *e);
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QWorkspace)
+ Q_DISABLE_COPY(QWorkspace)
+ Q_PRIVATE_SLOT(d_func(), void _q_normalizeActiveWindow())
+ Q_PRIVATE_SLOT(d_func(), void _q_minimizeActiveWindow())
+ Q_PRIVATE_SLOT(d_func(), void _q_showOperationMenu())
+ Q_PRIVATE_SLOT(d_func(), void _q_popupOperationMenu(const QPoint&))
+ Q_PRIVATE_SLOT(d_func(), void _q_operationMenuActivated(QAction *))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateActions())
+ Q_PRIVATE_SLOT(d_func(), void _q_scrollBarChanged())
+
+ friend class QWorkspaceChild;
+};
+
+#endif // QT_NO_WORKSPACE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QWORKSPACE_H
diff --git a/src/widgets/widgets/widgets.pri b/src/widgets/widgets/widgets.pri
new file mode 100644
index 0000000000..986e5e79a0
--- /dev/null
+++ b/src/widgets/widgets/widgets.pri
@@ -0,0 +1,165 @@
+# Qt widgets module
+
+HEADERS += \
+ widgets/qbuttongroup.h \
+ widgets/qabstractbutton.h \
+ widgets/qabstractbutton_p.h \
+ widgets/qabstractslider.h \
+ widgets/qabstractslider_p.h \
+ widgets/qabstractspinbox.h \
+ widgets/qabstractspinbox_p.h \
+ widgets/qcalendartextnavigator_p.h \
+ widgets/qcalendarwidget.h \
+ widgets/qcheckbox.h \
+ widgets/qcombobox.h \
+ widgets/qcombobox_p.h \
+ widgets/qcommandlinkbutton.h \
+ widgets/qdatetimeedit.h \
+ widgets/qdatetimeedit_p.h \
+ widgets/qdial.h \
+ widgets/qdialogbuttonbox.h \
+ widgets/qdockwidget.h \
+ widgets/qdockwidget_p.h \
+ widgets/qdockarealayout_p.h \
+ widgets/qfontcombobox.h \
+ widgets/qframe.h \
+ widgets/qframe_p.h \
+ widgets/qgroupbox.h \
+ widgets/qlabel.h \
+ widgets/qlabel_p.h \
+ widgets/qlcdnumber.h \
+ widgets/qlineedit.h \
+ widgets/qlineedit_p.h \
+ widgets/qmainwindow.h \
+ widgets/qmainwindowlayout_p.h \
+ widgets/qmdiarea.h \
+ widgets/qmdiarea_p.h \
+ widgets/qmdisubwindow.h \
+ widgets/qmdisubwindow_p.h \
+ widgets/qmenu.h \
+ widgets/qmenu_p.h \
+ widgets/qmenubar.h \
+ widgets/qmenubar_p.h \
+ widgets/qprogressbar.h \
+ widgets/qpushbutton.h \
+ widgets/qpushbutton_p.h \
+ widgets/qradiobutton.h \
+ widgets/qrubberband.h \
+ widgets/qscrollbar.h \
+ widgets/qscrollarea_p.h \
+ widgets/qsizegrip.h \
+ widgets/qslider.h \
+ widgets/qspinbox.h \
+ widgets/qsplashscreen.h \
+ widgets/qsplitter.h \
+ widgets/qsplitter_p.h \
+ widgets/qstackedwidget.h \
+ widgets/qstatusbar.h \
+ widgets/qtabbar.h \
+ widgets/qtabbar_p.h \
+ widgets/qtabwidget.h \
+ widgets/qtextedit.h \
+ widgets/qtextedit_p.h \
+ widgets/qtextbrowser.h \
+ widgets/qtoolbar.h \
+ widgets/qtoolbar_p.h \
+ widgets/qtoolbarlayout_p.h \
+ widgets/qtoolbarextension_p.h \
+ widgets/qtoolbarseparator_p.h \
+ widgets/qtoolbox.h \
+ widgets/qtoolbutton.h \
+ widgets/qabstractscrollarea.h \
+ widgets/qabstractscrollarea_p.h \
+ widgets/qwidgetresizehandler_p.h \
+ widgets/qfocusframe.h \
+ widgets/qscrollarea.h \
+ widgets/qworkspace.h \
+ widgets/qwidgetanimator_p.h \
+ widgets/qwidgettextcontrol_p.h \
+ widgets/qwidgettextcontrol_p_p.h \
+ widgets/qwidgetlinecontrol_p.h \
+ widgets/qtoolbararealayout_p.h \
+ widgets/qplaintextedit.h \
+ widgets/qplaintextedit_p.h
+
+SOURCES += \
+ widgets/qabstractbutton.cpp \
+ widgets/qabstractslider.cpp \
+ widgets/qabstractspinbox.cpp \
+ widgets/qcalendarwidget.cpp \
+ widgets/qcheckbox.cpp \
+ widgets/qcombobox.cpp \
+ widgets/qcommandlinkbutton.cpp \
+ widgets/qdatetimeedit.cpp \
+ widgets/qdial.cpp \
+ widgets/qdialogbuttonbox.cpp \
+ widgets/qdockwidget.cpp \
+ widgets/qdockarealayout.cpp \
+ widgets/qeffects.cpp \
+ widgets/qfontcombobox.cpp \
+ widgets/qframe.cpp \
+ widgets/qgroupbox.cpp \
+ widgets/qlabel.cpp \
+ widgets/qlcdnumber.cpp \
+ widgets/qlineedit_p.cpp \
+ widgets/qlineedit.cpp \
+ widgets/qmainwindow.cpp \
+ widgets/qmainwindowlayout.cpp \
+ widgets/qmdiarea.cpp \
+ widgets/qmdisubwindow.cpp \
+ widgets/qmenu.cpp \
+ widgets/qmenubar.cpp \
+ widgets/qprogressbar.cpp \
+ widgets/qpushbutton.cpp \
+ widgets/qradiobutton.cpp \
+ widgets/qrubberband.cpp \
+ widgets/qscrollbar.cpp \
+ widgets/qsizegrip.cpp \
+ widgets/qslider.cpp \
+ widgets/qspinbox.cpp \
+ widgets/qsplashscreen.cpp \
+ widgets/qsplitter.cpp \
+ widgets/qstackedwidget.cpp \
+ widgets/qstatusbar.cpp \
+ widgets/qtabbar.cpp \
+ widgets/qtabwidget.cpp \
+ widgets/qtextedit.cpp \
+ widgets/qtextbrowser.cpp \
+ widgets/qtoolbar.cpp \
+ widgets/qtoolbarlayout.cpp \
+ widgets/qtoolbarextension.cpp \
+ widgets/qtoolbarseparator.cpp \
+ widgets/qtoolbox.cpp \
+ widgets/qtoolbutton.cpp \
+ widgets/qabstractscrollarea.cpp \
+ widgets/qwidgetresizehandler.cpp \
+ widgets/qfocusframe.cpp \
+ widgets/qscrollarea.cpp \
+ widgets/qworkspace.cpp \
+ widgets/qwidgetanimator.cpp \
+ widgets/qwidgettextcontrol.cpp \
+ widgets/qwidgetlinecontrol.cpp \
+ widgets/qtoolbararealayout.cpp \
+ widgets/qplaintextedit.cpp
+
+!qpa:mac {
+ HEADERS += widgets/qmacnativewidget_mac.h \
+ widgets/qmaccocoaviewcontainer_mac.h
+ OBJECTIVE_HEADERS += widgets/qcocoatoolbardelegate_mac_p.h \
+ widgets/qcocoamenu_mac_p.h
+ OBJECTIVE_SOURCES += widgets/qmaccocoaviewcontainer_mac.mm \
+ widgets/qcocoatoolbardelegate_mac.mm \
+ widgets/qmainwindowlayout_mac.mm \
+ widgets/qmacnativewidget_mac.mm \
+}
+
+wince*: {
+ SOURCES += widgets/qmenu_wince.cpp
+ HEADERS += widgets/qmenu_wince_resource_p.h
+ RC_FILE = widgets/qmenu_wince.rc
+ !static: QMAKE_WRITE_DEFAULT_RC = 1
+}
+
+symbian: {
+ SOURCES += widgets/qmenu_symbian.cpp
+}